blob: d9707043685aefb43d6f0586a8e6528630577c03 [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"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010032#include "code_generator_arm.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010033#include "code_generator_arm64.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020034#include "code_generator_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070035#include "code_generator_mips64.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010036#include "code_generator_x86.h"
37#include "code_generator_x86_64.h"
Phil Wang751beff2015-08-28 15:17:15 +080038#include "code_simulator_container.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000039#include "common_compiler_test.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000040#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000041#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000042#include "driver/compiler_options.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000043#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000044#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010045#include "prepare_for_register_allocation.h"
46#include "register_allocator.h"
47#include "ssa_liveness_analysis.h"
Roland Levillain55dcfb52014-10-24 18:09:09 +010048#include "utils.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010049#include "utils/arm/managed_register_arm.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020050#include "utils/mips/managed_register_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070051#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010052#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000053
54#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000055
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000056namespace art {
57
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000058// Provide our own codegen, that ensures the C calling conventions
59// are preserved. Currently, ART and C do not match as R4 is caller-save
60// in ART, and callee-save in C. Alternatively, we could use or write
61// the stub that saves and restores all registers, but it is easier
62// to just overwrite the code generator.
63class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
64 public:
65 TestCodeGeneratorARM(HGraph* graph,
66 const ArmInstructionSetFeatures& isa_features,
67 const CompilerOptions& compiler_options)
68 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +010069 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
70 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000071 }
72
73 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE {
74 arm::CodeGeneratorARM::SetupBlockedRegisters(is_baseline);
Nicolas Geoffray5da21802015-04-20 09:29:18 +010075 blocked_core_registers_[arm::R4] = true;
76 blocked_core_registers_[arm::R6] = false;
77 blocked_core_registers_[arm::R7] = false;
Nicolas Geoffraye6362282015-01-26 13:57:30 +000078 // Makes pair R6-R7 available.
Nicolas Geoffray5da21802015-04-20 09:29:18 +010079 blocked_register_pairs_[arm::R6_R7] = false;
80 }
81};
82
83class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
84 public:
85 TestCodeGeneratorX86(HGraph* graph,
86 const X86InstructionSetFeatures& isa_features,
87 const CompilerOptions& compiler_options)
88 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
89 // Save edi, we need it for getting enough registers for long multiplication.
90 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
91 }
92
93 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE {
94 x86::CodeGeneratorX86::SetupBlockedRegisters(is_baseline);
95 // ebx is a callee-save register in C, but caller-save for ART.
96 blocked_core_registers_[x86::EBX] = true;
97 blocked_register_pairs_[x86::EAX_EBX] = true;
98 blocked_register_pairs_[x86::EDX_EBX] = true;
99 blocked_register_pairs_[x86::ECX_EBX] = true;
100 blocked_register_pairs_[x86::EBX_EDI] = true;
101
102 // Make edi available.
103 blocked_core_registers_[x86::EDI] = false;
104 blocked_register_pairs_[x86::ECX_EDI] = false;
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000105 }
106};
107
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000108class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000109 public:
Ian Rogersd582fa42014-11-05 23:46:43 -0800110 InternalCodeAllocator() : size_(0) { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000111
112 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000113 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000114 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000115 return memory_.get();
116 }
117
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000118 size_t GetSize() const { return size_; }
119 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000120
121 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000122 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -0700123 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000124
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000125 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000126};
127
Phil Wang751beff2015-08-28 15:17:15 +0800128static bool CanExecuteOnHardware(InstructionSet target_isa) {
129 return (target_isa == kRuntimeISA)
130 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
131 || (kRuntimeISA == kArm && target_isa == kThumb2);
132}
133
134static bool CanExecute(InstructionSet target_isa) {
135 CodeSimulatorContainer simulator(target_isa);
136 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
137}
138
139template <typename Expected>
140static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
141
142template <>
143bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
144 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
145 return simulator->GetCReturnBool();
146}
147
148template <>
149int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
150 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
151 return simulator->GetCReturnInt32();
152}
153
154template <>
155int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
156 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
157 return simulator->GetCReturnInt64();
158}
159
160template <typename Expected>
161static void VerifyGeneratedCode(InstructionSet target_isa,
162 Expected (*f)(),
163 bool has_result,
164 Expected expected) {
165 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
166
167 // Verify on simulator.
168 CodeSimulatorContainer simulator(target_isa);
169 if (simulator.CanSimulate()) {
170 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
171 if (has_result) {
172 ASSERT_EQ(expected, result);
173 }
174 }
175
176 // Verify on hardware.
177 if (CanExecuteOnHardware(target_isa)) {
178 Expected result = f();
179 if (has_result) {
180 ASSERT_EQ(expected, result);
181 }
182 }
183}
184
Roland Levillain55dcfb52014-10-24 18:09:09 +0100185template <typename Expected>
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100186static void Run(const InternalCodeAllocator& allocator,
187 const CodeGenerator& codegen,
188 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100189 Expected expected) {
Phil Wang751beff2015-08-28 15:17:15 +0800190 InstructionSet target_isa = codegen.GetInstructionSet();
191
Roland Levillain55dcfb52014-10-24 18:09:09 +0100192 typedef Expected (*fptr)();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100193 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -0700194 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Phil Wang751beff2015-08-28 15:17:15 +0800195 if (target_isa == kThumb2) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100196 // For thumb we need the bottom bit set.
197 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
198 }
Phil Wang751beff2015-08-28 15:17:15 +0800199 VerifyGeneratedCode(target_isa, f, has_result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100200}
201
Roland Levillain55dcfb52014-10-24 18:09:09 +0100202template <typename Expected>
Phil Wang751beff2015-08-28 15:17:15 +0800203static void RunCodeBaseline(InstructionSet target_isa,
204 HGraph* graph,
205 bool has_result,
206 Expected expected) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000207 InternalCodeAllocator allocator;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100208
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000209 CompilerOptions compiler_options;
Mark Mendellfb8d2792015-03-31 22:16:59 -0400210 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
211 X86InstructionSetFeatures::FromCppDefines());
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100212 TestCodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
Nicolas Geoffray73e80c32014-07-22 17:47:56 +0100213 // We avoid doing a stack overflow check that requires the runtime being setup,
214 // by making sure the compiler knows the methods we are running are leaf methods.
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100215 codegenX86.CompileBaseline(&allocator, true);
Phil Wang751beff2015-08-28 15:17:15 +0800216 if (target_isa == kX86) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100217 Run(allocator, codegenX86, has_result, expected);
218 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100219
Serban Constantinescu579885a2015-02-22 20:51:33 +0000220 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
Andreas Gampedf649502015-01-06 14:13:52 -0800221 ArmInstructionSetFeatures::FromCppDefines());
Serban Constantinescu579885a2015-02-22 20:51:33 +0000222 TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100223 codegenARM.CompileBaseline(&allocator, true);
Phil Wang751beff2015-08-28 15:17:15 +0800224 if (target_isa == kArm || target_isa == kThumb2) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100225 Run(allocator, codegenARM, has_result, expected);
226 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100227
Mark Mendellfb8d2792015-03-31 22:16:59 -0400228 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
229 X86_64InstructionSetFeatures::FromCppDefines());
230 x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100231 codegenX86_64.CompileBaseline(&allocator, true);
Phil Wang751beff2015-08-28 15:17:15 +0800232 if (target_isa == kX86_64) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100233 Run(allocator, codegenX86_64, has_result, expected);
234 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100235
Serban Constantinescu579885a2015-02-22 20:51:33 +0000236 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
237 Arm64InstructionSetFeatures::FromCppDefines());
238 arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
Alexandre Rames5319def2014-10-23 10:03:10 +0100239 codegenARM64.CompileBaseline(&allocator, true);
Phil Wang751beff2015-08-28 15:17:15 +0800240 if (target_isa == kArm64) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100241 Run(allocator, codegenARM64, has_result, expected);
242 }
Alexey Frunze4dda3372015-06-01 18:31:49 -0700243
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200244 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
245 MipsInstructionSetFeatures::FromCppDefines());
246 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), compiler_options);
247 codegenMIPS.CompileBaseline(&allocator, true);
248 if (kRuntimeISA == kMips) {
249 Run(allocator, codegenMIPS, has_result, expected);
250 }
251
Alexey Frunze4dda3372015-06-01 18:31:49 -0700252 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
253 Mips64InstructionSetFeatures::FromCppDefines());
254 mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
255 codegenMIPS64.CompileBaseline(&allocator, true);
Phil Wang751beff2015-08-28 15:17:15 +0800256 if (target_isa == kMips64) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700257 Run(allocator, codegenMIPS64, has_result, expected);
258 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000259}
260
Roland Levillain55dcfb52014-10-24 18:09:09 +0100261template <typename Expected>
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100262static void RunCodeOptimized(CodeGenerator* codegen,
263 HGraph* graph,
264 std::function<void(HGraph*)> hook_before_codegen,
265 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100266 Expected expected) {
Nicolas Geoffrayea809422015-06-24 14:25:09 +0100267 // Tests may have already computed it.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100268 if (graph->GetReversePostOrder().empty()) {
Nicolas Geoffrayea809422015-06-24 14:25:09 +0100269 graph->BuildDominatorTree();
270 }
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100271 SsaLivenessAnalysis liveness(graph, codegen);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100272 liveness.Analyze();
273
274 RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
275 register_allocator.AllocateRegisters();
276 hook_before_codegen(graph);
277
278 InternalCodeAllocator allocator;
279 codegen->CompileOptimized(&allocator);
280 Run(allocator, *codegen, has_result, expected);
281}
282
Roland Levillain55dcfb52014-10-24 18:09:09 +0100283template <typename Expected>
Phil Wang751beff2015-08-28 15:17:15 +0800284static void RunCodeOptimized(InstructionSet target_isa,
285 HGraph* graph,
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100286 std::function<void(HGraph*)> hook_before_codegen,
287 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100288 Expected expected) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000289 CompilerOptions compiler_options;
Phil Wang751beff2015-08-28 15:17:15 +0800290 if (target_isa == kArm || target_isa == kThumb2) {
291 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
292 ArmInstructionSetFeatures::FromCppDefines());
293 TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100294 RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected);
Phil Wang751beff2015-08-28 15:17:15 +0800295 } else if (target_isa == kArm64) {
296 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
297 Arm64InstructionSetFeatures::FromCppDefines());
298 arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
Alexandre Rames3e69f162014-12-10 10:36:50 +0000299 RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected);
Phil Wang751beff2015-08-28 15:17:15 +0800300 } else if (target_isa == kX86) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400301 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
302 X86InstructionSetFeatures::FromCppDefines());
303 x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
Alexandre Rames3e69f162014-12-10 10:36:50 +0000304 RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected);
Phil Wang751beff2015-08-28 15:17:15 +0800305 } else if (target_isa == kX86_64) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400306 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
307 X86_64InstructionSetFeatures::FromCppDefines());
308 x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100309 RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
Phil Wang751beff2015-08-28 15:17:15 +0800310 } else if (target_isa == kMips) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200311 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
312 MipsInstructionSetFeatures::FromCppDefines());
313 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), compiler_options);
314 RunCodeOptimized(&codegenMIPS, graph, hook_before_codegen, has_result, expected);
Phil Wang751beff2015-08-28 15:17:15 +0800315 } else if (target_isa == kMips64) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700316 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
317 Mips64InstructionSetFeatures::FromCppDefines());
318 mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
319 RunCodeOptimized(&codegenMIPS64, graph, hook_before_codegen, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100320 }
321}
322
Phil Wang751beff2015-08-28 15:17:15 +0800323static void TestCode(InstructionSet target_isa,
324 const uint16_t* data,
325 bool has_result = false,
326 int32_t expected = 0) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100327 ArenaPool pool;
328 ArenaAllocator arena(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100329 HGraph* graph = CreateGraph(&arena);
David Brazdil5e8b1372015-01-23 14:39:08 +0000330 HGraphBuilder builder(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100331 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +0000332 bool graph_built = builder.BuildGraph(*item);
333 ASSERT_TRUE(graph_built);
Calin Juravle039b6e22014-10-23 12:32:11 +0100334 // Remove suspend checks, they cannot be executed in this context.
Calin Juravle48dee042014-10-22 15:54:12 +0100335 RemoveSuspendChecks(graph);
Phil Wang751beff2015-08-28 15:17:15 +0800336 RunCodeBaseline(target_isa, graph, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100337}
338
Phil Wang751beff2015-08-28 15:17:15 +0800339static void TestCodeLong(InstructionSet target_isa,
340 const uint16_t* data,
341 bool has_result,
342 int64_t expected) {
Roland Levillain55dcfb52014-10-24 18:09:09 +0100343 ArenaPool pool;
344 ArenaAllocator arena(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100345 HGraph* graph = CreateGraph(&arena);
David Brazdil5e8b1372015-01-23 14:39:08 +0000346 HGraphBuilder builder(graph, Primitive::kPrimLong);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100347 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +0000348 bool graph_built = builder.BuildGraph(*item);
349 ASSERT_TRUE(graph_built);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100350 // Remove suspend checks, they cannot be executed in this context.
351 RemoveSuspendChecks(graph);
Phil Wang751beff2015-08-28 15:17:15 +0800352 RunCodeBaseline(target_isa, graph, has_result, expected);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100353}
354
Phil Wang751beff2015-08-28 15:17:15 +0800355class CodegenTest: public ::testing::TestWithParam<InstructionSet> {};
356
357TEST_P(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000358 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
Phil Wang751beff2015-08-28 15:17:15 +0800359 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000360}
361
Phil Wang751beff2015-08-28 15:17:15 +0800362TEST_P(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000363 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000364 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000365 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000366
Phil Wang751beff2015-08-28 15:17:15 +0800367 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000368}
369
Phil Wang751beff2015-08-28 15:17:15 +0800370TEST_P(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000371 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000372 Instruction::GOTO | 0x100,
373 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000374 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000375
Phil Wang751beff2015-08-28 15:17:15 +0800376 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000377}
378
Phil Wang751beff2015-08-28 15:17:15 +0800379TEST_P(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000380 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000381 Instruction::GOTO | 0x200,
382 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000383 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000384
Phil Wang751beff2015-08-28 15:17:15 +0800385 TestCode(GetParam(), data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000386
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000387 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000388 Instruction::GOTO_16, 3,
389 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000390 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000391
Phil Wang751beff2015-08-28 15:17:15 +0800392 TestCode(GetParam(), data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000393
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000394 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000395 Instruction::GOTO_32, 4, 0,
396 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000397 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000398
Phil Wang751beff2015-08-28 15:17:15 +0800399 TestCode(GetParam(), data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000400}
401
Phil Wang751beff2015-08-28 15:17:15 +0800402TEST_P(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000403 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000404 Instruction::RETURN_VOID,
405 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000406 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000407
Phil Wang751beff2015-08-28 15:17:15 +0800408 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000409}
410
Phil Wang751beff2015-08-28 15:17:15 +0800411TEST_P(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000412 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
413 Instruction::CONST_4 | 0 | 0,
414 Instruction::IF_EQ, 3,
415 Instruction::GOTO | 0x100,
416 Instruction::RETURN_VOID);
417
Phil Wang751beff2015-08-28 15:17:15 +0800418 TestCode(GetParam(), data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000419}
420
Phil Wang751beff2015-08-28 15:17:15 +0800421TEST_P(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000422 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
423 Instruction::CONST_4 | 0 | 0,
424 Instruction::RETURN_VOID);
425
Phil Wang751beff2015-08-28 15:17:15 +0800426 TestCode(GetParam(), data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000427}
428
Phil Wang751beff2015-08-28 15:17:15 +0800429TEST_P(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000430 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
431 Instruction::CONST_4 | 0 | 0,
432 Instruction::RETURN | 0);
433
Phil Wang751beff2015-08-28 15:17:15 +0800434 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000435}
436
Phil Wang751beff2015-08-28 15:17:15 +0800437TEST_P(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000438 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
439 Instruction::CONST_4 | 0 | 0,
440 Instruction::CONST_4 | 0 | 1 << 8,
441 Instruction::RETURN | 1 << 8);
442
Phil Wang751beff2015-08-28 15:17:15 +0800443 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000444}
445
Phil Wang751beff2015-08-28 15:17:15 +0800446TEST_P(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000447 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
448 Instruction::CONST_4 | 0 | 0,
449 Instruction::CONST_4 | 1 << 8 | 1 << 12,
450 Instruction::RETURN | 1 << 8);
451
Phil Wang751beff2015-08-28 15:17:15 +0800452 TestCode(GetParam(), data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000453}
454
Phil Wang751beff2015-08-28 15:17:15 +0800455TEST_P(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000456 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
457 Instruction::CONST_4 | 0 | 0,
458 Instruction::CONST_4 | 1 << 8 | 1 << 12,
459 Instruction::IF_EQ, 3,
460 Instruction::RETURN | 0 << 8,
461 Instruction::RETURN | 1 << 8);
462
Phil Wang751beff2015-08-28 15:17:15 +0800463 TestCode(GetParam(), data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000464}
465
Phil Wang751beff2015-08-28 15:17:15 +0800466TEST_P(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000467 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
468 Instruction::CONST_4 | 0 | 0,
469 Instruction::CONST_4 | 1 << 8 | 1 << 12,
470 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
471 Instruction::RETURN | 0 << 8,
472 Instruction::RETURN | 1 << 8);
473
Phil Wang751beff2015-08-28 15:17:15 +0800474 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000475}
476
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100477// Exercise bit-wise (one's complement) not-int instruction.
478#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
Phil Wang751beff2015-08-28 15:17:15 +0800479TEST_P(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100480 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100481 const uint16_t input_lo = Low16Bits(input); \
482 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100483 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
484 Instruction::CONST | 0 << 8, input_lo, input_hi, \
485 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
486 Instruction::RETURN | 1 << 8); \
487 \
Phil Wang751beff2015-08-28 15:17:15 +0800488 TestCode(GetParam(), data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100489}
490
491NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
492NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
493NOT_INT_TEST(ReturnNotInt0, 0, -1)
494NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100495NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
496NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
497NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
498NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100499
500#undef NOT_INT_TEST
501
Roland Levillain55dcfb52014-10-24 18:09:09 +0100502// Exercise bit-wise (one's complement) not-long instruction.
503#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
Phil Wang751beff2015-08-28 15:17:15 +0800504TEST_P(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100505 const int64_t input = INPUT; \
506 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
507 const uint16_t word1 = High16Bits(Low32Bits(input)); \
508 const uint16_t word2 = Low16Bits(High32Bits(input)); \
509 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
510 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
511 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
512 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
513 Instruction::RETURN_WIDE | 2 << 8); \
514 \
Phil Wang751beff2015-08-28 15:17:15 +0800515 TestCodeLong(GetParam(), data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100516}
517
518NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
519NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
520NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
521NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
522
523NOT_LONG_TEST(ReturnNotLongINT32_MIN,
524 INT64_C(-2147483648),
525 INT64_C(2147483647)) // (2^31) - 1
526NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
527 INT64_C(-2147483647),
528 INT64_C(2147483646)) // (2^31) - 2
529NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
530 INT64_C(2147483646),
531 INT64_C(-2147483647)) // -(2^31) - 1
532NOT_LONG_TEST(ReturnNotLongINT32_MAX,
533 INT64_C(2147483647),
534 INT64_C(-2147483648)) // -(2^31)
535
536// Note that the C++ compiler won't accept
537// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
538// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
539NOT_LONG_TEST(ReturnNotINT64_MIN,
540 INT64_C(-9223372036854775807)-1,
541 INT64_C(9223372036854775807)); // (2^63) - 1
542NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
543 INT64_C(-9223372036854775807),
544 INT64_C(9223372036854775806)); // (2^63) - 2
545NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
546 INT64_C(9223372036854775806),
547 INT64_C(-9223372036854775807)); // -(2^63) - 1
548NOT_LONG_TEST(ReturnNotLongINT64_MAX,
549 INT64_C(9223372036854775807),
550 INT64_C(-9223372036854775807)-1); // -(2^63)
551
552#undef NOT_LONG_TEST
553
Phil Wang751beff2015-08-28 15:17:15 +0800554TEST_P(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000555 const int64_t input = INT64_C(4294967296); // 2^32
556 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
557 const uint16_t word1 = High16Bits(Low32Bits(input));
558 const uint16_t word2 = Low16Bits(High32Bits(input));
559 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
560 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
561 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
562 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
563 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
564 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
565 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
566 Instruction::RETURN_WIDE | 2 << 8);
567
Phil Wang751beff2015-08-28 15:17:15 +0800568 TestCodeLong(GetParam(), data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000569}
570
Phil Wang751beff2015-08-28 15:17:15 +0800571TEST_P(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000572 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
573 Instruction::CONST_4 | 3 << 12 | 0,
574 Instruction::CONST_4 | 4 << 12 | 1 << 8,
575 Instruction::ADD_INT, 1 << 8 | 0,
576 Instruction::RETURN);
577
Phil Wang751beff2015-08-28 15:17:15 +0800578 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000579}
580
Phil Wang751beff2015-08-28 15:17:15 +0800581TEST_P(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000582 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
583 Instruction::CONST_4 | 3 << 12 | 0,
584 Instruction::CONST_4 | 4 << 12 | 1 << 8,
585 Instruction::ADD_INT_2ADDR | 1 << 12,
586 Instruction::RETURN);
587
Phil Wang751beff2015-08-28 15:17:15 +0800588 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000589}
590
Phil Wang751beff2015-08-28 15:17:15 +0800591TEST_P(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000592 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
593 Instruction::CONST_4 | 4 << 12 | 0 << 8,
594 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
595 Instruction::RETURN);
596
Phil Wang751beff2015-08-28 15:17:15 +0800597 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000598}
599
Phil Wang751beff2015-08-28 15:17:15 +0800600TEST_P(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000601 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
602 Instruction::CONST_4 | 4 << 12 | 0 << 8,
603 Instruction::ADD_INT_LIT16, 3,
604 Instruction::RETURN);
605
Phil Wang751beff2015-08-28 15:17:15 +0800606 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000607}
608
Phil Wang751beff2015-08-28 15:17:15 +0800609TEST_P(CodegenTest, NonMaterializedCondition) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100610 ArenaPool pool;
611 ArenaAllocator allocator(&pool);
612
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100613 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100614 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
615 graph->AddBlock(entry);
616 graph->SetEntryBlock(entry);
617 entry->AddInstruction(new (&allocator) HGoto());
618
619 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
620 graph->AddBlock(first_block);
621 entry->AddSuccessor(first_block);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000622 HIntConstant* constant0 = graph->GetIntConstant(0);
623 HIntConstant* constant1 = graph->GetIntConstant(1);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100624 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
625 first_block->AddInstruction(equal);
626 first_block->AddInstruction(new (&allocator) HIf(equal));
627
628 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
629 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
630 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
631
632 graph->AddBlock(then);
633 graph->AddBlock(else_);
634 graph->AddBlock(exit);
635 first_block->AddSuccessor(then);
636 first_block->AddSuccessor(else_);
637 then->AddSuccessor(exit);
638 else_->AddSuccessor(exit);
639
640 exit->AddInstruction(new (&allocator) HExit());
641 then->AddInstruction(new (&allocator) HReturn(constant0));
642 else_->AddInstruction(new (&allocator) HReturn(constant1));
643
644 ASSERT_TRUE(equal->NeedsMaterialization());
645 graph->BuildDominatorTree();
646 PrepareForRegisterAllocation(graph).Run();
647 ASSERT_FALSE(equal->NeedsMaterialization());
648
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800649 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100650 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800651 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100652 block->InsertInstructionBefore(move, block->GetLastInstruction());
653 };
654
Phil Wang751beff2015-08-28 15:17:15 +0800655 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, 0);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100656}
657
Phil Wang751beff2015-08-28 15:17:15 +0800658TEST_P(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100659 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
660 Instruction::CONST_4 | 3 << 12 | 0,
661 Instruction::CONST_4 | 4 << 12 | 1 << 8,
662 Instruction::MUL_INT, 1 << 8 | 0,
663 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100664
Phil Wang751beff2015-08-28 15:17:15 +0800665 TestCode(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100666}
667
Phil Wang751beff2015-08-28 15:17:15 +0800668TEST_P(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100669 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
670 Instruction::CONST_4 | 3 << 12 | 0,
671 Instruction::CONST_4 | 4 << 12 | 1 << 8,
672 Instruction::MUL_INT_2ADDR | 1 << 12,
673 Instruction::RETURN);
674
Phil Wang751beff2015-08-28 15:17:15 +0800675 TestCode(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100676}
677
Phil Wang751beff2015-08-28 15:17:15 +0800678TEST_P(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100679 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
680 Instruction::CONST_4 | 3 << 12 | 0,
681 Instruction::CONST_4 | 0 << 12 | 1 << 8,
682 Instruction::CONST_4 | 4 << 12 | 2 << 8,
683 Instruction::CONST_4 | 0 << 12 | 3 << 8,
684 Instruction::MUL_LONG, 2 << 8 | 0,
685 Instruction::RETURN_WIDE);
686
Phil Wang751beff2015-08-28 15:17:15 +0800687 TestCodeLong(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100688}
689
Phil Wang751beff2015-08-28 15:17:15 +0800690TEST_P(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100691 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
692 Instruction::CONST_4 | 3 << 12 | 0 << 8,
693 Instruction::CONST_4 | 0 << 12 | 1 << 8,
694 Instruction::CONST_4 | 4 << 12 | 2 << 8,
695 Instruction::CONST_4 | 0 << 12 | 3 << 8,
696 Instruction::MUL_LONG_2ADDR | 2 << 12,
697 Instruction::RETURN_WIDE);
698
Phil Wang751beff2015-08-28 15:17:15 +0800699 TestCodeLong(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100700}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100701
Phil Wang751beff2015-08-28 15:17:15 +0800702TEST_P(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100703 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
704 Instruction::CONST_4 | 4 << 12 | 0 << 8,
705 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
706 Instruction::RETURN);
707
Phil Wang751beff2015-08-28 15:17:15 +0800708 TestCode(GetParam(), data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100709}
710
Phil Wang751beff2015-08-28 15:17:15 +0800711TEST_P(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100712 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
713 Instruction::CONST_4 | 4 << 12 | 0 << 8,
714 Instruction::MUL_INT_LIT16, 3,
715 Instruction::RETURN);
716
Phil Wang751beff2015-08-28 15:17:15 +0800717 TestCode(GetParam(), data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100718}
719
Phil Wang751beff2015-08-28 15:17:15 +0800720TEST_P(CodegenTest, MaterializedCondition1) {
Alexandre Rames92730742014-10-01 12:55:56 +0100721 // Check that condition are materialized correctly. A materialized condition
722 // should yield `1` if it evaluated to true, and `0` otherwise.
723 // We force the materialization of comparisons for different combinations of
724 // inputs and check the results.
725
726 int lhs[] = {1, 2, -1, 2, 0xabc};
727 int rhs[] = {2, 1, 2, -1, 0xabc};
728
729 for (size_t i = 0; i < arraysize(lhs); i++) {
730 ArenaPool pool;
731 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100732 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100733
734 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
735 graph->AddBlock(entry_block);
736 graph->SetEntryBlock(entry_block);
737 entry_block->AddInstruction(new (&allocator) HGoto());
738 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
739 graph->AddBlock(code_block);
740 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
741 graph->AddBlock(exit_block);
742 exit_block->AddInstruction(new (&allocator) HExit());
743
744 entry_block->AddSuccessor(code_block);
745 code_block->AddSuccessor(exit_block);
746 graph->SetExitBlock(exit_block);
747
David Brazdil8d5b8b22015-03-24 10:51:52 +0000748 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
749 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
750 HLessThan cmp_lt(cst_lhs, cst_rhs);
Alexandre Rames92730742014-10-01 12:55:56 +0100751 code_block->AddInstruction(&cmp_lt);
752 HReturn ret(&cmp_lt);
753 code_block->AddInstruction(&ret);
754
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800755 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100756 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800757 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100758 block->InsertInstructionBefore(move, block->GetLastInstruction());
759 };
760
Phil Wang751beff2015-08-28 15:17:15 +0800761 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]);
Alexandre Rames92730742014-10-01 12:55:56 +0100762 }
763}
764
Phil Wang751beff2015-08-28 15:17:15 +0800765TEST_P(CodegenTest, MaterializedCondition2) {
Alexandre Rames92730742014-10-01 12:55:56 +0100766 // Check that HIf correctly interprets a materialized condition.
767 // We force the materialization of comparisons for different combinations of
768 // inputs. An HIf takes the materialized combination as input and returns a
769 // value that we verify.
770
771 int lhs[] = {1, 2, -1, 2, 0xabc};
772 int rhs[] = {2, 1, 2, -1, 0xabc};
773
774
775 for (size_t i = 0; i < arraysize(lhs); i++) {
776 ArenaPool pool;
777 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100778 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100779
780 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
781 graph->AddBlock(entry_block);
782 graph->SetEntryBlock(entry_block);
783 entry_block->AddInstruction(new (&allocator) HGoto());
784
785 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
786 graph->AddBlock(if_block);
787 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
788 graph->AddBlock(if_true_block);
789 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
790 graph->AddBlock(if_false_block);
791 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
792 graph->AddBlock(exit_block);
793 exit_block->AddInstruction(new (&allocator) HExit());
794
795 graph->SetEntryBlock(entry_block);
796 entry_block->AddSuccessor(if_block);
797 if_block->AddSuccessor(if_true_block);
798 if_block->AddSuccessor(if_false_block);
799 if_true_block->AddSuccessor(exit_block);
800 if_false_block->AddSuccessor(exit_block);
801 graph->SetExitBlock(exit_block);
802
David Brazdil8d5b8b22015-03-24 10:51:52 +0000803 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
804 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
805 HLessThan cmp_lt(cst_lhs, cst_rhs);
Alexandre Rames92730742014-10-01 12:55:56 +0100806 if_block->AddInstruction(&cmp_lt);
807 // We insert a temporary to separate the HIf from the HLessThan and force
808 // the materialization of the condition.
809 HTemporary force_materialization(0);
810 if_block->AddInstruction(&force_materialization);
811 HIf if_lt(&cmp_lt);
812 if_block->AddInstruction(&if_lt);
813
David Brazdil8d5b8b22015-03-24 10:51:52 +0000814 HIntConstant* cst_lt = graph->GetIntConstant(1);
815 HReturn ret_lt(cst_lt);
Alexandre Rames92730742014-10-01 12:55:56 +0100816 if_true_block->AddInstruction(&ret_lt);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000817 HIntConstant* cst_ge = graph->GetIntConstant(0);
818 HReturn ret_ge(cst_ge);
Alexandre Rames92730742014-10-01 12:55:56 +0100819 if_false_block->AddInstruction(&ret_ge);
820
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800821 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100822 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800823 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100824 block->InsertInstructionBefore(move, block->GetLastInstruction());
825 };
826
Phil Wang751beff2015-08-28 15:17:15 +0800827 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]);
Alexandre Rames92730742014-10-01 12:55:56 +0100828 }
829}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100830
Phil Wang751beff2015-08-28 15:17:15 +0800831TEST_P(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000832 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
833 Instruction::CONST_4 | 4 << 12 | 0 << 8,
834 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
835 Instruction::RETURN);
836
Phil Wang751beff2015-08-28 15:17:15 +0800837 TestCode(GetParam(), data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000838}
839
Phil Wang751beff2015-08-28 15:17:15 +0800840TEST_P(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000841 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
842 Instruction::CONST_4 | 4 << 12 | 0,
843 Instruction::CONST_4 | 2 << 12 | 1 << 8,
844 Instruction::DIV_INT_2ADDR | 1 << 12,
845 Instruction::RETURN);
846
Phil Wang751beff2015-08-28 15:17:15 +0800847 TestCode(GetParam(), data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000848}
849
Aart Bike9f37602015-10-09 11:15:55 -0700850// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800851static void TestComparison(IfCondition condition,
852 int64_t i,
853 int64_t j,
854 Primitive::Type type,
855 const InstructionSet target_isa) {
Aart Bike9f37602015-10-09 11:15:55 -0700856 ArenaPool pool;
857 ArenaAllocator allocator(&pool);
858 HGraph* graph = CreateGraph(&allocator);
859
860 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
861 graph->AddBlock(entry_block);
862 graph->SetEntryBlock(entry_block);
863 entry_block->AddInstruction(new (&allocator) HGoto());
864
865 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
866 graph->AddBlock(block);
867
868 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
869 graph->AddBlock(exit_block);
870 graph->SetExitBlock(exit_block);
871 exit_block->AddInstruction(new (&allocator) HExit());
872
873 entry_block->AddSuccessor(block);
874 block->AddSuccessor(exit_block);
875
876 HInstruction* op1;
877 HInstruction* op2;
878 if (type == Primitive::kPrimInt) {
879 op1 = graph->GetIntConstant(i);
880 op2 = graph->GetIntConstant(j);
881 } else {
882 DCHECK_EQ(type, Primitive::kPrimLong);
883 op1 = graph->GetLongConstant(i);
884 op2 = graph->GetLongConstant(j);
885 }
886
887 HInstruction* comparison = nullptr;
888 bool expected_result = false;
889 const uint64_t x = i;
890 const uint64_t y = j;
891 switch (condition) {
892 case kCondEQ:
893 comparison = new (&allocator) HEqual(op1, op2);
894 expected_result = (i == j);
895 break;
896 case kCondNE:
897 comparison = new (&allocator) HNotEqual(op1, op2);
898 expected_result = (i != j);
899 break;
900 case kCondLT:
901 comparison = new (&allocator) HLessThan(op1, op2);
902 expected_result = (i < j);
903 break;
904 case kCondLE:
905 comparison = new (&allocator) HLessThanOrEqual(op1, op2);
906 expected_result = (i <= j);
907 break;
908 case kCondGT:
909 comparison = new (&allocator) HGreaterThan(op1, op2);
910 expected_result = (i > j);
911 break;
912 case kCondGE:
913 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
914 expected_result = (i >= j);
915 break;
916 case kCondB:
917 comparison = new (&allocator) HBelow(op1, op2);
918 expected_result = (x < y);
919 break;
920 case kCondBE:
921 comparison = new (&allocator) HBelowOrEqual(op1, op2);
922 expected_result = (x <= y);
923 break;
924 case kCondA:
925 comparison = new (&allocator) HAbove(op1, op2);
926 expected_result = (x > y);
927 break;
928 case kCondAE:
929 comparison = new (&allocator) HAboveOrEqual(op1, op2);
930 expected_result = (x >= y);
931 break;
932 }
933 block->AddInstruction(comparison);
934 block->AddInstruction(new (&allocator) HReturn(comparison));
935
936 auto hook_before_codegen = [](HGraph*) {
937 };
Phil Wang751beff2015-08-28 15:17:15 +0800938 RunCodeOptimized(target_isa, graph, hook_before_codegen, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700939}
940
Phil Wang751beff2015-08-28 15:17:15 +0800941TEST_P(CodegenTest, ComparisonsInt) {
942 const InstructionSet target_isa = GetParam();
Aart Bike9f37602015-10-09 11:15:55 -0700943 for (int64_t i = -1; i <= 1; i++) {
944 for (int64_t j = -1; j <= 1; j++) {
Phil Wang751beff2015-08-28 15:17:15 +0800945 TestComparison(kCondEQ, i, j, Primitive::kPrimInt, target_isa);
946 TestComparison(kCondNE, i, j, Primitive::kPrimInt, target_isa);
947 TestComparison(kCondLT, i, j, Primitive::kPrimInt, target_isa);
948 TestComparison(kCondLE, i, j, Primitive::kPrimInt, target_isa);
949 TestComparison(kCondGT, i, j, Primitive::kPrimInt, target_isa);
950 TestComparison(kCondGE, i, j, Primitive::kPrimInt, target_isa);
951 TestComparison(kCondB, i, j, Primitive::kPrimInt, target_isa);
952 TestComparison(kCondBE, i, j, Primitive::kPrimInt, target_isa);
953 TestComparison(kCondA, i, j, Primitive::kPrimInt, target_isa);
954 TestComparison(kCondAE, i, j, Primitive::kPrimInt, target_isa);
Aart Bike9f37602015-10-09 11:15:55 -0700955 }
956 }
957}
958
Phil Wang751beff2015-08-28 15:17:15 +0800959TEST_P(CodegenTest, ComparisonsLong) {
Aart Bike9f37602015-10-09 11:15:55 -0700960 // TODO: make MIPS work for long
961 if (kRuntimeISA == kMips || kRuntimeISA == kMips64) {
962 return;
963 }
964
Phil Wang751beff2015-08-28 15:17:15 +0800965 const InstructionSet target_isa = GetParam();
966 if (target_isa == kMips || target_isa == kMips64) {
967 return;
968 }
969
Aart Bike9f37602015-10-09 11:15:55 -0700970 for (int64_t i = -1; i <= 1; i++) {
971 for (int64_t j = -1; j <= 1; j++) {
Phil Wang751beff2015-08-28 15:17:15 +0800972 TestComparison(kCondEQ, i, j, Primitive::kPrimLong, target_isa);
973 TestComparison(kCondNE, i, j, Primitive::kPrimLong, target_isa);
974 TestComparison(kCondLT, i, j, Primitive::kPrimLong, target_isa);
975 TestComparison(kCondLE, i, j, Primitive::kPrimLong, target_isa);
976 TestComparison(kCondGT, i, j, Primitive::kPrimLong, target_isa);
977 TestComparison(kCondGE, i, j, Primitive::kPrimLong, target_isa);
978 TestComparison(kCondB, i, j, Primitive::kPrimLong, target_isa);
979 TestComparison(kCondBE, i, j, Primitive::kPrimLong, target_isa);
980 TestComparison(kCondA, i, j, Primitive::kPrimLong, target_isa);
981 TestComparison(kCondAE, i, j, Primitive::kPrimLong, target_isa);
Aart Bike9f37602015-10-09 11:15:55 -0700982 }
983 }
984}
985
Phil Wang751beff2015-08-28 15:17:15 +0800986static ::std::vector<InstructionSet> GetTargetISAs() {
987 ::std::vector<InstructionSet> v;
988 // Add all ISAs that are executable on hardware or on simulator.
989 const ::std::vector<InstructionSet> executable_isa_candidates = {
990 kArm,
991 kArm64,
992 kThumb2,
993 kX86,
994 kX86_64,
995 kMips,
996 kMips64
997 };
998
999 for (auto target_isa : executable_isa_candidates) {
1000 if (CanExecute(target_isa)) {
1001 v.push_back(target_isa);
1002 }
1003 }
1004
1005 return v;
1006}
1007
1008INSTANTIATE_TEST_CASE_P(MultipleTargets,
1009 CodegenTest,
1010 ::testing::ValuesIn(GetTargetISAs()));
1011
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001012} // namespace art