blob: 070cbb3894c047a047e5ae7e47ad5a884547ea62 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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
Nicolas Geoffray360231a2014-10-08 21:07:48 +010017#include <functional>
18
Ian Rogersd582fa42014-11-05 23:46:43 -080019#include "arch/instruction_set.h"
Calin Juravle34166012014-12-19 17:22:29 +000020#include "arch/arm/instruction_set_features_arm.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010021#include "arch/arm/registers_arm.h"
Serban Constantinescu579885a2015-02-22 20:51:33 +000022#include "arch/arm64/instruction_set_features_arm64.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020023#include "arch/mips/instruction_set_features_mips.h"
24#include "arch/mips/registers_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070025#include "arch/mips64/instruction_set_features_mips64.h"
26#include "arch/mips64/registers_mips64.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040027#include "arch/x86/instruction_set_features_x86.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010028#include "arch/x86/registers_x86.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040029#include "arch/x86_64/instruction_set_features_x86_64.h"
Alexandre Rames92730742014-10-01 12:55:56 +010030#include "base/macros.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031#include "builder.h"
Phil Wang751beff2015-08-28 15:17:15 +080032#include "code_simulator_container.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033#include "common_compiler_test.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000034#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000036#include "driver/compiler_options.h"
David Brazdil58282f42016-01-14 12:45:10 +000037#include "graph_checker.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000038#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000039#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010040#include "prepare_for_register_allocation.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070041#include "register_allocator_linear_scan.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010042#include "ssa_liveness_analysis.h"
Roland Levillain55dcfb52014-10-24 18:09:09 +010043#include "utils.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010044#include "utils/arm/managed_register_arm.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020045#include "utils/mips/managed_register_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070046#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010047#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000048
Colin Crossa75b01a2016-08-18 13:45:24 -070049#ifdef ART_ENABLE_CODEGEN_arm
50#include "code_generator_arm.h"
51#endif
52
53#ifdef ART_ENABLE_CODEGEN_arm64
54#include "code_generator_arm64.h"
55#endif
56
57#ifdef ART_ENABLE_CODEGEN_x86
58#include "code_generator_x86.h"
59#endif
60
61#ifdef ART_ENABLE_CODEGEN_x86_64
62#include "code_generator_x86_64.h"
63#endif
64
65#ifdef ART_ENABLE_CODEGEN_mips
66#include "code_generator_mips.h"
67#endif
68
69#ifdef ART_ENABLE_CODEGEN_mips64
70#include "code_generator_mips64.h"
71#endif
72
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000073#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000074
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000075namespace art {
76
Scott Wakeling2c76e062016-08-31 09:48:54 +010077typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
78
79class CodegenTargetConfig {
80 public:
81 CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
82 : isa_(isa), create_codegen_(create_codegen) {
83 }
84 InstructionSet GetInstructionSet() const { return isa_; }
85 CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
86 return create_codegen_(graph, compiler_options);
87 }
88
89 private:
90 CodegenTargetConfig() {}
91 InstructionSet isa_;
92 CreateCodegenFn create_codegen_;
93};
94
Colin Crossa75b01a2016-08-18 13:45:24 -070095#ifdef ART_ENABLE_CODEGEN_arm
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000096// Provide our own codegen, that ensures the C calling conventions
97// are preserved. Currently, ART and C do not match as R4 is caller-save
98// in ART, and callee-save in C. Alternatively, we could use or write
99// the stub that saves and restores all registers, but it is easier
100// to just overwrite the code generator.
101class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
102 public:
103 TestCodeGeneratorARM(HGraph* graph,
104 const ArmInstructionSetFeatures& isa_features,
105 const CompilerOptions& compiler_options)
106 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100107 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
108 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000109 }
110
David Brazdil58282f42016-01-14 12:45:10 +0000111 void SetupBlockedRegisters() const OVERRIDE {
112 arm::CodeGeneratorARM::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100113 blocked_core_registers_[arm::R4] = true;
114 blocked_core_registers_[arm::R6] = false;
115 blocked_core_registers_[arm::R7] = false;
Nicolas Geoffraye6362282015-01-26 13:57:30 +0000116 // Makes pair R6-R7 available.
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100117 blocked_register_pairs_[arm::R6_R7] = false;
118 }
119};
Colin Crossa75b01a2016-08-18 13:45:24 -0700120#endif
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100121
Colin Crossa75b01a2016-08-18 13:45:24 -0700122#ifdef ART_ENABLE_CODEGEN_x86
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100123class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
124 public:
125 TestCodeGeneratorX86(HGraph* graph,
126 const X86InstructionSetFeatures& isa_features,
127 const CompilerOptions& compiler_options)
128 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
129 // Save edi, we need it for getting enough registers for long multiplication.
130 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
131 }
132
David Brazdil58282f42016-01-14 12:45:10 +0000133 void SetupBlockedRegisters() const OVERRIDE {
134 x86::CodeGeneratorX86::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100135 // ebx is a callee-save register in C, but caller-save for ART.
136 blocked_core_registers_[x86::EBX] = true;
137 blocked_register_pairs_[x86::EAX_EBX] = true;
138 blocked_register_pairs_[x86::EDX_EBX] = true;
139 blocked_register_pairs_[x86::ECX_EBX] = true;
140 blocked_register_pairs_[x86::EBX_EDI] = true;
141
142 // Make edi available.
143 blocked_core_registers_[x86::EDI] = false;
144 blocked_register_pairs_[x86::ECX_EDI] = false;
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000145 }
146};
Colin Crossa75b01a2016-08-18 13:45:24 -0700147#endif
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000148
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000149class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150 public:
Ian Rogersd582fa42014-11-05 23:46:43 -0800151 InternalCodeAllocator() : size_(0) { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000152
153 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000154 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000155 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000156 return memory_.get();
157 }
158
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000159 size_t GetSize() const { return size_; }
160 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000161
162 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000163 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -0700164 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000165
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000166 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000167};
168
Phil Wang751beff2015-08-28 15:17:15 +0800169static bool CanExecuteOnHardware(InstructionSet target_isa) {
170 return (target_isa == kRuntimeISA)
171 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
172 || (kRuntimeISA == kArm && target_isa == kThumb2);
173}
174
175static bool CanExecute(InstructionSet target_isa) {
176 CodeSimulatorContainer simulator(target_isa);
177 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
178}
179
180template <typename Expected>
181static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
182
183template <>
184bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
185 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
186 return simulator->GetCReturnBool();
187}
188
189template <>
190int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
191 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
192 return simulator->GetCReturnInt32();
193}
194
195template <>
196int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
197 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
198 return simulator->GetCReturnInt64();
199}
200
201template <typename Expected>
202static void VerifyGeneratedCode(InstructionSet target_isa,
203 Expected (*f)(),
204 bool has_result,
205 Expected expected) {
206 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
207
208 // Verify on simulator.
209 CodeSimulatorContainer simulator(target_isa);
210 if (simulator.CanSimulate()) {
211 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
212 if (has_result) {
213 ASSERT_EQ(expected, result);
214 }
215 }
216
217 // Verify on hardware.
218 if (CanExecuteOnHardware(target_isa)) {
219 Expected result = f();
220 if (has_result) {
221 ASSERT_EQ(expected, result);
222 }
223 }
224}
225
Roland Levillain55dcfb52014-10-24 18:09:09 +0100226template <typename Expected>
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100227static void Run(const InternalCodeAllocator& allocator,
228 const CodeGenerator& codegen,
229 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100230 Expected expected) {
Phil Wang751beff2015-08-28 15:17:15 +0800231 InstructionSet target_isa = codegen.GetInstructionSet();
232
Roland Levillain55dcfb52014-10-24 18:09:09 +0100233 typedef Expected (*fptr)();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100234 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -0700235 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Phil Wang751beff2015-08-28 15:17:15 +0800236 if (target_isa == kThumb2) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100237 // For thumb we need the bottom bit set.
238 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
239 }
Phil Wang751beff2015-08-28 15:17:15 +0800240 VerifyGeneratedCode(target_isa, f, has_result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100241}
242
Scott Wakeling2c76e062016-08-31 09:48:54 +0100243static void ValidateGraph(HGraph* graph) {
David Brazdilbadd8262016-02-02 16:28:56 +0000244 GraphChecker graph_checker(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000245 graph_checker.Run();
David Brazdilbadd8262016-02-02 16:28:56 +0000246 if (!graph_checker.IsValid()) {
247 for (auto error : graph_checker.GetErrors()) {
248 std::cout << error << std::endl;
249 }
250 }
David Brazdil58282f42016-01-14 12:45:10 +0000251 ASSERT_TRUE(graph_checker.IsValid());
Scott Wakeling2c76e062016-08-31 09:48:54 +0100252}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100253
Scott Wakeling2c76e062016-08-31 09:48:54 +0100254template <typename Expected>
255static void RunCodeNoCheck(CodeGenerator* codegen,
256 HGraph* graph,
257 std::function<void(HGraph*)> hook_before_codegen,
258 bool has_result,
259 Expected expected) {
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100260 SsaLivenessAnalysis liveness(graph, codegen);
David Brazdil58282f42016-01-14 12:45:10 +0000261 PrepareForRegisterAllocation(graph).Run();
262 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700263 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100264 hook_before_codegen(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100265 InternalCodeAllocator allocator;
David Brazdil58282f42016-01-14 12:45:10 +0000266 codegen->Compile(&allocator);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100267 Run(allocator, *codegen, has_result, expected);
268}
269
Roland Levillain55dcfb52014-10-24 18:09:09 +0100270template <typename Expected>
Scott Wakeling2c76e062016-08-31 09:48:54 +0100271static void RunCode(CodeGenerator* codegen,
272 HGraph* graph,
273 std::function<void(HGraph*)> hook_before_codegen,
274 bool has_result,
275 Expected expected) {
276 ValidateGraph(graph);
277 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
278}
279
280template <typename Expected>
281static void RunCode(CodegenTargetConfig target_config,
David Brazdil58282f42016-01-14 12:45:10 +0000282 HGraph* graph,
283 std::function<void(HGraph*)> hook_before_codegen,
284 bool has_result,
285 Expected expected) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000286 CompilerOptions compiler_options;
Scott Wakeling2c76e062016-08-31 09:48:54 +0100287 CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options);
288 RunCode(codegen, graph, hook_before_codegen, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100289}
290
Scott Wakeling2c76e062016-08-31 09:48:54 +0100291#ifdef ART_ENABLE_CODEGEN_arm
292CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
293 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
294 ArmInstructionSetFeatures::FromCppDefines());
295 return new (graph->GetArena()) TestCodeGeneratorARM(graph,
296 *features_arm.get(),
297 compiler_options);
298}
299#endif
300
301#ifdef ART_ENABLE_CODEGEN_arm64
302CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
303 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
304 Arm64InstructionSetFeatures::FromCppDefines());
305 return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
306 *features_arm64.get(),
307 compiler_options);
308}
309#endif
310
311#ifdef ART_ENABLE_CODEGEN_x86
312CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
313 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
314 X86InstructionSetFeatures::FromCppDefines());
315 return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
316}
317#endif
318
319#ifdef ART_ENABLE_CODEGEN_x86_64
320CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
321 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
322 X86_64InstructionSetFeatures::FromCppDefines());
323 return new (graph->GetArena())
324 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
325}
326#endif
327
328#ifdef ART_ENABLE_CODEGEN_mips
329CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
330 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
331 MipsInstructionSetFeatures::FromCppDefines());
332 return new (graph->GetArena())
333 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
334}
335#endif
336
337#ifdef ART_ENABLE_CODEGEN_mips64
338CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
339 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
340 Mips64InstructionSetFeatures::FromCppDefines());
341 return new (graph->GetArena())
342 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
343}
344#endif
345
346// Return all combinations of ISA and code generator that are executable on
347// hardware, or on simulator, and that we'd like to test.
348static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
349 ::std::vector<CodegenTargetConfig> v;
350 ::std::vector<CodegenTargetConfig> test_config_candidates = {
351#ifdef ART_ENABLE_CODEGEN_arm
352 CodegenTargetConfig(kArm, create_codegen_arm),
353 CodegenTargetConfig(kThumb2, create_codegen_arm),
354#endif
355#ifdef ART_ENABLE_CODEGEN_arm64
356 CodegenTargetConfig(kArm64, create_codegen_arm64),
357#endif
358#ifdef ART_ENABLE_CODEGEN_x86
359 CodegenTargetConfig(kX86, create_codegen_x86),
360#endif
361#ifdef ART_ENABLE_CODEGEN_x86_64
362 CodegenTargetConfig(kX86_64, create_codegen_x86_64),
363#endif
364#ifdef ART_ENABLE_CODEGEN_mips
365 CodegenTargetConfig(kMips, create_codegen_mips),
366#endif
367#ifdef ART_ENABLE_CODEGEN_mips64
368 CodegenTargetConfig(kMips64, create_codegen_mips64)
369#endif
David Brazdil58282f42016-01-14 12:45:10 +0000370 };
371
Scott Wakeling2c76e062016-08-31 09:48:54 +0100372 for (auto test_config : test_config_candidates) {
373 if (CanExecute(test_config.GetInstructionSet())) {
374 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +0000375 }
376 }
377
378 return v;
379}
380
381static void TestCode(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800382 bool has_result = false,
383 int32_t expected = 0) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100384 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000385 ArenaPool pool;
386 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000387 HGraph* graph = CreateCFG(&arena, data);
David Brazdil58282f42016-01-14 12:45:10 +0000388 // Remove suspend checks, they cannot be executed in this context.
389 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100390 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000391 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100392}
393
David Brazdil58282f42016-01-14 12:45:10 +0000394static void TestCodeLong(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800395 bool has_result,
396 int64_t expected) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100397 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000398 ArenaPool pool;
399 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000400 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
David Brazdil58282f42016-01-14 12:45:10 +0000401 // Remove suspend checks, they cannot be executed in this context.
402 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100403 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000404 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100405}
406
David Brazdil58282f42016-01-14 12:45:10 +0000407class CodegenTest : public CommonCompilerTest {};
Phil Wang751beff2015-08-28 15:17:15 +0800408
David Brazdil58282f42016-01-14 12:45:10 +0000409TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000410 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000411 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000412}
413
David Brazdil58282f42016-01-14 12:45:10 +0000414TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000415 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000416 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000417 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000418
David Brazdil58282f42016-01-14 12:45:10 +0000419 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000420}
421
David Brazdil58282f42016-01-14 12:45:10 +0000422TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000423 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000424 Instruction::GOTO | 0x100,
425 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000426 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000427
David Brazdil58282f42016-01-14 12:45:10 +0000428 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000429}
430
David Brazdil58282f42016-01-14 12:45:10 +0000431TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000432 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000433 Instruction::GOTO | 0x200,
434 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000435 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000436
David Brazdil58282f42016-01-14 12:45:10 +0000437 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000438
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000439 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000440 Instruction::GOTO_16, 3,
441 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000442 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000443
David Brazdil58282f42016-01-14 12:45:10 +0000444 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000445
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000446 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000447 Instruction::GOTO_32, 4, 0,
448 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000449 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000450
David Brazdil58282f42016-01-14 12:45:10 +0000451 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000452}
453
David Brazdil58282f42016-01-14 12:45:10 +0000454TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000455 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000456 Instruction::RETURN_VOID,
457 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000458 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000459
David Brazdil58282f42016-01-14 12:45:10 +0000460 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000461}
462
David Brazdil58282f42016-01-14 12:45:10 +0000463TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000464 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
465 Instruction::CONST_4 | 0 | 0,
466 Instruction::IF_EQ, 3,
467 Instruction::GOTO | 0x100,
468 Instruction::RETURN_VOID);
469
David Brazdil58282f42016-01-14 12:45:10 +0000470 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000471}
472
David Brazdil58282f42016-01-14 12:45:10 +0000473TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000474 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
475 Instruction::CONST_4 | 0 | 0,
476 Instruction::RETURN_VOID);
477
David Brazdil58282f42016-01-14 12:45:10 +0000478 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000479}
480
David Brazdil58282f42016-01-14 12:45:10 +0000481TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000482 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
483 Instruction::CONST_4 | 0 | 0,
484 Instruction::RETURN | 0);
485
David Brazdil58282f42016-01-14 12:45:10 +0000486 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000487}
488
David Brazdil58282f42016-01-14 12:45:10 +0000489TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000490 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
491 Instruction::CONST_4 | 0 | 0,
492 Instruction::CONST_4 | 0 | 1 << 8,
493 Instruction::RETURN | 1 << 8);
494
David Brazdil58282f42016-01-14 12:45:10 +0000495 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000496}
497
David Brazdil58282f42016-01-14 12:45:10 +0000498TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000499 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
500 Instruction::CONST_4 | 0 | 0,
501 Instruction::CONST_4 | 1 << 8 | 1 << 12,
502 Instruction::RETURN | 1 << 8);
503
David Brazdil58282f42016-01-14 12:45:10 +0000504 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000505}
506
David Brazdil58282f42016-01-14 12:45:10 +0000507TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000508 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
509 Instruction::CONST_4 | 0 | 0,
510 Instruction::CONST_4 | 1 << 8 | 1 << 12,
511 Instruction::IF_EQ, 3,
512 Instruction::RETURN | 0 << 8,
513 Instruction::RETURN | 1 << 8);
514
David Brazdil58282f42016-01-14 12:45:10 +0000515 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000516}
517
David Brazdil58282f42016-01-14 12:45:10 +0000518TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000519 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
520 Instruction::CONST_4 | 0 | 0,
521 Instruction::CONST_4 | 1 << 8 | 1 << 12,
522 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
523 Instruction::RETURN | 0 << 8,
524 Instruction::RETURN | 1 << 8);
525
David Brazdil58282f42016-01-14 12:45:10 +0000526 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000527}
528
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100529// Exercise bit-wise (one's complement) not-int instruction.
530#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000531TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100532 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100533 const uint16_t input_lo = Low16Bits(input); \
534 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100535 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
536 Instruction::CONST | 0 << 8, input_lo, input_hi, \
537 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
538 Instruction::RETURN | 1 << 8); \
539 \
David Brazdil58282f42016-01-14 12:45:10 +0000540 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100541}
542
543NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
544NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
545NOT_INT_TEST(ReturnNotInt0, 0, -1)
546NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100547NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
548NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
549NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
550NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100551
552#undef NOT_INT_TEST
553
Roland Levillain55dcfb52014-10-24 18:09:09 +0100554// Exercise bit-wise (one's complement) not-long instruction.
555#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000556TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100557 const int64_t input = INPUT; \
558 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
559 const uint16_t word1 = High16Bits(Low32Bits(input)); \
560 const uint16_t word2 = Low16Bits(High32Bits(input)); \
561 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
562 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
563 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
564 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
565 Instruction::RETURN_WIDE | 2 << 8); \
566 \
David Brazdil58282f42016-01-14 12:45:10 +0000567 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100568}
569
570NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
571NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
572NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
573NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
574
575NOT_LONG_TEST(ReturnNotLongINT32_MIN,
576 INT64_C(-2147483648),
577 INT64_C(2147483647)) // (2^31) - 1
578NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
579 INT64_C(-2147483647),
580 INT64_C(2147483646)) // (2^31) - 2
581NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
582 INT64_C(2147483646),
583 INT64_C(-2147483647)) // -(2^31) - 1
584NOT_LONG_TEST(ReturnNotLongINT32_MAX,
585 INT64_C(2147483647),
586 INT64_C(-2147483648)) // -(2^31)
587
588// Note that the C++ compiler won't accept
589// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
590// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
591NOT_LONG_TEST(ReturnNotINT64_MIN,
592 INT64_C(-9223372036854775807)-1,
593 INT64_C(9223372036854775807)); // (2^63) - 1
594NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
595 INT64_C(-9223372036854775807),
596 INT64_C(9223372036854775806)); // (2^63) - 2
597NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
598 INT64_C(9223372036854775806),
599 INT64_C(-9223372036854775807)); // -(2^63) - 1
600NOT_LONG_TEST(ReturnNotLongINT64_MAX,
601 INT64_C(9223372036854775807),
602 INT64_C(-9223372036854775807)-1); // -(2^63)
603
604#undef NOT_LONG_TEST
605
David Brazdil58282f42016-01-14 12:45:10 +0000606TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000607 const int64_t input = INT64_C(4294967296); // 2^32
608 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
609 const uint16_t word1 = High16Bits(Low32Bits(input));
610 const uint16_t word2 = Low16Bits(High32Bits(input));
611 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
612 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
613 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
614 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
615 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
616 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
617 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
618 Instruction::RETURN_WIDE | 2 << 8);
619
David Brazdil58282f42016-01-14 12:45:10 +0000620 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000621}
622
David Brazdil58282f42016-01-14 12:45:10 +0000623TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000624 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
625 Instruction::CONST_4 | 3 << 12 | 0,
626 Instruction::CONST_4 | 4 << 12 | 1 << 8,
627 Instruction::ADD_INT, 1 << 8 | 0,
628 Instruction::RETURN);
629
David Brazdil58282f42016-01-14 12:45:10 +0000630 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000631}
632
David Brazdil58282f42016-01-14 12:45:10 +0000633TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000634 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
635 Instruction::CONST_4 | 3 << 12 | 0,
636 Instruction::CONST_4 | 4 << 12 | 1 << 8,
637 Instruction::ADD_INT_2ADDR | 1 << 12,
638 Instruction::RETURN);
639
David Brazdil58282f42016-01-14 12:45:10 +0000640 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000641}
642
David Brazdil58282f42016-01-14 12:45:10 +0000643TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000644 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
645 Instruction::CONST_4 | 4 << 12 | 0 << 8,
646 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
647 Instruction::RETURN);
648
David Brazdil58282f42016-01-14 12:45:10 +0000649 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000650}
651
David Brazdil58282f42016-01-14 12:45:10 +0000652TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000653 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
654 Instruction::CONST_4 | 4 << 12 | 0 << 8,
655 Instruction::ADD_INT_LIT16, 3,
656 Instruction::RETURN);
657
David Brazdil58282f42016-01-14 12:45:10 +0000658 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000659}
660
David Brazdil58282f42016-01-14 12:45:10 +0000661TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100662 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
663 Instruction::CONST_4 | 3 << 12 | 0,
664 Instruction::CONST_4 | 4 << 12 | 1 << 8,
665 Instruction::MUL_INT, 1 << 8 | 0,
666 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100667
David Brazdil58282f42016-01-14 12:45:10 +0000668 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100669}
670
David Brazdil58282f42016-01-14 12:45:10 +0000671TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100672 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
673 Instruction::CONST_4 | 3 << 12 | 0,
674 Instruction::CONST_4 | 4 << 12 | 1 << 8,
675 Instruction::MUL_INT_2ADDR | 1 << 12,
676 Instruction::RETURN);
677
David Brazdil58282f42016-01-14 12:45:10 +0000678 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100679}
680
David Brazdil58282f42016-01-14 12:45:10 +0000681TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100682 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000683 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
684 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100685 Instruction::MUL_LONG, 2 << 8 | 0,
686 Instruction::RETURN_WIDE);
687
David Brazdil58282f42016-01-14 12:45:10 +0000688 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100689}
690
David Brazdil58282f42016-01-14 12:45:10 +0000691TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100692 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000693 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
694 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100695 Instruction::MUL_LONG_2ADDR | 2 << 12,
696 Instruction::RETURN_WIDE);
697
David Brazdil58282f42016-01-14 12:45:10 +0000698 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100699}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100700
David Brazdil58282f42016-01-14 12:45:10 +0000701TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100702 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
703 Instruction::CONST_4 | 4 << 12 | 0 << 8,
704 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
705 Instruction::RETURN);
706
David Brazdil58282f42016-01-14 12:45:10 +0000707 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100708}
709
David Brazdil58282f42016-01-14 12:45:10 +0000710TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100711 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
712 Instruction::CONST_4 | 4 << 12 | 0 << 8,
713 Instruction::MUL_INT_LIT16, 3,
714 Instruction::RETURN);
715
David Brazdil58282f42016-01-14 12:45:10 +0000716 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100717}
718
David Brazdil58282f42016-01-14 12:45:10 +0000719TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100720 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Alexandre Rames92730742014-10-01 12:55:56 +0100721 ArenaPool pool;
722 ArenaAllocator allocator(&pool);
David Brazdil58282f42016-01-14 12:45:10 +0000723
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100724 HGraph* graph = CreateGraph(&allocator);
David Brazdilbadd8262016-02-02 16:28:56 +0000725
David Brazdil58282f42016-01-14 12:45:10 +0000726 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
727 graph->AddBlock(entry);
728 graph->SetEntryBlock(entry);
729 entry->AddInstruction(new (&allocator) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100730
David Brazdil58282f42016-01-14 12:45:10 +0000731 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
732 graph->AddBlock(first_block);
733 entry->AddSuccessor(first_block);
734 HIntConstant* constant0 = graph->GetIntConstant(0);
735 HIntConstant* constant1 = graph->GetIntConstant(1);
736 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
737 first_block->AddInstruction(equal);
738 first_block->AddInstruction(new (&allocator) HIf(equal));
739
740 HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
741 HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100742 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100743 graph->SetExitBlock(exit_block);
744
David Brazdil58282f42016-01-14 12:45:10 +0000745 graph->AddBlock(then_block);
746 graph->AddBlock(else_block);
747 graph->AddBlock(exit_block);
748 first_block->AddSuccessor(then_block);
749 first_block->AddSuccessor(else_block);
750 then_block->AddSuccessor(exit_block);
751 else_block->AddSuccessor(exit_block);
752
753 exit_block->AddInstruction(new (&allocator) HExit());
754 then_block->AddInstruction(new (&allocator) HReturn(constant0));
755 else_block->AddInstruction(new (&allocator) HReturn(constant1));
756
David Brazdilb11b0722016-01-28 16:22:40 +0000757 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000758 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000759 PrepareForRegisterAllocation(graph).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000760 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100761
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800762 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100763 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800764 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100765 block->InsertInstructionBefore(move, block->GetLastInstruction());
766 };
767
Scott Wakeling2c76e062016-08-31 09:48:54 +0100768 RunCode(target_config, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100769 }
770}
771
David Brazdil58282f42016-01-14 12:45:10 +0000772TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100773 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000774 // Check that condition are materialized correctly. A materialized condition
775 // should yield `1` if it evaluated to true, and `0` otherwise.
776 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100777
David Brazdil58282f42016-01-14 12:45:10 +0000778 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100779
David Brazdil58282f42016-01-14 12:45:10 +0000780 int lhs[] = {1, 2, -1, 2, 0xabc};
781 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100782
David Brazdil58282f42016-01-14 12:45:10 +0000783 for (size_t i = 0; i < arraysize(lhs); i++) {
784 ArenaPool pool;
785 ArenaAllocator allocator(&pool);
786 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100787
David Brazdil58282f42016-01-14 12:45:10 +0000788 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
789 graph->AddBlock(entry_block);
790 graph->SetEntryBlock(entry_block);
791 entry_block->AddInstruction(new (&allocator) HGoto());
792 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
793 graph->AddBlock(code_block);
794 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
795 graph->AddBlock(exit_block);
796 exit_block->AddInstruction(new (&allocator) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100797
David Brazdil58282f42016-01-14 12:45:10 +0000798 entry_block->AddSuccessor(code_block);
799 code_block->AddSuccessor(exit_block);
800 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100801
David Brazdil58282f42016-01-14 12:45:10 +0000802 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
803 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
804 HLessThan cmp_lt(cst_lhs, cst_rhs);
805 code_block->AddInstruction(&cmp_lt);
806 HReturn ret(&cmp_lt);
807 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100808
David Brazdilbadd8262016-02-02 16:28:56 +0000809 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000810 auto hook_before_codegen = [](HGraph* graph_in) {
811 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
812 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
813 block->InsertInstructionBefore(move, block->GetLastInstruction());
814 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100815 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000816 }
Alexandre Rames92730742014-10-01 12:55:56 +0100817 }
818}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100819
David Brazdil58282f42016-01-14 12:45:10 +0000820TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100821 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000822 // Check that HIf correctly interprets a materialized condition.
823 // We force the materialization of comparisons for different combinations of
824 // inputs. An HIf takes the materialized combination as input and returns a
825 // value that we verify.
826
827 int lhs[] = {1, 2, -1, 2, 0xabc};
828 int rhs[] = {2, 1, 2, -1, 0xabc};
829
830
831 for (size_t i = 0; i < arraysize(lhs); i++) {
832 ArenaPool pool;
833 ArenaAllocator allocator(&pool);
834 HGraph* graph = CreateGraph(&allocator);
835
836 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
837 graph->AddBlock(entry_block);
838 graph->SetEntryBlock(entry_block);
839 entry_block->AddInstruction(new (&allocator) HGoto());
840
841 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
842 graph->AddBlock(if_block);
843 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
844 graph->AddBlock(if_true_block);
845 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
846 graph->AddBlock(if_false_block);
847 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
848 graph->AddBlock(exit_block);
849 exit_block->AddInstruction(new (&allocator) HExit());
850
851 graph->SetEntryBlock(entry_block);
852 entry_block->AddSuccessor(if_block);
853 if_block->AddSuccessor(if_true_block);
854 if_block->AddSuccessor(if_false_block);
855 if_true_block->AddSuccessor(exit_block);
856 if_false_block->AddSuccessor(exit_block);
857 graph->SetExitBlock(exit_block);
858
859 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
860 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
861 HLessThan cmp_lt(cst_lhs, cst_rhs);
862 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000863 // We insert a dummy instruction to separate the HIf from the HLessThan
864 // and force the materialization of the condition.
865 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000866 if_block->AddInstruction(&force_materialization);
867 HIf if_lt(&cmp_lt);
868 if_block->AddInstruction(&if_lt);
869
870 HIntConstant* cst_lt = graph->GetIntConstant(1);
871 HReturn ret_lt(cst_lt);
872 if_true_block->AddInstruction(&ret_lt);
873 HIntConstant* cst_ge = graph->GetIntConstant(0);
874 HReturn ret_ge(cst_ge);
875 if_false_block->AddInstruction(&ret_ge);
876
David Brazdilbadd8262016-02-02 16:28:56 +0000877 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000878 auto hook_before_codegen = [](HGraph* graph_in) {
879 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
880 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
881 block->InsertInstructionBefore(move, block->GetLastInstruction());
882 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100883 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000884 }
885 }
886}
887
888TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000889 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
890 Instruction::CONST_4 | 4 << 12 | 0 << 8,
891 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
892 Instruction::RETURN);
893
David Brazdil58282f42016-01-14 12:45:10 +0000894 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000895}
896
David Brazdil58282f42016-01-14 12:45:10 +0000897TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000898 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
899 Instruction::CONST_4 | 4 << 12 | 0,
900 Instruction::CONST_4 | 2 << 12 | 1 << 8,
901 Instruction::DIV_INT_2ADDR | 1 << 12,
902 Instruction::RETURN);
903
David Brazdil58282f42016-01-14 12:45:10 +0000904 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000905}
906
Aart Bike9f37602015-10-09 11:15:55 -0700907// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800908static void TestComparison(IfCondition condition,
909 int64_t i,
910 int64_t j,
911 Primitive::Type type,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100912 const CodegenTargetConfig target_config) {
Aart Bike9f37602015-10-09 11:15:55 -0700913 ArenaPool pool;
914 ArenaAllocator allocator(&pool);
915 HGraph* graph = CreateGraph(&allocator);
916
917 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
918 graph->AddBlock(entry_block);
919 graph->SetEntryBlock(entry_block);
920 entry_block->AddInstruction(new (&allocator) HGoto());
921
922 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
923 graph->AddBlock(block);
924
925 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
926 graph->AddBlock(exit_block);
927 graph->SetExitBlock(exit_block);
928 exit_block->AddInstruction(new (&allocator) HExit());
929
930 entry_block->AddSuccessor(block);
931 block->AddSuccessor(exit_block);
932
933 HInstruction* op1;
934 HInstruction* op2;
935 if (type == Primitive::kPrimInt) {
936 op1 = graph->GetIntConstant(i);
937 op2 = graph->GetIntConstant(j);
938 } else {
939 DCHECK_EQ(type, Primitive::kPrimLong);
940 op1 = graph->GetLongConstant(i);
941 op2 = graph->GetLongConstant(j);
942 }
943
944 HInstruction* comparison = nullptr;
945 bool expected_result = false;
946 const uint64_t x = i;
947 const uint64_t y = j;
948 switch (condition) {
949 case kCondEQ:
950 comparison = new (&allocator) HEqual(op1, op2);
951 expected_result = (i == j);
952 break;
953 case kCondNE:
954 comparison = new (&allocator) HNotEqual(op1, op2);
955 expected_result = (i != j);
956 break;
957 case kCondLT:
958 comparison = new (&allocator) HLessThan(op1, op2);
959 expected_result = (i < j);
960 break;
961 case kCondLE:
962 comparison = new (&allocator) HLessThanOrEqual(op1, op2);
963 expected_result = (i <= j);
964 break;
965 case kCondGT:
966 comparison = new (&allocator) HGreaterThan(op1, op2);
967 expected_result = (i > j);
968 break;
969 case kCondGE:
970 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
971 expected_result = (i >= j);
972 break;
973 case kCondB:
974 comparison = new (&allocator) HBelow(op1, op2);
975 expected_result = (x < y);
976 break;
977 case kCondBE:
978 comparison = new (&allocator) HBelowOrEqual(op1, op2);
979 expected_result = (x <= y);
980 break;
981 case kCondA:
982 comparison = new (&allocator) HAbove(op1, op2);
983 expected_result = (x > y);
984 break;
985 case kCondAE:
986 comparison = new (&allocator) HAboveOrEqual(op1, op2);
987 expected_result = (x >= y);
988 break;
989 }
990 block->AddInstruction(comparison);
991 block->AddInstruction(new (&allocator) HReturn(comparison));
992
David Brazdilbadd8262016-02-02 16:28:56 +0000993 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +0100994 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700995}
996
David Brazdil58282f42016-01-14 12:45:10 +0000997TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100998 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000999 for (int64_t i = -1; i <= 1; i++) {
1000 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001001 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1002 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
1003 }
David Brazdil58282f42016-01-14 12:45:10 +00001004 }
Aart Bike9f37602015-10-09 11:15:55 -07001005 }
1006 }
1007}
1008
David Brazdil58282f42016-01-14 12:45:10 +00001009TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001010 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +00001011 for (int64_t i = -1; i <= 1; i++) {
1012 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001013 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1014 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
1015 }
David Brazdil58282f42016-01-14 12:45:10 +00001016 }
Aart Bike9f37602015-10-09 11:15:55 -07001017 }
1018 }
1019}
1020
Alexey Frunze58320ce2016-08-30 21:40:46 -07001021#ifdef ART_ENABLE_CODEGEN_mips
1022TEST_F(CodegenTest, MipsClobberRA) {
1023 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
1024 MipsInstructionSetFeatures::FromCppDefines());
1025 if (!CanExecute(kMips) || features_mips->IsR6()) {
1026 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
1027 // should only be generated on non-R6.
1028 return;
1029 }
1030
1031 ArenaPool pool;
1032 ArenaAllocator allocator(&pool);
1033 HGraph* graph = CreateGraph(&allocator);
1034
1035 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
1036 graph->AddBlock(entry_block);
1037 graph->SetEntryBlock(entry_block);
1038 entry_block->AddInstruction(new (&allocator) HGoto());
1039
1040 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
1041 graph->AddBlock(block);
1042
1043 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
1044 graph->AddBlock(exit_block);
1045 graph->SetExitBlock(exit_block);
1046 exit_block->AddInstruction(new (&allocator) HExit());
1047
1048 entry_block->AddSuccessor(block);
1049 block->AddSuccessor(exit_block);
1050
1051 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
1052 // Instead, generate HMipsComputeBaseMethodAddress directly.
1053 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
1054 block->AddInstruction(base);
1055 // HMipsComputeBaseMethodAddress is defined as int, so just make the
1056 // compiled method return it.
1057 block->AddInstruction(new (&allocator) HReturn(base));
1058
1059 graph->BuildDominatorTree();
1060
1061 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
1062 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
1063 // that RA is clobbered and the method entry code should generate a stack frame
1064 // and preserve RA in it. And this is what we're testing here.
1065 codegenMIPS.ClobberRA();
1066 // Without ClobberRA() the code would be:
1067 // nal # Sets RA to point to the jr instruction below
1068 // move v0, ra # and the CPU falls into an infinite loop.
1069 // jr ra
1070 // nop
1071 // The expected code is:
1072 // addiu sp, sp, -16
1073 // sw ra, 12(sp)
1074 // sw a0, 0(sp)
1075 // nal # Sets RA to point to the lw instruction below.
1076 // move v0, ra
1077 // lw ra, 12(sp)
1078 // jr ra
1079 // addiu sp, sp, 16
1080 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
1081}
1082#endif
1083
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001084} // namespace art