codegen_test.cc revision b138dfbd76f9d8b64fb9dbaf1a7c25e2549b2a8c
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <functional>
18
19#include "arch/instruction_set.h"
20#include "arch/arm/instruction_set_features_arm.h"
21#include "arch/arm/registers_arm.h"
22#include "arch/arm64/instruction_set_features_arm64.h"
23#include "arch/mips/instruction_set_features_mips.h"
24#include "arch/mips/registers_mips.h"
25#include "arch/mips64/instruction_set_features_mips64.h"
26#include "arch/mips64/registers_mips64.h"
27#include "arch/x86/instruction_set_features_x86.h"
28#include "arch/x86/registers_x86.h"
29#include "arch/x86_64/instruction_set_features_x86_64.h"
30#include "base/macros.h"
31#include "builder.h"
32#include "code_simulator_container.h"
33#include "common_compiler_test.h"
34#include "dex_file.h"
35#include "dex_instruction.h"
36#include "driver/compiler_options.h"
37#include "graph_checker.h"
38#include "nodes.h"
39#include "optimizing_unit_test.h"
40#include "prepare_for_register_allocation.h"
41#include "register_allocator_linear_scan.h"
42#include "ssa_liveness_analysis.h"
43#include "utils.h"
44#include "utils/arm/assembler_arm_vixl.h"
45#include "utils/arm/managed_register_arm.h"
46#include "utils/mips/managed_register_mips.h"
47#include "utils/mips64/managed_register_mips64.h"
48#include "utils/x86/managed_register_x86.h"
49
50#ifdef ART_ENABLE_CODEGEN_arm
51#include "code_generator_arm.h"
52#include "code_generator_arm_vixl.h"
53#endif
54
55#ifdef ART_ENABLE_CODEGEN_arm64
56#include "code_generator_arm64.h"
57#endif
58
59#ifdef ART_ENABLE_CODEGEN_x86
60#include "code_generator_x86.h"
61#endif
62
63#ifdef ART_ENABLE_CODEGEN_x86_64
64#include "code_generator_x86_64.h"
65#endif
66
67#ifdef ART_ENABLE_CODEGEN_mips
68#include "code_generator_mips.h"
69#endif
70
71#ifdef ART_ENABLE_CODEGEN_mips64
72#include "code_generator_mips64.h"
73#endif
74
75#include "gtest/gtest.h"
76
77namespace art {
78
79typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
80
81class CodegenTargetConfig {
82 public:
83  CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
84      : isa_(isa), create_codegen_(create_codegen) {
85  }
86  InstructionSet GetInstructionSet() const { return isa_; }
87  CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
88    return create_codegen_(graph, compiler_options);
89  }
90
91 private:
92  CodegenTargetConfig() {}
93  InstructionSet isa_;
94  CreateCodegenFn create_codegen_;
95};
96
97#ifdef ART_ENABLE_CODEGEN_arm
98// Provide our own codegen, that ensures the C calling conventions
99// are preserved. Currently, ART and C do not match as R4 is caller-save
100// in ART, and callee-save in C. Alternatively, we could use or write
101// the stub that saves and restores all registers, but it is easier
102// to just overwrite the code generator.
103class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
104 public:
105  TestCodeGeneratorARM(HGraph* graph,
106                       const ArmInstructionSetFeatures& isa_features,
107                       const CompilerOptions& compiler_options)
108      : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
109    AddAllocatedRegister(Location::RegisterLocation(arm::R6));
110    AddAllocatedRegister(Location::RegisterLocation(arm::R7));
111  }
112
113  void SetupBlockedRegisters() const OVERRIDE {
114    arm::CodeGeneratorARM::SetupBlockedRegisters();
115    blocked_core_registers_[arm::R4] = true;
116    blocked_core_registers_[arm::R6] = false;
117    blocked_core_registers_[arm::R7] = false;
118    // Makes pair R6-R7 available.
119    blocked_register_pairs_[arm::R6_R7] = false;
120  }
121};
122
123// A way to test the VIXL32-based code generator on ARM. This will replace
124// TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one.
125class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
126 public:
127  TestCodeGeneratorARMVIXL(HGraph* graph,
128                           const ArmInstructionSetFeatures& isa_features,
129                           const CompilerOptions& compiler_options)
130      : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
131    AddAllocatedRegister(Location::RegisterLocation(arm::R6));
132    AddAllocatedRegister(Location::RegisterLocation(arm::R7));
133  }
134
135  void SetupBlockedRegisters() const OVERRIDE {
136    arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
137    blocked_core_registers_[arm::R4] = true;
138    blocked_core_registers_[arm::R6] = false;
139    blocked_core_registers_[arm::R7] = false;
140    // Makes pair R6-R7 available.
141    blocked_register_pairs_[arm::R6_R7] = false;
142  }
143};
144#endif
145
146#ifdef ART_ENABLE_CODEGEN_x86
147class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
148 public:
149  TestCodeGeneratorX86(HGraph* graph,
150                       const X86InstructionSetFeatures& isa_features,
151                       const CompilerOptions& compiler_options)
152      : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
153    // Save edi, we need it for getting enough registers for long multiplication.
154    AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
155  }
156
157  void SetupBlockedRegisters() const OVERRIDE {
158    x86::CodeGeneratorX86::SetupBlockedRegisters();
159    // ebx is a callee-save register in C, but caller-save for ART.
160    blocked_core_registers_[x86::EBX] = true;
161    blocked_register_pairs_[x86::EAX_EBX] = true;
162    blocked_register_pairs_[x86::EDX_EBX] = true;
163    blocked_register_pairs_[x86::ECX_EBX] = true;
164    blocked_register_pairs_[x86::EBX_EDI] = true;
165
166    // Make edi available.
167    blocked_core_registers_[x86::EDI] = false;
168    blocked_register_pairs_[x86::ECX_EDI] = false;
169  }
170};
171#endif
172
173class InternalCodeAllocator : public CodeAllocator {
174 public:
175  InternalCodeAllocator() : size_(0) { }
176
177  virtual uint8_t* Allocate(size_t size) {
178    size_ = size;
179    memory_.reset(new uint8_t[size]);
180    return memory_.get();
181  }
182
183  size_t GetSize() const { return size_; }
184  uint8_t* GetMemory() const { return memory_.get(); }
185
186 private:
187  size_t size_;
188  std::unique_ptr<uint8_t[]> memory_;
189
190  DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
191};
192
193static bool CanExecuteOnHardware(InstructionSet target_isa) {
194  return (target_isa == kRuntimeISA)
195      // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
196      || (kRuntimeISA == kArm && target_isa == kThumb2);
197}
198
199static bool CanExecute(InstructionSet target_isa) {
200  CodeSimulatorContainer simulator(target_isa);
201  return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
202}
203
204template <typename Expected>
205static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
206
207template <>
208bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
209  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
210  return simulator->GetCReturnBool();
211}
212
213template <>
214int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
215  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
216  return simulator->GetCReturnInt32();
217}
218
219template <>
220int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
221  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
222  return simulator->GetCReturnInt64();
223}
224
225template <typename Expected>
226static void VerifyGeneratedCode(InstructionSet target_isa,
227                                Expected (*f)(),
228                                bool has_result,
229                                Expected expected) {
230  ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
231
232  // Verify on simulator.
233  CodeSimulatorContainer simulator(target_isa);
234  if (simulator.CanSimulate()) {
235    Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
236    if (has_result) {
237      ASSERT_EQ(expected, result);
238    }
239  }
240
241  // Verify on hardware.
242  if (CanExecuteOnHardware(target_isa)) {
243    Expected result = f();
244    if (has_result) {
245      ASSERT_EQ(expected, result);
246    }
247  }
248}
249
250template <typename Expected>
251static void Run(const InternalCodeAllocator& allocator,
252                const CodeGenerator& codegen,
253                bool has_result,
254                Expected expected) {
255  InstructionSet target_isa = codegen.GetInstructionSet();
256
257  typedef Expected (*fptr)();
258  CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
259  fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
260  if (target_isa == kThumb2) {
261    // For thumb we need the bottom bit set.
262    f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
263  }
264  VerifyGeneratedCode(target_isa, f, has_result, expected);
265}
266
267static void ValidateGraph(HGraph* graph) {
268  GraphChecker graph_checker(graph);
269  graph_checker.Run();
270  if (!graph_checker.IsValid()) {
271    for (auto error : graph_checker.GetErrors()) {
272      std::cout << error << std::endl;
273    }
274  }
275  ASSERT_TRUE(graph_checker.IsValid());
276}
277
278template <typename Expected>
279static void RunCodeNoCheck(CodeGenerator* codegen,
280                           HGraph* graph,
281                           std::function<void(HGraph*)> hook_before_codegen,
282                           bool has_result,
283                           Expected expected) {
284  SsaLivenessAnalysis liveness(graph, codegen);
285  PrepareForRegisterAllocation(graph).Run();
286  liveness.Analyze();
287  RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
288  hook_before_codegen(graph);
289  InternalCodeAllocator allocator;
290  codegen->Compile(&allocator);
291  Run(allocator, *codegen, has_result, expected);
292}
293
294template <typename Expected>
295static void RunCode(CodeGenerator* codegen,
296                    HGraph* graph,
297                    std::function<void(HGraph*)> hook_before_codegen,
298                    bool has_result,
299                    Expected expected) {
300  ValidateGraph(graph);
301  RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
302}
303
304template <typename Expected>
305static void RunCode(CodegenTargetConfig target_config,
306                    HGraph* graph,
307                    std::function<void(HGraph*)> hook_before_codegen,
308                    bool has_result,
309                    Expected expected) {
310  CompilerOptions compiler_options;
311  CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options);
312  RunCode(codegen, graph, hook_before_codegen, has_result, expected);
313}
314
315#ifdef ART_ENABLE_CODEGEN_arm
316CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
317  std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
318      ArmInstructionSetFeatures::FromCppDefines());
319  return new (graph->GetArena()) TestCodeGeneratorARM(graph,
320                                                      *features_arm.get(),
321                                                      compiler_options);
322}
323
324CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
325  std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
326      ArmInstructionSetFeatures::FromCppDefines());
327  return new (graph->GetArena())
328      TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
329}
330#endif
331
332#ifdef ART_ENABLE_CODEGEN_arm64
333CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
334  std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
335      Arm64InstructionSetFeatures::FromCppDefines());
336  return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
337                                                           *features_arm64.get(),
338                                                           compiler_options);
339}
340#endif
341
342#ifdef ART_ENABLE_CODEGEN_x86
343CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
344  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
345      X86InstructionSetFeatures::FromCppDefines());
346  return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
347}
348#endif
349
350#ifdef ART_ENABLE_CODEGEN_x86_64
351CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
352  std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
353     X86_64InstructionSetFeatures::FromCppDefines());
354  return new (graph->GetArena())
355      x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
356}
357#endif
358
359#ifdef ART_ENABLE_CODEGEN_mips
360CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
361  std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
362      MipsInstructionSetFeatures::FromCppDefines());
363  return new (graph->GetArena())
364      mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
365}
366#endif
367
368#ifdef ART_ENABLE_CODEGEN_mips64
369CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
370  std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
371      Mips64InstructionSetFeatures::FromCppDefines());
372  return new (graph->GetArena())
373      mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
374}
375#endif
376
377// Return all combinations of ISA and code generator that are executable on
378// hardware, or on simulator, and that we'd like to test.
379static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
380  ::std::vector<CodegenTargetConfig> v;
381  ::std::vector<CodegenTargetConfig> test_config_candidates = {
382#ifdef ART_ENABLE_CODEGEN_arm
383    CodegenTargetConfig(kArm, create_codegen_arm),
384    CodegenTargetConfig(kThumb2, create_codegen_arm),
385    CodegenTargetConfig(kArm, create_codegen_arm_vixl32),
386#endif
387#ifdef ART_ENABLE_CODEGEN_arm64
388    CodegenTargetConfig(kArm64, create_codegen_arm64),
389#endif
390#ifdef ART_ENABLE_CODEGEN_x86
391    CodegenTargetConfig(kX86, create_codegen_x86),
392#endif
393#ifdef ART_ENABLE_CODEGEN_x86_64
394    CodegenTargetConfig(kX86_64, create_codegen_x86_64),
395#endif
396#ifdef ART_ENABLE_CODEGEN_mips
397    CodegenTargetConfig(kMips, create_codegen_mips),
398#endif
399#ifdef ART_ENABLE_CODEGEN_mips64
400    CodegenTargetConfig(kMips64, create_codegen_mips64)
401#endif
402  };
403
404  for (auto test_config : test_config_candidates) {
405    if (CanExecute(test_config.GetInstructionSet())) {
406      v.push_back(test_config);
407    }
408  }
409
410  return v;
411}
412
413static void TestCode(const uint16_t* data,
414                     bool has_result = false,
415                     int32_t expected = 0) {
416  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
417    ArenaPool pool;
418    ArenaAllocator arena(&pool);
419    HGraph* graph = CreateCFG(&arena, data);
420    // Remove suspend checks, they cannot be executed in this context.
421    RemoveSuspendChecks(graph);
422    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
423  }
424}
425
426static void TestCodeLong(const uint16_t* data,
427                         bool has_result,
428                         int64_t expected) {
429  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
430    ArenaPool pool;
431    ArenaAllocator arena(&pool);
432    HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
433    // Remove suspend checks, they cannot be executed in this context.
434    RemoveSuspendChecks(graph);
435    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
436  }
437}
438
439class CodegenTest : public CommonCompilerTest {};
440
441TEST_F(CodegenTest, ReturnVoid) {
442  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
443  TestCode(data);
444}
445
446TEST_F(CodegenTest, CFG1) {
447  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
448    Instruction::GOTO | 0x100,
449    Instruction::RETURN_VOID);
450
451  TestCode(data);
452}
453
454TEST_F(CodegenTest, CFG2) {
455  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
456    Instruction::GOTO | 0x100,
457    Instruction::GOTO | 0x100,
458    Instruction::RETURN_VOID);
459
460  TestCode(data);
461}
462
463TEST_F(CodegenTest, CFG3) {
464  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
465    Instruction::GOTO | 0x200,
466    Instruction::RETURN_VOID,
467    Instruction::GOTO | 0xFF00);
468
469  TestCode(data1);
470
471  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
472    Instruction::GOTO_16, 3,
473    Instruction::RETURN_VOID,
474    Instruction::GOTO_16, 0xFFFF);
475
476  TestCode(data2);
477
478  const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
479    Instruction::GOTO_32, 4, 0,
480    Instruction::RETURN_VOID,
481    Instruction::GOTO_32, 0xFFFF, 0xFFFF);
482
483  TestCode(data3);
484}
485
486TEST_F(CodegenTest, CFG4) {
487  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
488    Instruction::RETURN_VOID,
489    Instruction::GOTO | 0x100,
490    Instruction::GOTO | 0xFE00);
491
492  TestCode(data);
493}
494
495TEST_F(CodegenTest, CFG5) {
496  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
497    Instruction::CONST_4 | 0 | 0,
498    Instruction::IF_EQ, 3,
499    Instruction::GOTO | 0x100,
500    Instruction::RETURN_VOID);
501
502  TestCode(data);
503}
504
505TEST_F(CodegenTest, IntConstant) {
506  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
507    Instruction::CONST_4 | 0 | 0,
508    Instruction::RETURN_VOID);
509
510  TestCode(data);
511}
512
513TEST_F(CodegenTest, Return1) {
514  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
515    Instruction::CONST_4 | 0 | 0,
516    Instruction::RETURN | 0);
517
518  TestCode(data, true, 0);
519}
520
521TEST_F(CodegenTest, Return2) {
522  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
523    Instruction::CONST_4 | 0 | 0,
524    Instruction::CONST_4 | 0 | 1 << 8,
525    Instruction::RETURN | 1 << 8);
526
527  TestCode(data, true, 0);
528}
529
530TEST_F(CodegenTest, Return3) {
531  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
532    Instruction::CONST_4 | 0 | 0,
533    Instruction::CONST_4 | 1 << 8 | 1 << 12,
534    Instruction::RETURN | 1 << 8);
535
536  TestCode(data, true, 1);
537}
538
539TEST_F(CodegenTest, ReturnIf1) {
540  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
541    Instruction::CONST_4 | 0 | 0,
542    Instruction::CONST_4 | 1 << 8 | 1 << 12,
543    Instruction::IF_EQ, 3,
544    Instruction::RETURN | 0 << 8,
545    Instruction::RETURN | 1 << 8);
546
547  TestCode(data, true, 1);
548}
549
550TEST_F(CodegenTest, ReturnIf2) {
551  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
552    Instruction::CONST_4 | 0 | 0,
553    Instruction::CONST_4 | 1 << 8 | 1 << 12,
554    Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
555    Instruction::RETURN | 0 << 8,
556    Instruction::RETURN | 1 << 8);
557
558  TestCode(data, true, 0);
559}
560
561// Exercise bit-wise (one's complement) not-int instruction.
562#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
563TEST_F(CodegenTest, TEST_NAME) {                        \
564  const int32_t input = INPUT;                          \
565  const uint16_t input_lo = Low16Bits(input);           \
566  const uint16_t input_hi = High16Bits(input);          \
567  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(      \
568      Instruction::CONST | 0 << 8, input_lo, input_hi,  \
569      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,         \
570      Instruction::RETURN | 1 << 8);                    \
571                                                        \
572  TestCode(data, true, EXPECTED_OUTPUT);                \
573}
574
575NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
576NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
577NOT_INT_TEST(ReturnNotInt0, 0, -1)
578NOT_INT_TEST(ReturnNotInt1, 1, -2)
579NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647)  // (2^31) - 1
580NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
581NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
582NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648)  // -(2^31)
583
584#undef NOT_INT_TEST
585
586// Exercise bit-wise (one's complement) not-long instruction.
587#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)                 \
588TEST_F(CodegenTest, TEST_NAME) {                                         \
589  const int64_t input = INPUT;                                           \
590  const uint16_t word0 = Low16Bits(Low32Bits(input));   /* LSW. */       \
591  const uint16_t word1 = High16Bits(Low32Bits(input));                   \
592  const uint16_t word2 = Low16Bits(High32Bits(input));                   \
593  const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */       \
594  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(                      \
595      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,      \
596      Instruction::NOT_LONG | 2 << 8 | 0 << 12,                          \
597      Instruction::RETURN_WIDE | 2 << 8);                                \
598                                                                         \
599  TestCodeLong(data, true, EXPECTED_OUTPUT);                             \
600}
601
602NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
603NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
604NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
605NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
606
607NOT_LONG_TEST(ReturnNotLongINT32_MIN,
608              INT64_C(-2147483648),
609              INT64_C(2147483647))  // (2^31) - 1
610NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
611              INT64_C(-2147483647),
612              INT64_C(2147483646))  // (2^31) - 2
613NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
614              INT64_C(2147483646),
615              INT64_C(-2147483647))  // -(2^31) - 1
616NOT_LONG_TEST(ReturnNotLongINT32_MAX,
617              INT64_C(2147483647),
618              INT64_C(-2147483648))  // -(2^31)
619
620// Note that the C++ compiler won't accept
621// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
622// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
623NOT_LONG_TEST(ReturnNotINT64_MIN,
624              INT64_C(-9223372036854775807)-1,
625              INT64_C(9223372036854775807));  // (2^63) - 1
626NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
627              INT64_C(-9223372036854775807),
628              INT64_C(9223372036854775806));  // (2^63) - 2
629NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
630              INT64_C(9223372036854775806),
631              INT64_C(-9223372036854775807));  // -(2^63) - 1
632NOT_LONG_TEST(ReturnNotLongINT64_MAX,
633              INT64_C(9223372036854775807),
634              INT64_C(-9223372036854775807)-1);  // -(2^63)
635
636#undef NOT_LONG_TEST
637
638TEST_F(CodegenTest, IntToLongOfLongToInt) {
639  const int64_t input = INT64_C(4294967296);             // 2^32
640  const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
641  const uint16_t word1 = High16Bits(Low32Bits(input));
642  const uint16_t word2 = Low16Bits(High32Bits(input));
643  const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
644  const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
645      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
646      Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
647      Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
648      Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
649      Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
650      Instruction::RETURN_WIDE | 2 << 8);
651
652  TestCodeLong(data, true, 1);
653}
654
655TEST_F(CodegenTest, ReturnAdd1) {
656  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
657    Instruction::CONST_4 | 3 << 12 | 0,
658    Instruction::CONST_4 | 4 << 12 | 1 << 8,
659    Instruction::ADD_INT, 1 << 8 | 0,
660    Instruction::RETURN);
661
662  TestCode(data, true, 7);
663}
664
665TEST_F(CodegenTest, ReturnAdd2) {
666  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
667    Instruction::CONST_4 | 3 << 12 | 0,
668    Instruction::CONST_4 | 4 << 12 | 1 << 8,
669    Instruction::ADD_INT_2ADDR | 1 << 12,
670    Instruction::RETURN);
671
672  TestCode(data, true, 7);
673}
674
675TEST_F(CodegenTest, ReturnAdd3) {
676  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
677    Instruction::CONST_4 | 4 << 12 | 0 << 8,
678    Instruction::ADD_INT_LIT8, 3 << 8 | 0,
679    Instruction::RETURN);
680
681  TestCode(data, true, 7);
682}
683
684TEST_F(CodegenTest, ReturnAdd4) {
685  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
686    Instruction::CONST_4 | 4 << 12 | 0 << 8,
687    Instruction::ADD_INT_LIT16, 3,
688    Instruction::RETURN);
689
690  TestCode(data, true, 7);
691}
692
693TEST_F(CodegenTest, ReturnMulInt) {
694  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
695    Instruction::CONST_4 | 3 << 12 | 0,
696    Instruction::CONST_4 | 4 << 12 | 1 << 8,
697    Instruction::MUL_INT, 1 << 8 | 0,
698    Instruction::RETURN);
699
700  TestCode(data, true, 12);
701}
702
703TEST_F(CodegenTest, ReturnMulInt2addr) {
704  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
705    Instruction::CONST_4 | 3 << 12 | 0,
706    Instruction::CONST_4 | 4 << 12 | 1 << 8,
707    Instruction::MUL_INT_2ADDR | 1 << 12,
708    Instruction::RETURN);
709
710  TestCode(data, true, 12);
711}
712
713TEST_F(CodegenTest, ReturnMulLong) {
714  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
715    Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
716    Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
717    Instruction::MUL_LONG, 2 << 8 | 0,
718    Instruction::RETURN_WIDE);
719
720  TestCodeLong(data, true, 12);
721}
722
723TEST_F(CodegenTest, ReturnMulLong2addr) {
724  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
725    Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
726    Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
727    Instruction::MUL_LONG_2ADDR | 2 << 12,
728    Instruction::RETURN_WIDE);
729
730  TestCodeLong(data, true, 12);
731}
732
733TEST_F(CodegenTest, ReturnMulIntLit8) {
734  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
735    Instruction::CONST_4 | 4 << 12 | 0 << 8,
736    Instruction::MUL_INT_LIT8, 3 << 8 | 0,
737    Instruction::RETURN);
738
739  TestCode(data, true, 12);
740}
741
742TEST_F(CodegenTest, ReturnMulIntLit16) {
743  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
744    Instruction::CONST_4 | 4 << 12 | 0 << 8,
745    Instruction::MUL_INT_LIT16, 3,
746    Instruction::RETURN);
747
748  TestCode(data, true, 12);
749}
750
751TEST_F(CodegenTest, NonMaterializedCondition) {
752  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
753    ArenaPool pool;
754    ArenaAllocator allocator(&pool);
755
756    HGraph* graph = CreateGraph(&allocator);
757
758    HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
759    graph->AddBlock(entry);
760    graph->SetEntryBlock(entry);
761    entry->AddInstruction(new (&allocator) HGoto());
762
763    HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
764    graph->AddBlock(first_block);
765    entry->AddSuccessor(first_block);
766    HIntConstant* constant0 = graph->GetIntConstant(0);
767    HIntConstant* constant1 = graph->GetIntConstant(1);
768    HEqual* equal = new (&allocator) HEqual(constant0, constant0);
769    first_block->AddInstruction(equal);
770    first_block->AddInstruction(new (&allocator) HIf(equal));
771
772    HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
773    HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
774    HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
775    graph->SetExitBlock(exit_block);
776
777    graph->AddBlock(then_block);
778    graph->AddBlock(else_block);
779    graph->AddBlock(exit_block);
780    first_block->AddSuccessor(then_block);
781    first_block->AddSuccessor(else_block);
782    then_block->AddSuccessor(exit_block);
783    else_block->AddSuccessor(exit_block);
784
785    exit_block->AddInstruction(new (&allocator) HExit());
786    then_block->AddInstruction(new (&allocator) HReturn(constant0));
787    else_block->AddInstruction(new (&allocator) HReturn(constant1));
788
789    ASSERT_FALSE(equal->IsEmittedAtUseSite());
790    graph->BuildDominatorTree();
791    PrepareForRegisterAllocation(graph).Run();
792    ASSERT_TRUE(equal->IsEmittedAtUseSite());
793
794    auto hook_before_codegen = [](HGraph* graph_in) {
795      HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
796      HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
797      block->InsertInstructionBefore(move, block->GetLastInstruction());
798    };
799
800    RunCode(target_config, graph, hook_before_codegen, true, 0);
801  }
802}
803
804TEST_F(CodegenTest, MaterializedCondition1) {
805  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
806    // Check that condition are materialized correctly. A materialized condition
807    // should yield `1` if it evaluated to true, and `0` otherwise.
808    // We force the materialization of comparisons for different combinations of
809
810    // inputs and check the results.
811
812    int lhs[] = {1, 2, -1, 2, 0xabc};
813    int rhs[] = {2, 1, 2, -1, 0xabc};
814
815    for (size_t i = 0; i < arraysize(lhs); i++) {
816      ArenaPool pool;
817      ArenaAllocator allocator(&pool);
818      HGraph* graph = CreateGraph(&allocator);
819
820      HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
821      graph->AddBlock(entry_block);
822      graph->SetEntryBlock(entry_block);
823      entry_block->AddInstruction(new (&allocator) HGoto());
824      HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
825      graph->AddBlock(code_block);
826      HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
827      graph->AddBlock(exit_block);
828      exit_block->AddInstruction(new (&allocator) HExit());
829
830      entry_block->AddSuccessor(code_block);
831      code_block->AddSuccessor(exit_block);
832      graph->SetExitBlock(exit_block);
833
834      HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
835      HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
836      HLessThan cmp_lt(cst_lhs, cst_rhs);
837      code_block->AddInstruction(&cmp_lt);
838      HReturn ret(&cmp_lt);
839      code_block->AddInstruction(&ret);
840
841      graph->BuildDominatorTree();
842      auto hook_before_codegen = [](HGraph* graph_in) {
843        HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
844        HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
845        block->InsertInstructionBefore(move, block->GetLastInstruction());
846      };
847      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
848    }
849  }
850}
851
852TEST_F(CodegenTest, MaterializedCondition2) {
853  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
854    // Check that HIf correctly interprets a materialized condition.
855    // We force the materialization of comparisons for different combinations of
856    // inputs. An HIf takes the materialized combination as input and returns a
857    // value that we verify.
858
859    int lhs[] = {1, 2, -1, 2, 0xabc};
860    int rhs[] = {2, 1, 2, -1, 0xabc};
861
862
863    for (size_t i = 0; i < arraysize(lhs); i++) {
864      ArenaPool pool;
865      ArenaAllocator allocator(&pool);
866      HGraph* graph = CreateGraph(&allocator);
867
868      HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
869      graph->AddBlock(entry_block);
870      graph->SetEntryBlock(entry_block);
871      entry_block->AddInstruction(new (&allocator) HGoto());
872
873      HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
874      graph->AddBlock(if_block);
875      HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
876      graph->AddBlock(if_true_block);
877      HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
878      graph->AddBlock(if_false_block);
879      HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
880      graph->AddBlock(exit_block);
881      exit_block->AddInstruction(new (&allocator) HExit());
882
883      graph->SetEntryBlock(entry_block);
884      entry_block->AddSuccessor(if_block);
885      if_block->AddSuccessor(if_true_block);
886      if_block->AddSuccessor(if_false_block);
887      if_true_block->AddSuccessor(exit_block);
888      if_false_block->AddSuccessor(exit_block);
889      graph->SetExitBlock(exit_block);
890
891      HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
892      HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
893      HLessThan cmp_lt(cst_lhs, cst_rhs);
894      if_block->AddInstruction(&cmp_lt);
895      // We insert a dummy instruction to separate the HIf from the HLessThan
896      // and force the materialization of the condition.
897      HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
898      if_block->AddInstruction(&force_materialization);
899      HIf if_lt(&cmp_lt);
900      if_block->AddInstruction(&if_lt);
901
902      HIntConstant* cst_lt = graph->GetIntConstant(1);
903      HReturn ret_lt(cst_lt);
904      if_true_block->AddInstruction(&ret_lt);
905      HIntConstant* cst_ge = graph->GetIntConstant(0);
906      HReturn ret_ge(cst_ge);
907      if_false_block->AddInstruction(&ret_ge);
908
909      graph->BuildDominatorTree();
910      auto hook_before_codegen = [](HGraph* graph_in) {
911        HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
912        HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
913        block->InsertInstructionBefore(move, block->GetLastInstruction());
914      };
915      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
916    }
917  }
918}
919
920TEST_F(CodegenTest, ReturnDivIntLit8) {
921  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
922    Instruction::CONST_4 | 4 << 12 | 0 << 8,
923    Instruction::DIV_INT_LIT8, 3 << 8 | 0,
924    Instruction::RETURN);
925
926  TestCode(data, true, 1);
927}
928
929TEST_F(CodegenTest, ReturnDivInt2Addr) {
930  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
931    Instruction::CONST_4 | 4 << 12 | 0,
932    Instruction::CONST_4 | 2 << 12 | 1 << 8,
933    Instruction::DIV_INT_2ADDR | 1 << 12,
934    Instruction::RETURN);
935
936  TestCode(data, true, 2);
937}
938
939// Helper method.
940static void TestComparison(IfCondition condition,
941                           int64_t i,
942                           int64_t j,
943                           Primitive::Type type,
944                           const CodegenTargetConfig target_config) {
945  ArenaPool pool;
946  ArenaAllocator allocator(&pool);
947  HGraph* graph = CreateGraph(&allocator);
948
949  HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
950  graph->AddBlock(entry_block);
951  graph->SetEntryBlock(entry_block);
952  entry_block->AddInstruction(new (&allocator) HGoto());
953
954  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
955  graph->AddBlock(block);
956
957  HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
958  graph->AddBlock(exit_block);
959  graph->SetExitBlock(exit_block);
960  exit_block->AddInstruction(new (&allocator) HExit());
961
962  entry_block->AddSuccessor(block);
963  block->AddSuccessor(exit_block);
964
965  HInstruction* op1;
966  HInstruction* op2;
967  if (type == Primitive::kPrimInt) {
968    op1 = graph->GetIntConstant(i);
969    op2 = graph->GetIntConstant(j);
970  } else {
971    DCHECK_EQ(type, Primitive::kPrimLong);
972    op1 = graph->GetLongConstant(i);
973    op2 = graph->GetLongConstant(j);
974  }
975
976  HInstruction* comparison = nullptr;
977  bool expected_result = false;
978  const uint64_t x = i;
979  const uint64_t y = j;
980  switch (condition) {
981    case kCondEQ:
982      comparison = new (&allocator) HEqual(op1, op2);
983      expected_result = (i == j);
984      break;
985    case kCondNE:
986      comparison = new (&allocator) HNotEqual(op1, op2);
987      expected_result = (i != j);
988      break;
989    case kCondLT:
990      comparison = new (&allocator) HLessThan(op1, op2);
991      expected_result = (i < j);
992      break;
993    case kCondLE:
994      comparison = new (&allocator) HLessThanOrEqual(op1, op2);
995      expected_result = (i <= j);
996      break;
997    case kCondGT:
998      comparison = new (&allocator) HGreaterThan(op1, op2);
999      expected_result = (i > j);
1000      break;
1001    case kCondGE:
1002      comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
1003      expected_result = (i >= j);
1004      break;
1005    case kCondB:
1006      comparison = new (&allocator) HBelow(op1, op2);
1007      expected_result = (x < y);
1008      break;
1009    case kCondBE:
1010      comparison = new (&allocator) HBelowOrEqual(op1, op2);
1011      expected_result = (x <= y);
1012      break;
1013    case kCondA:
1014      comparison = new (&allocator) HAbove(op1, op2);
1015      expected_result = (x > y);
1016      break;
1017    case kCondAE:
1018      comparison = new (&allocator) HAboveOrEqual(op1, op2);
1019      expected_result = (x >= y);
1020      break;
1021  }
1022  block->AddInstruction(comparison);
1023  block->AddInstruction(new (&allocator) HReturn(comparison));
1024
1025  graph->BuildDominatorTree();
1026  RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
1027}
1028
1029TEST_F(CodegenTest, ComparisonsInt) {
1030  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
1031    for (int64_t i = -1; i <= 1; i++) {
1032      for (int64_t j = -1; j <= 1; j++) {
1033        for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1034          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
1035        }
1036      }
1037    }
1038  }
1039}
1040
1041TEST_F(CodegenTest, ComparisonsLong) {
1042  // TODO: make MIPS work for long
1043  if (kRuntimeISA == kMips || kRuntimeISA == kMips64) {
1044    return;
1045  }
1046
1047  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
1048    if ((target_config.GetInstructionSet() == kMips) ||
1049        (target_config.GetInstructionSet() == kMips64)) {
1050      continue;
1051    }
1052
1053    for (int64_t i = -1; i <= 1; i++) {
1054      for (int64_t j = -1; j <= 1; j++) {
1055        for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1056          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
1057        }
1058      }
1059    }
1060  }
1061}
1062
1063#ifdef ART_ENABLE_CODEGEN_mips
1064TEST_F(CodegenTest, MipsClobberRA) {
1065  std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
1066      MipsInstructionSetFeatures::FromCppDefines());
1067  if (!CanExecute(kMips) || features_mips->IsR6()) {
1068    // HMipsComputeBaseMethodAddress and the NAL instruction behind it
1069    // should only be generated on non-R6.
1070    return;
1071  }
1072
1073  ArenaPool pool;
1074  ArenaAllocator allocator(&pool);
1075  HGraph* graph = CreateGraph(&allocator);
1076
1077  HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
1078  graph->AddBlock(entry_block);
1079  graph->SetEntryBlock(entry_block);
1080  entry_block->AddInstruction(new (&allocator) HGoto());
1081
1082  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
1083  graph->AddBlock(block);
1084
1085  HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
1086  graph->AddBlock(exit_block);
1087  graph->SetExitBlock(exit_block);
1088  exit_block->AddInstruction(new (&allocator) HExit());
1089
1090  entry_block->AddSuccessor(block);
1091  block->AddSuccessor(exit_block);
1092
1093  // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
1094  // Instead, generate HMipsComputeBaseMethodAddress directly.
1095  HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
1096  block->AddInstruction(base);
1097  // HMipsComputeBaseMethodAddress is defined as int, so just make the
1098  // compiled method return it.
1099  block->AddInstruction(new (&allocator) HReturn(base));
1100
1101  graph->BuildDominatorTree();
1102
1103  mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
1104  // Since there isn't HLoadClass or HLoadString, we need to manually indicate
1105  // that RA is clobbered and the method entry code should generate a stack frame
1106  // and preserve RA in it. And this is what we're testing here.
1107  codegenMIPS.ClobberRA();
1108  // Without ClobberRA() the code would be:
1109  //   nal              # Sets RA to point to the jr instruction below
1110  //   move  v0, ra     # and the CPU falls into an infinite loop.
1111  //   jr    ra
1112  //   nop
1113  // The expected code is:
1114  //   addiu sp, sp, -16
1115  //   sw    ra, 12(sp)
1116  //   sw    a0, 0(sp)
1117  //   nal              # Sets RA to point to the lw instruction below.
1118  //   move  v0, ra
1119  //   lw    ra, 12(sp)
1120  //   jr    ra
1121  //   addiu sp, sp, 16
1122  RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
1123}
1124#endif
1125
1126}  // namespace art
1127