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