blob: ac83bd9b0c773dac54c48c918a94351451bf270e [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"
Scott Wakelingfe885462016-09-22 10:24:38 +010044#include "utils/arm/assembler_arm_vixl.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010045#include "utils/arm/managed_register_arm.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020046#include "utils/mips/managed_register_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070047#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010048#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000049
Colin Crossa75b01a2016-08-18 13:45:24 -070050#ifdef ART_ENABLE_CODEGEN_arm
51#include "code_generator_arm.h"
Scott Wakelingfe885462016-09-22 10:24:38 +010052#include "code_generator_arm_vixl.h"
Colin Crossa75b01a2016-08-18 13:45:24 -070053#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
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000075#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000076
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000077namespace art {
78
Scott Wakeling2c76e062016-08-31 09:48:54 +010079typedef 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
Colin Crossa75b01a2016-08-18 13:45:24 -070097#ifdef ART_ENABLE_CODEGEN_arm
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000098// 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) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100109 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
110 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000111 }
112
David Brazdil58282f42016-01-14 12:45:10 +0000113 void SetupBlockedRegisters() const OVERRIDE {
114 arm::CodeGeneratorARM::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100115 blocked_core_registers_[arm::R4] = true;
116 blocked_core_registers_[arm::R6] = false;
117 blocked_core_registers_[arm::R7] = false;
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100118 }
119};
Scott Wakelingfe885462016-09-22 10:24:38 +0100120
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;
Scott Wakelingfe885462016-09-22 10:24:38 +0100138 }
139};
Colin Crossa75b01a2016-08-18 13:45:24 -0700140#endif
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100141
Colin Crossa75b01a2016-08-18 13:45:24 -0700142#ifdef ART_ENABLE_CODEGEN_x86
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100143class 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
David Brazdil58282f42016-01-14 12:45:10 +0000153 void SetupBlockedRegisters() const OVERRIDE {
154 x86::CodeGeneratorX86::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100155 // ebx is a callee-save register in C, but caller-save for ART.
156 blocked_core_registers_[x86::EBX] = true;
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100157
158 // Make edi available.
159 blocked_core_registers_[x86::EDI] = false;
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000160 }
161};
Colin Crossa75b01a2016-08-18 13:45:24 -0700162#endif
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000163
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000164class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000165 public:
Ian Rogersd582fa42014-11-05 23:46:43 -0800166 InternalCodeAllocator() : size_(0) { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000167
168 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000169 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000170 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000171 return memory_.get();
172 }
173
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000174 size_t GetSize() const { return size_; }
175 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000176
177 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000178 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -0700179 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000180
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000181 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000182};
183
Phil Wang751beff2015-08-28 15:17:15 +0800184static 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
Roland Levillain55dcfb52014-10-24 18:09:09 +0100241template <typename Expected>
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100242static void Run(const InternalCodeAllocator& allocator,
243 const CodeGenerator& codegen,
244 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100245 Expected expected) {
Phil Wang751beff2015-08-28 15:17:15 +0800246 InstructionSet target_isa = codegen.GetInstructionSet();
247
Roland Levillain55dcfb52014-10-24 18:09:09 +0100248 typedef Expected (*fptr)();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100249 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -0700250 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Phil Wang751beff2015-08-28 15:17:15 +0800251 if (target_isa == kThumb2) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100252 // For thumb we need the bottom bit set.
253 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
254 }
Phil Wang751beff2015-08-28 15:17:15 +0800255 VerifyGeneratedCode(target_isa, f, has_result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100256}
257
Scott Wakeling2c76e062016-08-31 09:48:54 +0100258static void ValidateGraph(HGraph* graph) {
David Brazdilbadd8262016-02-02 16:28:56 +0000259 GraphChecker graph_checker(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000260 graph_checker.Run();
David Brazdilbadd8262016-02-02 16:28:56 +0000261 if (!graph_checker.IsValid()) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800262 for (const auto& error : graph_checker.GetErrors()) {
David Brazdilbadd8262016-02-02 16:28:56 +0000263 std::cout << error << std::endl;
264 }
265 }
David Brazdil58282f42016-01-14 12:45:10 +0000266 ASSERT_TRUE(graph_checker.IsValid());
Scott Wakeling2c76e062016-08-31 09:48:54 +0100267}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100268
Scott Wakeling2c76e062016-08-31 09:48:54 +0100269template <typename Expected>
270static void RunCodeNoCheck(CodeGenerator* codegen,
271 HGraph* graph,
Andreas Gampeca620d72016-11-08 08:09:33 -0800272 const std::function<void(HGraph*)>& hook_before_codegen,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100273 bool has_result,
274 Expected expected) {
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100275 SsaLivenessAnalysis liveness(graph, codegen);
David Brazdil58282f42016-01-14 12:45:10 +0000276 PrepareForRegisterAllocation(graph).Run();
277 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700278 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100279 hook_before_codegen(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100280 InternalCodeAllocator allocator;
David Brazdil58282f42016-01-14 12:45:10 +0000281 codegen->Compile(&allocator);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100282 Run(allocator, *codegen, has_result, expected);
283}
284
Roland Levillain55dcfb52014-10-24 18:09:09 +0100285template <typename Expected>
Scott Wakeling2c76e062016-08-31 09:48:54 +0100286static 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,
David Brazdil58282f42016-01-14 12:45:10 +0000297 HGraph* graph,
298 std::function<void(HGraph*)> hook_before_codegen,
299 bool has_result,
300 Expected expected) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000301 CompilerOptions compiler_options;
Scott Wakeling2c76e062016-08-31 09:48:54 +0100302 CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options);
303 RunCode(codegen, graph, hook_before_codegen, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100304}
305
Scott Wakeling2c76e062016-08-31 09:48:54 +0100306#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}
Scott Wakelingfe885462016-09-22 10:24:38 +0100314
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}
Scott Wakeling2c76e062016-08-31 09:48:54 +0100321#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),
Scott Wakelingfe885462016-09-22 10:24:38 +0100376 CodegenTargetConfig(kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +0100377#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
David Brazdil58282f42016-01-14 12:45:10 +0000393 };
394
Scott Wakeling2c76e062016-08-31 09:48:54 +0100395 for (auto test_config : test_config_candidates) {
396 if (CanExecute(test_config.GetInstructionSet())) {
397 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +0000398 }
399 }
400
401 return v;
402}
403
404static void TestCode(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800405 bool has_result = false,
406 int32_t expected = 0) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100407 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000408 ArenaPool pool;
409 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000410 HGraph* graph = CreateCFG(&arena, data);
David Brazdil58282f42016-01-14 12:45:10 +0000411 // Remove suspend checks, they cannot be executed in this context.
412 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100413 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000414 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100415}
416
David Brazdil58282f42016-01-14 12:45:10 +0000417static void TestCodeLong(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800418 bool has_result,
419 int64_t expected) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100420 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000421 ArenaPool pool;
422 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000423 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
David Brazdil58282f42016-01-14 12:45:10 +0000424 // Remove suspend checks, they cannot be executed in this context.
425 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100426 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000427 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100428}
429
David Brazdil58282f42016-01-14 12:45:10 +0000430class CodegenTest : public CommonCompilerTest {};
Phil Wang751beff2015-08-28 15:17:15 +0800431
David Brazdil58282f42016-01-14 12:45:10 +0000432TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000433 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000434 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000435}
436
David Brazdil58282f42016-01-14 12:45:10 +0000437TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000438 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000439 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000440 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000441
David Brazdil58282f42016-01-14 12:45:10 +0000442 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000443}
444
David Brazdil58282f42016-01-14 12:45:10 +0000445TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000446 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000447 Instruction::GOTO | 0x100,
448 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000449 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000450
David Brazdil58282f42016-01-14 12:45:10 +0000451 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000452}
453
David Brazdil58282f42016-01-14 12:45:10 +0000454TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000455 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000456 Instruction::GOTO | 0x200,
457 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000458 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000459
David Brazdil58282f42016-01-14 12:45:10 +0000460 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000461
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000462 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000463 Instruction::GOTO_16, 3,
464 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000465 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000466
David Brazdil58282f42016-01-14 12:45:10 +0000467 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000468
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000469 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000470 Instruction::GOTO_32, 4, 0,
471 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000472 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000473
David Brazdil58282f42016-01-14 12:45:10 +0000474 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000475}
476
David Brazdil58282f42016-01-14 12:45:10 +0000477TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000478 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000479 Instruction::RETURN_VOID,
480 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000481 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000482
David Brazdil58282f42016-01-14 12:45:10 +0000483 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000484}
485
David Brazdil58282f42016-01-14 12:45:10 +0000486TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000487 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
David Brazdil58282f42016-01-14 12:45:10 +0000493 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000494}
495
David Brazdil58282f42016-01-14 12:45:10 +0000496TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000497 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
498 Instruction::CONST_4 | 0 | 0,
499 Instruction::RETURN_VOID);
500
David Brazdil58282f42016-01-14 12:45:10 +0000501 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000502}
503
David Brazdil58282f42016-01-14 12:45:10 +0000504TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000505 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
506 Instruction::CONST_4 | 0 | 0,
507 Instruction::RETURN | 0);
508
David Brazdil58282f42016-01-14 12:45:10 +0000509 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000510}
511
David Brazdil58282f42016-01-14 12:45:10 +0000512TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000513 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
David Brazdil58282f42016-01-14 12:45:10 +0000518 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000519}
520
David Brazdil58282f42016-01-14 12:45:10 +0000521TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000522 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
David Brazdil58282f42016-01-14 12:45:10 +0000527 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000528}
529
David Brazdil58282f42016-01-14 12:45:10 +0000530TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000531 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
David Brazdil58282f42016-01-14 12:45:10 +0000538 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000539}
540
David Brazdil58282f42016-01-14 12:45:10 +0000541TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000542 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
David Brazdil58282f42016-01-14 12:45:10 +0000549 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000550}
551
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100552// Exercise bit-wise (one's complement) not-int instruction.
553#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000554TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100555 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100556 const uint16_t input_lo = Low16Bits(input); \
557 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100558 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 \
David Brazdil58282f42016-01-14 12:45:10 +0000563 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100564}
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)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100570NOT_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)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100574
575#undef NOT_INT_TEST
576
Roland Levillain55dcfb52014-10-24 18:09:09 +0100577// Exercise bit-wise (one's complement) not-long instruction.
578#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000579TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100580 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 \
David Brazdil58282f42016-01-14 12:45:10 +0000590 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100591}
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
David Brazdil58282f42016-01-14 12:45:10 +0000629TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000630 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
David Brazdil58282f42016-01-14 12:45:10 +0000643 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000644}
645
David Brazdil58282f42016-01-14 12:45:10 +0000646TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000647 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
David Brazdil58282f42016-01-14 12:45:10 +0000653 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000654}
655
David Brazdil58282f42016-01-14 12:45:10 +0000656TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000657 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
David Brazdil58282f42016-01-14 12:45:10 +0000663 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000664}
665
David Brazdil58282f42016-01-14 12:45:10 +0000666TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000667 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
David Brazdil58282f42016-01-14 12:45:10 +0000672 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000673}
674
David Brazdil58282f42016-01-14 12:45:10 +0000675TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000676 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
David Brazdil58282f42016-01-14 12:45:10 +0000681 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000682}
683
David Brazdil58282f42016-01-14 12:45:10 +0000684TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100685 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);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100690
David Brazdil58282f42016-01-14 12:45:10 +0000691 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100692}
693
David Brazdil58282f42016-01-14 12:45:10 +0000694TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100695 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
David Brazdil58282f42016-01-14 12:45:10 +0000701 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100702}
703
David Brazdil58282f42016-01-14 12:45:10 +0000704TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100705 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000706 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
707 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100708 Instruction::MUL_LONG, 2 << 8 | 0,
709 Instruction::RETURN_WIDE);
710
David Brazdil58282f42016-01-14 12:45:10 +0000711 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100712}
713
David Brazdil58282f42016-01-14 12:45:10 +0000714TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100715 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000716 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
717 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100718 Instruction::MUL_LONG_2ADDR | 2 << 12,
719 Instruction::RETURN_WIDE);
720
David Brazdil58282f42016-01-14 12:45:10 +0000721 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100722}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100723
David Brazdil58282f42016-01-14 12:45:10 +0000724TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100725 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
David Brazdil58282f42016-01-14 12:45:10 +0000730 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100731}
732
David Brazdil58282f42016-01-14 12:45:10 +0000733TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100734 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
David Brazdil58282f42016-01-14 12:45:10 +0000739 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100740}
741
David Brazdil58282f42016-01-14 12:45:10 +0000742TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100743 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Alexandre Rames92730742014-10-01 12:55:56 +0100744 ArenaPool pool;
745 ArenaAllocator allocator(&pool);
David Brazdil58282f42016-01-14 12:45:10 +0000746
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100747 HGraph* graph = CreateGraph(&allocator);
David Brazdilbadd8262016-02-02 16:28:56 +0000748
David Brazdil58282f42016-01-14 12:45:10 +0000749 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
750 graph->AddBlock(entry);
751 graph->SetEntryBlock(entry);
752 entry->AddInstruction(new (&allocator) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100753
David Brazdil58282f42016-01-14 12:45:10 +0000754 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);
Alexandre Rames92730742014-10-01 12:55:56 +0100765 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100766 graph->SetExitBlock(exit_block);
767
David Brazdil58282f42016-01-14 12:45:10 +0000768 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
David Brazdilb11b0722016-01-28 16:22:40 +0000780 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000781 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000782 PrepareForRegisterAllocation(graph).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000783 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100784
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800785 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100786 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800787 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100788 block->InsertInstructionBefore(move, block->GetLastInstruction());
789 };
790
Scott Wakeling2c76e062016-08-31 09:48:54 +0100791 RunCode(target_config, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100792 }
793}
794
David Brazdil58282f42016-01-14 12:45:10 +0000795TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100796 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000797 // 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
Alexandre Rames92730742014-10-01 12:55:56 +0100800
David Brazdil58282f42016-01-14 12:45:10 +0000801 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100802
David Brazdil58282f42016-01-14 12:45:10 +0000803 int lhs[] = {1, 2, -1, 2, 0xabc};
804 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100805
David Brazdil58282f42016-01-14 12:45:10 +0000806 for (size_t i = 0; i < arraysize(lhs); i++) {
807 ArenaPool pool;
808 ArenaAllocator allocator(&pool);
809 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100810
David Brazdil58282f42016-01-14 12:45:10 +0000811 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());
Alexandre Rames92730742014-10-01 12:55:56 +0100820
David Brazdil58282f42016-01-14 12:45:10 +0000821 entry_block->AddSuccessor(code_block);
822 code_block->AddSuccessor(exit_block);
823 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100824
David Brazdil58282f42016-01-14 12:45:10 +0000825 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);
Alexandre Rames92730742014-10-01 12:55:56 +0100831
David Brazdilbadd8262016-02-02 16:28:56 +0000832 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000833 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 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100838 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000839 }
Alexandre Rames92730742014-10-01 12:55:56 +0100840 }
841}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100842
David Brazdil58282f42016-01-14 12:45:10 +0000843TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100844 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000845 // 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);
David Brazdil6e332522016-02-02 16:15:27 +0000886 // 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);
David Brazdil58282f42016-01-14 12:45:10 +0000889 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
David Brazdilbadd8262016-02-02 16:28:56 +0000900 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000901 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 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100906 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000907 }
908 }
909}
910
911TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000912 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
David Brazdil58282f42016-01-14 12:45:10 +0000917 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000918}
919
David Brazdil58282f42016-01-14 12:45:10 +0000920TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000921 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
David Brazdil58282f42016-01-14 12:45:10 +0000927 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000928}
929
Aart Bike9f37602015-10-09 11:15:55 -0700930// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800931static void TestComparison(IfCondition condition,
932 int64_t i,
933 int64_t j,
934 Primitive::Type type,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100935 const CodegenTargetConfig target_config) {
Aart Bike9f37602015-10-09 11:15:55 -0700936 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
David Brazdilbadd8262016-02-02 16:28:56 +00001016 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +01001017 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -07001018}
1019
David Brazdil58282f42016-01-14 12:45:10 +00001020TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001021 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +00001022 for (int64_t i = -1; i <= 1; i++) {
1023 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001024 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1025 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
1026 }
David Brazdil58282f42016-01-14 12:45:10 +00001027 }
Aart Bike9f37602015-10-09 11:15:55 -07001028 }
1029 }
1030}
1031
David Brazdil58282f42016-01-14 12:45:10 +00001032TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001033 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +00001034 for (int64_t i = -1; i <= 1; i++) {
1035 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001036 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1037 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
1038 }
David Brazdil58282f42016-01-14 12:45:10 +00001039 }
Aart Bike9f37602015-10-09 11:15:55 -07001040 }
1041 }
1042}
1043
Alexey Frunze58320ce2016-08-30 21:40:46 -07001044#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
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001107} // namespace art