blob: 763d6da6f5070731c22f6301866c3def7ca31e8f [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>
Anton Kirilov3a2e78e2017-01-06 13:33:42 +000018#include <memory>
Nicolas Geoffray360231a2014-10-08 21:07:48 +010019
Ian Rogersd582fa42014-11-05 23:46:43 -080020#include "arch/instruction_set.h"
Calin Juravle34166012014-12-19 17:22:29 +000021#include "arch/arm/instruction_set_features_arm.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010022#include "arch/arm/registers_arm.h"
Serban Constantinescu579885a2015-02-22 20:51:33 +000023#include "arch/arm64/instruction_set_features_arm64.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020024#include "arch/mips/instruction_set_features_mips.h"
25#include "arch/mips/registers_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070026#include "arch/mips64/instruction_set_features_mips64.h"
27#include "arch/mips64/registers_mips64.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040028#include "arch/x86/instruction_set_features_x86.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010029#include "arch/x86/registers_x86.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040030#include "arch/x86_64/instruction_set_features_x86_64.h"
Alexandre Rames92730742014-10-01 12:55:56 +010031#include "base/macros.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032#include "builder.h"
Phil Wang751beff2015-08-28 15:17:15 +080033#include "code_simulator_container.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000034#include "common_compiler_test.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000035#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000037#include "driver/compiler_options.h"
David Brazdil58282f42016-01-14 12:45:10 +000038#include "graph_checker.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000039#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000040#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010041#include "prepare_for_register_allocation.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070042#include "register_allocator_linear_scan.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010043#include "ssa_liveness_analysis.h"
Roland Levillain55dcfb52014-10-24 18:09:09 +010044#include "utils.h"
Scott Wakelingfe885462016-09-22 10:24:38 +010045#include "utils/arm/assembler_arm_vixl.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010046#include "utils/arm/managed_register_arm.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020047#include "utils/mips/managed_register_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070048#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010049#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000050
Colin Crossa75b01a2016-08-18 13:45:24 -070051#ifdef ART_ENABLE_CODEGEN_arm
52#include "code_generator_arm.h"
Scott Wakelingfe885462016-09-22 10:24:38 +010053#include "code_generator_arm_vixl.h"
Colin Crossa75b01a2016-08-18 13:45:24 -070054#endif
55
56#ifdef ART_ENABLE_CODEGEN_arm64
57#include "code_generator_arm64.h"
58#endif
59
60#ifdef ART_ENABLE_CODEGEN_x86
61#include "code_generator_x86.h"
62#endif
63
64#ifdef ART_ENABLE_CODEGEN_x86_64
65#include "code_generator_x86_64.h"
66#endif
67
68#ifdef ART_ENABLE_CODEGEN_mips
69#include "code_generator_mips.h"
70#endif
71
72#ifdef ART_ENABLE_CODEGEN_mips64
73#include "code_generator_mips64.h"
74#endif
75
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000076#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000077
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000078namespace art {
79
Scott Wakeling2c76e062016-08-31 09:48:54 +010080typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
81
82class CodegenTargetConfig {
83 public:
84 CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
85 : isa_(isa), create_codegen_(create_codegen) {
86 }
87 InstructionSet GetInstructionSet() const { return isa_; }
88 CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
89 return create_codegen_(graph, compiler_options);
90 }
91
92 private:
93 CodegenTargetConfig() {}
94 InstructionSet isa_;
95 CreateCodegenFn create_codegen_;
96};
97
Colin Crossa75b01a2016-08-18 13:45:24 -070098#ifdef ART_ENABLE_CODEGEN_arm
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000099// Provide our own codegen, that ensures the C calling conventions
100// are preserved. Currently, ART and C do not match as R4 is caller-save
101// in ART, and callee-save in C. Alternatively, we could use or write
102// the stub that saves and restores all registers, but it is easier
103// to just overwrite the code generator.
104class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
105 public:
106 TestCodeGeneratorARM(HGraph* graph,
107 const ArmInstructionSetFeatures& isa_features,
108 const CompilerOptions& compiler_options)
109 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100110 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
111 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000112 }
113
David Brazdil58282f42016-01-14 12:45:10 +0000114 void SetupBlockedRegisters() const OVERRIDE {
115 arm::CodeGeneratorARM::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100116 blocked_core_registers_[arm::R4] = true;
117 blocked_core_registers_[arm::R6] = false;
118 blocked_core_registers_[arm::R7] = false;
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100119 }
120};
Scott Wakelingfe885462016-09-22 10:24:38 +0100121
122// A way to test the VIXL32-based code generator on ARM. This will replace
123// TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one.
124class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
125 public:
126 TestCodeGeneratorARMVIXL(HGraph* graph,
127 const ArmInstructionSetFeatures& isa_features,
128 const CompilerOptions& compiler_options)
129 : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
130 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
131 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
132 }
133
134 void SetupBlockedRegisters() const OVERRIDE {
135 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
136 blocked_core_registers_[arm::R4] = true;
137 blocked_core_registers_[arm::R6] = false;
138 blocked_core_registers_[arm::R7] = false;
Scott Wakelingfe885462016-09-22 10:24:38 +0100139 }
140};
Colin Crossa75b01a2016-08-18 13:45:24 -0700141#endif
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100142
Colin Crossa75b01a2016-08-18 13:45:24 -0700143#ifdef ART_ENABLE_CODEGEN_x86
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100144class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
145 public:
146 TestCodeGeneratorX86(HGraph* graph,
147 const X86InstructionSetFeatures& isa_features,
148 const CompilerOptions& compiler_options)
149 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
150 // Save edi, we need it for getting enough registers for long multiplication.
151 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
152 }
153
David Brazdil58282f42016-01-14 12:45:10 +0000154 void SetupBlockedRegisters() const OVERRIDE {
155 x86::CodeGeneratorX86::SetupBlockedRegisters();
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100156 // ebx is a callee-save register in C, but caller-save for ART.
157 blocked_core_registers_[x86::EBX] = true;
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100158
159 // Make edi available.
160 blocked_core_registers_[x86::EDI] = false;
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000161 }
162};
Colin Crossa75b01a2016-08-18 13:45:24 -0700163#endif
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000164
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000165class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000166 public:
Ian Rogersd582fa42014-11-05 23:46:43 -0800167 InternalCodeAllocator() : size_(0) { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000168
169 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000170 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000171 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000172 return memory_.get();
173 }
174
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000175 size_t GetSize() const { return size_; }
176 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000177
178 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000179 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -0700180 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000181
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000182 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000183};
184
Phil Wang751beff2015-08-28 15:17:15 +0800185static bool CanExecuteOnHardware(InstructionSet target_isa) {
186 return (target_isa == kRuntimeISA)
187 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
188 || (kRuntimeISA == kArm && target_isa == kThumb2);
189}
190
191static bool CanExecute(InstructionSet target_isa) {
192 CodeSimulatorContainer simulator(target_isa);
193 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
194}
195
196template <typename Expected>
197static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
198
199template <>
200bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
201 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
202 return simulator->GetCReturnBool();
203}
204
205template <>
206int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
207 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
208 return simulator->GetCReturnInt32();
209}
210
211template <>
212int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
213 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
214 return simulator->GetCReturnInt64();
215}
216
217template <typename Expected>
218static void VerifyGeneratedCode(InstructionSet target_isa,
219 Expected (*f)(),
220 bool has_result,
221 Expected expected) {
222 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
223
224 // Verify on simulator.
225 CodeSimulatorContainer simulator(target_isa);
226 if (simulator.CanSimulate()) {
227 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
228 if (has_result) {
229 ASSERT_EQ(expected, result);
230 }
231 }
232
233 // Verify on hardware.
234 if (CanExecuteOnHardware(target_isa)) {
235 Expected result = f();
236 if (has_result) {
237 ASSERT_EQ(expected, result);
238 }
239 }
240}
241
Roland Levillain55dcfb52014-10-24 18:09:09 +0100242template <typename Expected>
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100243static void Run(const InternalCodeAllocator& allocator,
244 const CodeGenerator& codegen,
245 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100246 Expected expected) {
Phil Wang751beff2015-08-28 15:17:15 +0800247 InstructionSet target_isa = codegen.GetInstructionSet();
248
Roland Levillain55dcfb52014-10-24 18:09:09 +0100249 typedef Expected (*fptr)();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100250 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -0700251 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Phil Wang751beff2015-08-28 15:17:15 +0800252 if (target_isa == kThumb2) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100253 // For thumb we need the bottom bit set.
254 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
255 }
Phil Wang751beff2015-08-28 15:17:15 +0800256 VerifyGeneratedCode(target_isa, f, has_result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100257}
258
Scott Wakeling2c76e062016-08-31 09:48:54 +0100259static void ValidateGraph(HGraph* graph) {
David Brazdilbadd8262016-02-02 16:28:56 +0000260 GraphChecker graph_checker(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000261 graph_checker.Run();
David Brazdilbadd8262016-02-02 16:28:56 +0000262 if (!graph_checker.IsValid()) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800263 for (const auto& error : graph_checker.GetErrors()) {
David Brazdilbadd8262016-02-02 16:28:56 +0000264 std::cout << error << std::endl;
265 }
266 }
David Brazdil58282f42016-01-14 12:45:10 +0000267 ASSERT_TRUE(graph_checker.IsValid());
Scott Wakeling2c76e062016-08-31 09:48:54 +0100268}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100269
Scott Wakeling2c76e062016-08-31 09:48:54 +0100270template <typename Expected>
271static void RunCodeNoCheck(CodeGenerator* codegen,
272 HGraph* graph,
Andreas Gampeca620d72016-11-08 08:09:33 -0800273 const std::function<void(HGraph*)>& hook_before_codegen,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100274 bool has_result,
275 Expected expected) {
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100276 SsaLivenessAnalysis liveness(graph, codegen);
David Brazdil58282f42016-01-14 12:45:10 +0000277 PrepareForRegisterAllocation(graph).Run();
278 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700279 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100280 hook_before_codegen(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100281 InternalCodeAllocator allocator;
David Brazdil58282f42016-01-14 12:45:10 +0000282 codegen->Compile(&allocator);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100283 Run(allocator, *codegen, has_result, expected);
284}
285
Roland Levillain55dcfb52014-10-24 18:09:09 +0100286template <typename Expected>
Scott Wakeling2c76e062016-08-31 09:48:54 +0100287static void RunCode(CodeGenerator* codegen,
288 HGraph* graph,
289 std::function<void(HGraph*)> hook_before_codegen,
290 bool has_result,
291 Expected expected) {
292 ValidateGraph(graph);
293 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
294}
295
296template <typename Expected>
297static void RunCode(CodegenTargetConfig target_config,
David Brazdil58282f42016-01-14 12:45:10 +0000298 HGraph* graph,
299 std::function<void(HGraph*)> hook_before_codegen,
300 bool has_result,
301 Expected expected) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000302 CompilerOptions compiler_options;
Anton Kirilov3a2e78e2017-01-06 13:33:42 +0000303 std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options));
304 RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100305}
306
Scott Wakeling2c76e062016-08-31 09:48:54 +0100307#ifdef ART_ENABLE_CODEGEN_arm
308CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
309 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
310 ArmInstructionSetFeatures::FromCppDefines());
311 return new (graph->GetArena()) TestCodeGeneratorARM(graph,
312 *features_arm.get(),
313 compiler_options);
314}
Scott Wakelingfe885462016-09-22 10:24:38 +0100315
316CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
317 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
318 ArmInstructionSetFeatures::FromCppDefines());
319 return new (graph->GetArena())
320 TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
321}
Scott Wakeling2c76e062016-08-31 09:48:54 +0100322#endif
323
324#ifdef ART_ENABLE_CODEGEN_arm64
325CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
326 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
327 Arm64InstructionSetFeatures::FromCppDefines());
328 return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
329 *features_arm64.get(),
330 compiler_options);
331}
332#endif
333
334#ifdef ART_ENABLE_CODEGEN_x86
335CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
336 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
337 X86InstructionSetFeatures::FromCppDefines());
338 return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
339}
340#endif
341
342#ifdef ART_ENABLE_CODEGEN_x86_64
343CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
344 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
345 X86_64InstructionSetFeatures::FromCppDefines());
346 return new (graph->GetArena())
347 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
348}
349#endif
350
351#ifdef ART_ENABLE_CODEGEN_mips
352CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
353 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
354 MipsInstructionSetFeatures::FromCppDefines());
355 return new (graph->GetArena())
356 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
357}
358#endif
359
360#ifdef ART_ENABLE_CODEGEN_mips64
361CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
362 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
363 Mips64InstructionSetFeatures::FromCppDefines());
364 return new (graph->GetArena())
365 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
366}
367#endif
368
369// Return all combinations of ISA and code generator that are executable on
370// hardware, or on simulator, and that we'd like to test.
371static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
372 ::std::vector<CodegenTargetConfig> v;
373 ::std::vector<CodegenTargetConfig> test_config_candidates = {
374#ifdef ART_ENABLE_CODEGEN_arm
375 CodegenTargetConfig(kArm, create_codegen_arm),
376 CodegenTargetConfig(kThumb2, create_codegen_arm),
Scott Wakelingfe885462016-09-22 10:24:38 +0100377 CodegenTargetConfig(kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +0100378#endif
379#ifdef ART_ENABLE_CODEGEN_arm64
380 CodegenTargetConfig(kArm64, create_codegen_arm64),
381#endif
382#ifdef ART_ENABLE_CODEGEN_x86
383 CodegenTargetConfig(kX86, create_codegen_x86),
384#endif
385#ifdef ART_ENABLE_CODEGEN_x86_64
386 CodegenTargetConfig(kX86_64, create_codegen_x86_64),
387#endif
388#ifdef ART_ENABLE_CODEGEN_mips
389 CodegenTargetConfig(kMips, create_codegen_mips),
390#endif
391#ifdef ART_ENABLE_CODEGEN_mips64
392 CodegenTargetConfig(kMips64, create_codegen_mips64)
393#endif
David Brazdil58282f42016-01-14 12:45:10 +0000394 };
395
Scott Wakeling2c76e062016-08-31 09:48:54 +0100396 for (auto test_config : test_config_candidates) {
397 if (CanExecute(test_config.GetInstructionSet())) {
398 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +0000399 }
400 }
401
402 return v;
403}
404
405static void TestCode(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800406 bool has_result = false,
407 int32_t expected = 0) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100408 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000409 ArenaPool pool;
410 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000411 HGraph* graph = CreateCFG(&arena, data);
David Brazdil58282f42016-01-14 12:45:10 +0000412 // Remove suspend checks, they cannot be executed in this context.
413 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100414 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000415 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100416}
417
David Brazdil58282f42016-01-14 12:45:10 +0000418static void TestCodeLong(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +0800419 bool has_result,
420 int64_t expected) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100421 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000422 ArenaPool pool;
423 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000424 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
David Brazdil58282f42016-01-14 12:45:10 +0000425 // Remove suspend checks, they cannot be executed in this context.
426 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100427 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000428 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100429}
430
David Brazdil58282f42016-01-14 12:45:10 +0000431class CodegenTest : public CommonCompilerTest {};
Phil Wang751beff2015-08-28 15:17:15 +0800432
David Brazdil58282f42016-01-14 12:45:10 +0000433TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000434 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000435 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000436}
437
David Brazdil58282f42016-01-14 12:45:10 +0000438TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000439 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000440 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000441 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000442
David Brazdil58282f42016-01-14 12:45:10 +0000443 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000444}
445
David Brazdil58282f42016-01-14 12:45:10 +0000446TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000447 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000448 Instruction::GOTO | 0x100,
449 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000450 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000451
David Brazdil58282f42016-01-14 12:45:10 +0000452 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000453}
454
David Brazdil58282f42016-01-14 12:45:10 +0000455TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000456 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000457 Instruction::GOTO | 0x200,
458 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000459 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000460
David Brazdil58282f42016-01-14 12:45:10 +0000461 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000462
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000463 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000464 Instruction::GOTO_16, 3,
465 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000466 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000467
David Brazdil58282f42016-01-14 12:45:10 +0000468 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000469
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000470 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000471 Instruction::GOTO_32, 4, 0,
472 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000473 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000474
David Brazdil58282f42016-01-14 12:45:10 +0000475 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000476}
477
David Brazdil58282f42016-01-14 12:45:10 +0000478TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000479 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000480 Instruction::RETURN_VOID,
481 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000482 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000483
David Brazdil58282f42016-01-14 12:45:10 +0000484 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000485}
486
David Brazdil58282f42016-01-14 12:45:10 +0000487TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000488 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
489 Instruction::CONST_4 | 0 | 0,
490 Instruction::IF_EQ, 3,
491 Instruction::GOTO | 0x100,
492 Instruction::RETURN_VOID);
493
David Brazdil58282f42016-01-14 12:45:10 +0000494 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000495}
496
David Brazdil58282f42016-01-14 12:45:10 +0000497TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000498 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
499 Instruction::CONST_4 | 0 | 0,
500 Instruction::RETURN_VOID);
501
David Brazdil58282f42016-01-14 12:45:10 +0000502 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000503}
504
David Brazdil58282f42016-01-14 12:45:10 +0000505TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000506 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
507 Instruction::CONST_4 | 0 | 0,
508 Instruction::RETURN | 0);
509
David Brazdil58282f42016-01-14 12:45:10 +0000510 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000511}
512
David Brazdil58282f42016-01-14 12:45:10 +0000513TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000514 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
515 Instruction::CONST_4 | 0 | 0,
516 Instruction::CONST_4 | 0 | 1 << 8,
517 Instruction::RETURN | 1 << 8);
518
David Brazdil58282f42016-01-14 12:45:10 +0000519 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000520}
521
David Brazdil58282f42016-01-14 12:45:10 +0000522TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000523 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
524 Instruction::CONST_4 | 0 | 0,
525 Instruction::CONST_4 | 1 << 8 | 1 << 12,
526 Instruction::RETURN | 1 << 8);
527
David Brazdil58282f42016-01-14 12:45:10 +0000528 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000529}
530
David Brazdil58282f42016-01-14 12:45:10 +0000531TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000532 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
533 Instruction::CONST_4 | 0 | 0,
534 Instruction::CONST_4 | 1 << 8 | 1 << 12,
535 Instruction::IF_EQ, 3,
536 Instruction::RETURN | 0 << 8,
537 Instruction::RETURN | 1 << 8);
538
David Brazdil58282f42016-01-14 12:45:10 +0000539 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000540}
541
David Brazdil58282f42016-01-14 12:45:10 +0000542TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000543 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
544 Instruction::CONST_4 | 0 | 0,
545 Instruction::CONST_4 | 1 << 8 | 1 << 12,
546 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
547 Instruction::RETURN | 0 << 8,
548 Instruction::RETURN | 1 << 8);
549
David Brazdil58282f42016-01-14 12:45:10 +0000550 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000551}
552
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100553// Exercise bit-wise (one's complement) not-int instruction.
554#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000555TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100556 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100557 const uint16_t input_lo = Low16Bits(input); \
558 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100559 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
560 Instruction::CONST | 0 << 8, input_lo, input_hi, \
561 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
562 Instruction::RETURN | 1 << 8); \
563 \
David Brazdil58282f42016-01-14 12:45:10 +0000564 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100565}
566
567NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
568NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
569NOT_INT_TEST(ReturnNotInt0, 0, -1)
570NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100571NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
572NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
573NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
574NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100575
576#undef NOT_INT_TEST
577
Roland Levillain55dcfb52014-10-24 18:09:09 +0100578// Exercise bit-wise (one's complement) not-long instruction.
579#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000580TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100581 const int64_t input = INPUT; \
582 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
583 const uint16_t word1 = High16Bits(Low32Bits(input)); \
584 const uint16_t word2 = Low16Bits(High32Bits(input)); \
585 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
586 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
587 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
588 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
589 Instruction::RETURN_WIDE | 2 << 8); \
590 \
David Brazdil58282f42016-01-14 12:45:10 +0000591 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100592}
593
594NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
595NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
596NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
597NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
598
599NOT_LONG_TEST(ReturnNotLongINT32_MIN,
600 INT64_C(-2147483648),
601 INT64_C(2147483647)) // (2^31) - 1
602NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
603 INT64_C(-2147483647),
604 INT64_C(2147483646)) // (2^31) - 2
605NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
606 INT64_C(2147483646),
607 INT64_C(-2147483647)) // -(2^31) - 1
608NOT_LONG_TEST(ReturnNotLongINT32_MAX,
609 INT64_C(2147483647),
610 INT64_C(-2147483648)) // -(2^31)
611
612// Note that the C++ compiler won't accept
613// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
614// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
615NOT_LONG_TEST(ReturnNotINT64_MIN,
616 INT64_C(-9223372036854775807)-1,
617 INT64_C(9223372036854775807)); // (2^63) - 1
618NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
619 INT64_C(-9223372036854775807),
620 INT64_C(9223372036854775806)); // (2^63) - 2
621NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
622 INT64_C(9223372036854775806),
623 INT64_C(-9223372036854775807)); // -(2^63) - 1
624NOT_LONG_TEST(ReturnNotLongINT64_MAX,
625 INT64_C(9223372036854775807),
626 INT64_C(-9223372036854775807)-1); // -(2^63)
627
628#undef NOT_LONG_TEST
629
David Brazdil58282f42016-01-14 12:45:10 +0000630TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000631 const int64_t input = INT64_C(4294967296); // 2^32
632 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
633 const uint16_t word1 = High16Bits(Low32Bits(input));
634 const uint16_t word2 = Low16Bits(High32Bits(input));
635 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
636 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
637 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
638 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
639 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
640 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
641 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
642 Instruction::RETURN_WIDE | 2 << 8);
643
David Brazdil58282f42016-01-14 12:45:10 +0000644 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000645}
646
David Brazdil58282f42016-01-14 12:45:10 +0000647TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000648 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
649 Instruction::CONST_4 | 3 << 12 | 0,
650 Instruction::CONST_4 | 4 << 12 | 1 << 8,
651 Instruction::ADD_INT, 1 << 8 | 0,
652 Instruction::RETURN);
653
David Brazdil58282f42016-01-14 12:45:10 +0000654 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000655}
656
David Brazdil58282f42016-01-14 12:45:10 +0000657TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000658 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
659 Instruction::CONST_4 | 3 << 12 | 0,
660 Instruction::CONST_4 | 4 << 12 | 1 << 8,
661 Instruction::ADD_INT_2ADDR | 1 << 12,
662 Instruction::RETURN);
663
David Brazdil58282f42016-01-14 12:45:10 +0000664 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000665}
666
David Brazdil58282f42016-01-14 12:45:10 +0000667TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000668 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
669 Instruction::CONST_4 | 4 << 12 | 0 << 8,
670 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
671 Instruction::RETURN);
672
David Brazdil58282f42016-01-14 12:45:10 +0000673 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000674}
675
David Brazdil58282f42016-01-14 12:45:10 +0000676TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000677 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
678 Instruction::CONST_4 | 4 << 12 | 0 << 8,
679 Instruction::ADD_INT_LIT16, 3,
680 Instruction::RETURN);
681
David Brazdil58282f42016-01-14 12:45:10 +0000682 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000683}
684
David Brazdil58282f42016-01-14 12:45:10 +0000685TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100686 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
687 Instruction::CONST_4 | 3 << 12 | 0,
688 Instruction::CONST_4 | 4 << 12 | 1 << 8,
689 Instruction::MUL_INT, 1 << 8 | 0,
690 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100691
David Brazdil58282f42016-01-14 12:45:10 +0000692 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100693}
694
David Brazdil58282f42016-01-14 12:45:10 +0000695TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100696 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
697 Instruction::CONST_4 | 3 << 12 | 0,
698 Instruction::CONST_4 | 4 << 12 | 1 << 8,
699 Instruction::MUL_INT_2ADDR | 1 << 12,
700 Instruction::RETURN);
701
David Brazdil58282f42016-01-14 12:45:10 +0000702 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100703}
704
David Brazdil58282f42016-01-14 12:45:10 +0000705TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100706 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000707 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
708 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100709 Instruction::MUL_LONG, 2 << 8 | 0,
710 Instruction::RETURN_WIDE);
711
David Brazdil58282f42016-01-14 12:45:10 +0000712 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100713}
714
David Brazdil58282f42016-01-14 12:45:10 +0000715TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100716 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000717 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
718 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100719 Instruction::MUL_LONG_2ADDR | 2 << 12,
720 Instruction::RETURN_WIDE);
721
David Brazdil58282f42016-01-14 12:45:10 +0000722 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100723}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100724
David Brazdil58282f42016-01-14 12:45:10 +0000725TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100726 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
727 Instruction::CONST_4 | 4 << 12 | 0 << 8,
728 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
729 Instruction::RETURN);
730
David Brazdil58282f42016-01-14 12:45:10 +0000731 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100732}
733
David Brazdil58282f42016-01-14 12:45:10 +0000734TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100735 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
736 Instruction::CONST_4 | 4 << 12 | 0 << 8,
737 Instruction::MUL_INT_LIT16, 3,
738 Instruction::RETURN);
739
David Brazdil58282f42016-01-14 12:45:10 +0000740 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100741}
742
David Brazdil58282f42016-01-14 12:45:10 +0000743TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100744 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Alexandre Rames92730742014-10-01 12:55:56 +0100745 ArenaPool pool;
746 ArenaAllocator allocator(&pool);
David Brazdil58282f42016-01-14 12:45:10 +0000747
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100748 HGraph* graph = CreateGraph(&allocator);
David Brazdilbadd8262016-02-02 16:28:56 +0000749
David Brazdil58282f42016-01-14 12:45:10 +0000750 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
751 graph->AddBlock(entry);
752 graph->SetEntryBlock(entry);
753 entry->AddInstruction(new (&allocator) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100754
David Brazdil58282f42016-01-14 12:45:10 +0000755 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
756 graph->AddBlock(first_block);
757 entry->AddSuccessor(first_block);
758 HIntConstant* constant0 = graph->GetIntConstant(0);
759 HIntConstant* constant1 = graph->GetIntConstant(1);
760 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
761 first_block->AddInstruction(equal);
762 first_block->AddInstruction(new (&allocator) HIf(equal));
763
764 HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
765 HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100766 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100767 graph->SetExitBlock(exit_block);
768
David Brazdil58282f42016-01-14 12:45:10 +0000769 graph->AddBlock(then_block);
770 graph->AddBlock(else_block);
771 graph->AddBlock(exit_block);
772 first_block->AddSuccessor(then_block);
773 first_block->AddSuccessor(else_block);
774 then_block->AddSuccessor(exit_block);
775 else_block->AddSuccessor(exit_block);
776
777 exit_block->AddInstruction(new (&allocator) HExit());
778 then_block->AddInstruction(new (&allocator) HReturn(constant0));
779 else_block->AddInstruction(new (&allocator) HReturn(constant1));
780
David Brazdilb11b0722016-01-28 16:22:40 +0000781 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000782 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000783 PrepareForRegisterAllocation(graph).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000784 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100785
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800786 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100787 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800788 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100789 block->InsertInstructionBefore(move, block->GetLastInstruction());
790 };
791
Scott Wakeling2c76e062016-08-31 09:48:54 +0100792 RunCode(target_config, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100793 }
794}
795
David Brazdil58282f42016-01-14 12:45:10 +0000796TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100797 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000798 // Check that condition are materialized correctly. A materialized condition
799 // should yield `1` if it evaluated to true, and `0` otherwise.
800 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100801
David Brazdil58282f42016-01-14 12:45:10 +0000802 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100803
David Brazdil58282f42016-01-14 12:45:10 +0000804 int lhs[] = {1, 2, -1, 2, 0xabc};
805 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100806
David Brazdil58282f42016-01-14 12:45:10 +0000807 for (size_t i = 0; i < arraysize(lhs); i++) {
808 ArenaPool pool;
809 ArenaAllocator allocator(&pool);
810 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100811
David Brazdil58282f42016-01-14 12:45:10 +0000812 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
813 graph->AddBlock(entry_block);
814 graph->SetEntryBlock(entry_block);
815 entry_block->AddInstruction(new (&allocator) HGoto());
816 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
817 graph->AddBlock(code_block);
818 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
819 graph->AddBlock(exit_block);
820 exit_block->AddInstruction(new (&allocator) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100821
David Brazdil58282f42016-01-14 12:45:10 +0000822 entry_block->AddSuccessor(code_block);
823 code_block->AddSuccessor(exit_block);
824 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100825
David Brazdil58282f42016-01-14 12:45:10 +0000826 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
827 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
828 HLessThan cmp_lt(cst_lhs, cst_rhs);
829 code_block->AddInstruction(&cmp_lt);
830 HReturn ret(&cmp_lt);
831 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100832
David Brazdilbadd8262016-02-02 16:28:56 +0000833 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000834 auto hook_before_codegen = [](HGraph* graph_in) {
835 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
836 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
837 block->InsertInstructionBefore(move, block->GetLastInstruction());
838 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100839 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000840 }
Alexandre Rames92730742014-10-01 12:55:56 +0100841 }
842}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100843
David Brazdil58282f42016-01-14 12:45:10 +0000844TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100845 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000846 // Check that HIf correctly interprets a materialized condition.
847 // We force the materialization of comparisons for different combinations of
848 // inputs. An HIf takes the materialized combination as input and returns a
849 // value that we verify.
850
851 int lhs[] = {1, 2, -1, 2, 0xabc};
852 int rhs[] = {2, 1, 2, -1, 0xabc};
853
854
855 for (size_t i = 0; i < arraysize(lhs); i++) {
856 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* if_block = new (&allocator) HBasicBlock(graph);
866 graph->AddBlock(if_block);
867 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
868 graph->AddBlock(if_true_block);
869 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
870 graph->AddBlock(if_false_block);
871 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
872 graph->AddBlock(exit_block);
873 exit_block->AddInstruction(new (&allocator) HExit());
874
875 graph->SetEntryBlock(entry_block);
876 entry_block->AddSuccessor(if_block);
877 if_block->AddSuccessor(if_true_block);
878 if_block->AddSuccessor(if_false_block);
879 if_true_block->AddSuccessor(exit_block);
880 if_false_block->AddSuccessor(exit_block);
881 graph->SetExitBlock(exit_block);
882
883 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
884 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
885 HLessThan cmp_lt(cst_lhs, cst_rhs);
886 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000887 // We insert a dummy instruction to separate the HIf from the HLessThan
888 // and force the materialization of the condition.
889 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000890 if_block->AddInstruction(&force_materialization);
891 HIf if_lt(&cmp_lt);
892 if_block->AddInstruction(&if_lt);
893
894 HIntConstant* cst_lt = graph->GetIntConstant(1);
895 HReturn ret_lt(cst_lt);
896 if_true_block->AddInstruction(&ret_lt);
897 HIntConstant* cst_ge = graph->GetIntConstant(0);
898 HReturn ret_ge(cst_ge);
899 if_false_block->AddInstruction(&ret_ge);
900
David Brazdilbadd8262016-02-02 16:28:56 +0000901 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000902 auto hook_before_codegen = [](HGraph* graph_in) {
903 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
904 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
905 block->InsertInstructionBefore(move, block->GetLastInstruction());
906 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100907 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000908 }
909 }
910}
911
912TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000913 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
914 Instruction::CONST_4 | 4 << 12 | 0 << 8,
915 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
916 Instruction::RETURN);
917
David Brazdil58282f42016-01-14 12:45:10 +0000918 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000919}
920
David Brazdil58282f42016-01-14 12:45:10 +0000921TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000922 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
923 Instruction::CONST_4 | 4 << 12 | 0,
924 Instruction::CONST_4 | 2 << 12 | 1 << 8,
925 Instruction::DIV_INT_2ADDR | 1 << 12,
926 Instruction::RETURN);
927
David Brazdil58282f42016-01-14 12:45:10 +0000928 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000929}
930
Aart Bike9f37602015-10-09 11:15:55 -0700931// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800932static void TestComparison(IfCondition condition,
933 int64_t i,
934 int64_t j,
935 Primitive::Type type,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100936 const CodegenTargetConfig target_config) {
Aart Bike9f37602015-10-09 11:15:55 -0700937 ArenaPool pool;
938 ArenaAllocator allocator(&pool);
939 HGraph* graph = CreateGraph(&allocator);
940
941 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
942 graph->AddBlock(entry_block);
943 graph->SetEntryBlock(entry_block);
944 entry_block->AddInstruction(new (&allocator) HGoto());
945
946 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
947 graph->AddBlock(block);
948
949 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
950 graph->AddBlock(exit_block);
951 graph->SetExitBlock(exit_block);
952 exit_block->AddInstruction(new (&allocator) HExit());
953
954 entry_block->AddSuccessor(block);
955 block->AddSuccessor(exit_block);
956
957 HInstruction* op1;
958 HInstruction* op2;
959 if (type == Primitive::kPrimInt) {
960 op1 = graph->GetIntConstant(i);
961 op2 = graph->GetIntConstant(j);
962 } else {
963 DCHECK_EQ(type, Primitive::kPrimLong);
964 op1 = graph->GetLongConstant(i);
965 op2 = graph->GetLongConstant(j);
966 }
967
968 HInstruction* comparison = nullptr;
969 bool expected_result = false;
970 const uint64_t x = i;
971 const uint64_t y = j;
972 switch (condition) {
973 case kCondEQ:
974 comparison = new (&allocator) HEqual(op1, op2);
975 expected_result = (i == j);
976 break;
977 case kCondNE:
978 comparison = new (&allocator) HNotEqual(op1, op2);
979 expected_result = (i != j);
980 break;
981 case kCondLT:
982 comparison = new (&allocator) HLessThan(op1, op2);
983 expected_result = (i < j);
984 break;
985 case kCondLE:
986 comparison = new (&allocator) HLessThanOrEqual(op1, op2);
987 expected_result = (i <= j);
988 break;
989 case kCondGT:
990 comparison = new (&allocator) HGreaterThan(op1, op2);
991 expected_result = (i > j);
992 break;
993 case kCondGE:
994 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
995 expected_result = (i >= j);
996 break;
997 case kCondB:
998 comparison = new (&allocator) HBelow(op1, op2);
999 expected_result = (x < y);
1000 break;
1001 case kCondBE:
1002 comparison = new (&allocator) HBelowOrEqual(op1, op2);
1003 expected_result = (x <= y);
1004 break;
1005 case kCondA:
1006 comparison = new (&allocator) HAbove(op1, op2);
1007 expected_result = (x > y);
1008 break;
1009 case kCondAE:
1010 comparison = new (&allocator) HAboveOrEqual(op1, op2);
1011 expected_result = (x >= y);
1012 break;
1013 }
1014 block->AddInstruction(comparison);
1015 block->AddInstruction(new (&allocator) HReturn(comparison));
1016
David Brazdilbadd8262016-02-02 16:28:56 +00001017 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +01001018 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -07001019}
1020
David Brazdil58282f42016-01-14 12:45:10 +00001021TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001022 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +00001023 for (int64_t i = -1; i <= 1; i++) {
1024 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001025 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1026 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
1027 }
David Brazdil58282f42016-01-14 12:45:10 +00001028 }
Aart Bike9f37602015-10-09 11:15:55 -07001029 }
1030 }
1031}
1032
David Brazdil58282f42016-01-14 12:45:10 +00001033TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001034 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +00001035 for (int64_t i = -1; i <= 1; i++) {
1036 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +01001037 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
1038 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
1039 }
David Brazdil58282f42016-01-14 12:45:10 +00001040 }
Aart Bike9f37602015-10-09 11:15:55 -07001041 }
1042 }
1043}
1044
Artem Serov4593f7d2016-12-29 16:21:49 +00001045#ifdef ART_ENABLE_CODEGEN_arm
1046TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
1047 std::unique_ptr<const ArmInstructionSetFeatures> features(
1048 ArmInstructionSetFeatures::FromCppDefines());
1049 ArenaPool pool;
1050 ArenaAllocator allocator(&pool);
1051 HGraph* graph = CreateGraph(&allocator);
1052 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
1053
1054 codegen.Initialize();
1055
1056 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
1057 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
1058 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
1059 // LDR encoding. So the following code is a regression test for that situation.
1060 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
1061 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), Primitive::kPrimInt, nullptr);
1062 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), Primitive::kPrimInt, nullptr);
1063 codegen.GetMoveResolver()->EmitNativeCode(move);
1064
1065 InternalCodeAllocator code_allocator;
1066 codegen.Finalize(&code_allocator);
1067}
1068#endif
1069
Roland Levillain558dea12017-01-27 19:40:44 +00001070#ifdef ART_ENABLE_CODEGEN_arm64
1071// Regression test for b/34760542.
1072TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
1073 std::unique_ptr<const Arm64InstructionSetFeatures> features(
1074 Arm64InstructionSetFeatures::FromCppDefines());
1075 ArenaPool pool;
1076 ArenaAllocator allocator(&pool);
1077 HGraph* graph = CreateGraph(&allocator);
1078 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
1079
1080 codegen.Initialize();
1081
1082 // The following ParallelMove used to fail this assertion:
1083 //
1084 // Assertion failed (!available->IsEmpty())
1085 //
1086 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable.
1087 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
1088 move->AddMove(Location::DoubleStackSlot(0),
1089 Location::DoubleStackSlot(257),
1090 Primitive::kPrimDouble,
1091 nullptr);
1092 move->AddMove(Location::DoubleStackSlot(257),
1093 Location::DoubleStackSlot(0),
1094 Primitive::kPrimDouble,
1095 nullptr);
1096 codegen.GetMoveResolver()->EmitNativeCode(move);
1097
1098 InternalCodeAllocator code_allocator;
1099 codegen.Finalize(&code_allocator);
1100}
1101#endif
1102
Alexey Frunze58320ce2016-08-30 21:40:46 -07001103#ifdef ART_ENABLE_CODEGEN_mips
1104TEST_F(CodegenTest, MipsClobberRA) {
1105 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
1106 MipsInstructionSetFeatures::FromCppDefines());
1107 if (!CanExecute(kMips) || features_mips->IsR6()) {
1108 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
1109 // should only be generated on non-R6.
1110 return;
1111 }
1112
1113 ArenaPool pool;
1114 ArenaAllocator allocator(&pool);
1115 HGraph* graph = CreateGraph(&allocator);
1116
1117 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
1118 graph->AddBlock(entry_block);
1119 graph->SetEntryBlock(entry_block);
1120 entry_block->AddInstruction(new (&allocator) HGoto());
1121
1122 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
1123 graph->AddBlock(block);
1124
1125 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
1126 graph->AddBlock(exit_block);
1127 graph->SetExitBlock(exit_block);
1128 exit_block->AddInstruction(new (&allocator) HExit());
1129
1130 entry_block->AddSuccessor(block);
1131 block->AddSuccessor(exit_block);
1132
1133 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
1134 // Instead, generate HMipsComputeBaseMethodAddress directly.
1135 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
1136 block->AddInstruction(base);
1137 // HMipsComputeBaseMethodAddress is defined as int, so just make the
1138 // compiled method return it.
1139 block->AddInstruction(new (&allocator) HReturn(base));
1140
1141 graph->BuildDominatorTree();
1142
1143 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
1144 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
1145 // that RA is clobbered and the method entry code should generate a stack frame
1146 // and preserve RA in it. And this is what we're testing here.
1147 codegenMIPS.ClobberRA();
1148 // Without ClobberRA() the code would be:
1149 // nal # Sets RA to point to the jr instruction below
1150 // move v0, ra # and the CPU falls into an infinite loop.
1151 // jr ra
1152 // nop
1153 // The expected code is:
1154 // addiu sp, sp, -16
1155 // sw ra, 12(sp)
1156 // sw a0, 0(sp)
1157 // nal # Sets RA to point to the lw instruction below.
1158 // move v0, ra
1159 // lw ra, 12(sp)
1160 // jr ra
1161 // addiu sp, sp, 16
1162 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
1163}
1164#endif
1165
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001166} // namespace art