blob: 28fc816ac39b7db6512046f59c96d8a0c796b29a [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"
Alexey Frunze4dda3372015-06-01 18:31:49 -070023#include "arch/mips64/instruction_set_features_mips64.h"
24#include "arch/mips64/registers_mips64.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040025#include "arch/x86/instruction_set_features_x86.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010026#include "arch/x86/registers_x86.h"
Mark Mendellfb8d2792015-03-31 22:16:59 -040027#include "arch/x86_64/instruction_set_features_x86_64.h"
Alexandre Rames92730742014-10-01 12:55:56 +010028#include "base/macros.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029#include "builder.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010030#include "code_generator_arm.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010031#include "code_generator_arm64.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070032#include "code_generator_mips64.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010033#include "code_generator_x86.h"
34#include "code_generator_x86_64.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035#include "common_compiler_test.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000036#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000037#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000038#include "driver/compiler_options.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"
42#include "register_allocator.h"
Phil Wangc2e1a5e2015-07-29 15:14:09 +080043#include "simulator/code_simulator.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010044#include "ssa_liveness_analysis.h"
Roland Levillain55dcfb52014-10-24 18:09:09 +010045#include "utils.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010046#include "utils/arm/managed_register_arm.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070047#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010048#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000049
50#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000051
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000052namespace art {
53
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000054// Provide our own codegen, that ensures the C calling conventions
55// are preserved. Currently, ART and C do not match as R4 is caller-save
56// in ART, and callee-save in C. Alternatively, we could use or write
57// the stub that saves and restores all registers, but it is easier
58// to just overwrite the code generator.
59class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
60 public:
61 TestCodeGeneratorARM(HGraph* graph,
62 const ArmInstructionSetFeatures& isa_features,
63 const CompilerOptions& compiler_options)
64 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +010065 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
66 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +000067 }
68
69 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE {
70 arm::CodeGeneratorARM::SetupBlockedRegisters(is_baseline);
Nicolas Geoffray5da21802015-04-20 09:29:18 +010071 blocked_core_registers_[arm::R4] = true;
72 blocked_core_registers_[arm::R6] = false;
73 blocked_core_registers_[arm::R7] = false;
Nicolas Geoffraye6362282015-01-26 13:57:30 +000074 // Makes pair R6-R7 available.
Nicolas Geoffray5da21802015-04-20 09:29:18 +010075 blocked_register_pairs_[arm::R6_R7] = false;
76 }
77};
78
79class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
80 public:
81 TestCodeGeneratorX86(HGraph* graph,
82 const X86InstructionSetFeatures& isa_features,
83 const CompilerOptions& compiler_options)
84 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
85 // Save edi, we need it for getting enough registers for long multiplication.
86 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
87 }
88
89 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE {
90 x86::CodeGeneratorX86::SetupBlockedRegisters(is_baseline);
91 // ebx is a callee-save register in C, but caller-save for ART.
92 blocked_core_registers_[x86::EBX] = true;
93 blocked_register_pairs_[x86::EAX_EBX] = true;
94 blocked_register_pairs_[x86::EDX_EBX] = true;
95 blocked_register_pairs_[x86::ECX_EBX] = true;
96 blocked_register_pairs_[x86::EBX_EDI] = true;
97
98 // Make edi available.
99 blocked_core_registers_[x86::EDI] = false;
100 blocked_register_pairs_[x86::ECX_EDI] = false;
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000101 }
102};
103
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000104class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000105 public:
Ian Rogersd582fa42014-11-05 23:46:43 -0800106 InternalCodeAllocator() : size_(0) { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000107
108 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000109 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000110 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000111 return memory_.get();
112 }
113
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000114 size_t GetSize() const { return size_; }
115 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000116
117 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000118 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -0700119 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000120
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000121 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000122};
123
Roland Levillain17ff9172015-08-18 18:36:20 +0100124static bool CanExecuteOnHardware(InstructionSet target_isa) {
125 return (target_isa == kRuntimeISA)
126 // Handle the special case of ARM, with two instructions sets
127 // (ARM32 and Thumb-2).
128 || (kRuntimeISA == kArm && target_isa == kThumb2);
129}
130
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800131static bool CanExecute(InstructionSet target_isa) {
Roland Levillain17ff9172015-08-18 18:36:20 +0100132 return CanExecuteOnHardware(target_isa) || CodeSimulator::CanSimulate(target_isa);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800133}
134
135template <typename Expected>
136static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
137
138template <>
139bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
140 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
141 return simulator->GetCReturnBool();
142}
143
144template <>
145int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
146 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
147 return simulator->GetCReturnInt32();
148}
149
150template <>
151int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
152 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
153 return simulator->GetCReturnInt64();
154}
155
156template <typename Expected>
157static void VerifyGeneratedCode(InstructionSet target_isa,
158 Expected (*f)(),
159 bool has_result,
160 Expected expected) {
Roland Levillain17ff9172015-08-18 18:36:20 +0100161 ASSERT_TRUE(CanExecute(target_isa)) << "Target ISA is not executable " << target_isa;
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800162
163 // Verify on simulator.
164 if (CodeSimulator::CanSimulate(target_isa)) {
165 std::unique_ptr<CodeSimulator> simulator(CodeSimulator::CreateCodeSimulator(target_isa));
166 Expected result = SimulatorExecute<Expected>(simulator.get(), f);
167 if (has_result) {
168 ASSERT_EQ(expected, result);
169 }
170 }
171
172 // Verify on hardware.
Roland Levillain17ff9172015-08-18 18:36:20 +0100173 if (CanExecuteOnHardware(target_isa)) {
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800174 Expected result = f();
175 if (has_result) {
176 ASSERT_EQ(expected, result);
177 }
178 }
179}
180
Roland Levillain55dcfb52014-10-24 18:09:09 +0100181template <typename Expected>
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100182static void Run(const InternalCodeAllocator& allocator,
183 const CodeGenerator& codegen,
184 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100185 Expected expected) {
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800186 InstructionSet target_isa = codegen.GetInstructionSet();
187
Roland Levillain55dcfb52014-10-24 18:09:09 +0100188 typedef Expected (*fptr)();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100189 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -0700190 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800191 if (target_isa == kThumb2) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100192 // For thumb we need the bottom bit set.
193 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
194 }
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800195 VerifyGeneratedCode(target_isa, f, has_result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100196}
197
Roland Levillain55dcfb52014-10-24 18:09:09 +0100198template <typename Expected>
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800199static void RunCodeBaseline(InstructionSet target_isa,
200 HGraph* graph,
201 bool has_result,
202 Expected expected) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000203 InternalCodeAllocator allocator;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100204
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000205 CompilerOptions compiler_options;
Mark Mendellfb8d2792015-03-31 22:16:59 -0400206 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
207 X86InstructionSetFeatures::FromCppDefines());
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100208 TestCodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
Nicolas Geoffray73e80c32014-07-22 17:47:56 +0100209 // We avoid doing a stack overflow check that requires the runtime being setup,
210 // by making sure the compiler knows the methods we are running are leaf methods.
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100211 codegenX86.CompileBaseline(&allocator, true);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800212 if (target_isa == kX86) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100213 Run(allocator, codegenX86, has_result, expected);
214 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100215
Serban Constantinescu579885a2015-02-22 20:51:33 +0000216 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
Andreas Gampedf649502015-01-06 14:13:52 -0800217 ArmInstructionSetFeatures::FromCppDefines());
Serban Constantinescu579885a2015-02-22 20:51:33 +0000218 TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100219 codegenARM.CompileBaseline(&allocator, true);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800220 if (target_isa == kArm || target_isa == kThumb2) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100221 Run(allocator, codegenARM, has_result, expected);
222 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100223
Mark Mendellfb8d2792015-03-31 22:16:59 -0400224 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
225 X86_64InstructionSetFeatures::FromCppDefines());
226 x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100227 codegenX86_64.CompileBaseline(&allocator, true);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800228 if (target_isa == kX86_64) {
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100229 Run(allocator, codegenX86_64, has_result, expected);
230 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100231
Serban Constantinescu579885a2015-02-22 20:51:33 +0000232 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
233 Arm64InstructionSetFeatures::FromCppDefines());
234 arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
Alexandre Rames5319def2014-10-23 10:03:10 +0100235 codegenARM64.CompileBaseline(&allocator, true);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800236 if (target_isa == kArm64) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100237 Run(allocator, codegenARM64, has_result, expected);
238 }
Alexey Frunze4dda3372015-06-01 18:31:49 -0700239
240 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
241 Mips64InstructionSetFeatures::FromCppDefines());
242 mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
243 codegenMIPS64.CompileBaseline(&allocator, true);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800244 if (target_isa == kMips64) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700245 Run(allocator, codegenMIPS64, has_result, expected);
246 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000247}
248
Roland Levillain55dcfb52014-10-24 18:09:09 +0100249template <typename Expected>
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100250static void RunCodeOptimized(CodeGenerator* codegen,
251 HGraph* graph,
252 std::function<void(HGraph*)> hook_before_codegen,
253 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100254 Expected expected) {
Nicolas Geoffrayea809422015-06-24 14:25:09 +0100255 // Tests may have already computed it.
256 if (graph->GetReversePostOrder().IsEmpty()) {
257 graph->BuildDominatorTree();
258 }
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100259 SsaLivenessAnalysis liveness(graph, codegen);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100260 liveness.Analyze();
261
262 RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
263 register_allocator.AllocateRegisters();
264 hook_before_codegen(graph);
265
266 InternalCodeAllocator allocator;
267 codegen->CompileOptimized(&allocator);
268 Run(allocator, *codegen, has_result, expected);
269}
270
Roland Levillain55dcfb52014-10-24 18:09:09 +0100271template <typename Expected>
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800272static void RunCodeOptimized(InstructionSet target_isa,
273 HGraph* graph,
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100274 std::function<void(HGraph*)> hook_before_codegen,
275 bool has_result,
Roland Levillain55dcfb52014-10-24 18:09:09 +0100276 Expected expected) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000277 CompilerOptions compiler_options;
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800278 if (target_isa == kArm || target_isa == kThumb2) {
279 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
280 ArmInstructionSetFeatures::FromCppDefines());
281 TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100282 RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800283 } else if (target_isa == kArm64) {
284 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
285 Arm64InstructionSetFeatures::FromCppDefines());
286 arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
Alexandre Rames3e69f162014-12-10 10:36:50 +0000287 RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800288 } else if (target_isa == kX86) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400289 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
290 X86InstructionSetFeatures::FromCppDefines());
291 x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
Alexandre Rames3e69f162014-12-10 10:36:50 +0000292 RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800293 } else if (target_isa == kX86_64) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400294 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
295 X86_64InstructionSetFeatures::FromCppDefines());
296 x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100297 RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800298 } else if (target_isa == kMips64) {
Alexey Frunze4dda3372015-06-01 18:31:49 -0700299 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
300 Mips64InstructionSetFeatures::FromCppDefines());
301 mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
302 RunCodeOptimized(&codegenMIPS64, graph, hook_before_codegen, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100303 }
304}
305
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800306static void TestCode(InstructionSet target_isa,
307 const uint16_t* data,
308 bool has_result = false,
309 int32_t expected = 0) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100310 ArenaPool pool;
311 ArenaAllocator arena(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100312 HGraph* graph = CreateGraph(&arena);
David Brazdil5e8b1372015-01-23 14:39:08 +0000313 HGraphBuilder builder(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100314 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +0000315 bool graph_built = builder.BuildGraph(*item);
316 ASSERT_TRUE(graph_built);
Calin Juravle039b6e22014-10-23 12:32:11 +0100317 // Remove suspend checks, they cannot be executed in this context.
Calin Juravle48dee042014-10-22 15:54:12 +0100318 RemoveSuspendChecks(graph);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800319 RunCodeBaseline(target_isa, graph, has_result, expected);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100320}
321
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800322static void TestCodeLong(InstructionSet target_isa,
323 const uint16_t* data,
324 bool has_result,
325 int64_t expected) {
Roland Levillain55dcfb52014-10-24 18:09:09 +0100326 ArenaPool pool;
327 ArenaAllocator arena(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100328 HGraph* graph = CreateGraph(&arena);
David Brazdil5e8b1372015-01-23 14:39:08 +0000329 HGraphBuilder builder(graph, Primitive::kPrimLong);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100330 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +0000331 bool graph_built = builder.BuildGraph(*item);
332 ASSERT_TRUE(graph_built);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100333 // Remove suspend checks, they cannot be executed in this context.
334 RemoveSuspendChecks(graph);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800335 RunCodeBaseline(target_isa, graph, has_result, expected);
Roland Levillain55dcfb52014-10-24 18:09:09 +0100336}
337
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800338class CodegenTest: public ::testing::TestWithParam<InstructionSet> {};
339
340TEST_P(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000341 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800342 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000343}
344
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800345TEST_P(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000346 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000347 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000348 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000349
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800350 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000351}
352
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800353TEST_P(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000354 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000355 Instruction::GOTO | 0x100,
356 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000357 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000358
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800359 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000360}
361
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800362TEST_P(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000363 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000364 Instruction::GOTO | 0x200,
365 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000366 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000367
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800368 TestCode(GetParam(), data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000369
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000370 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000371 Instruction::GOTO_16, 3,
372 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000373 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000374
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800375 TestCode(GetParam(), data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000376
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000377 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000378 Instruction::GOTO_32, 4, 0,
379 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000380 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000381
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800382 TestCode(GetParam(), data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000383}
384
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800385TEST_P(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000386 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000387 Instruction::RETURN_VOID,
388 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000389 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000390
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800391 TestCode(GetParam(), data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000392}
393
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800394TEST_P(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000395 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
396 Instruction::CONST_4 | 0 | 0,
397 Instruction::IF_EQ, 3,
398 Instruction::GOTO | 0x100,
399 Instruction::RETURN_VOID);
400
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800401 TestCode(GetParam(), data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000402}
403
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800404TEST_P(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000405 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
406 Instruction::CONST_4 | 0 | 0,
407 Instruction::RETURN_VOID);
408
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800409 TestCode(GetParam(), data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000410}
411
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800412TEST_P(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000413 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
414 Instruction::CONST_4 | 0 | 0,
415 Instruction::RETURN | 0);
416
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800417 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418}
419
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800420TEST_P(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000421 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
422 Instruction::CONST_4 | 0 | 0,
423 Instruction::CONST_4 | 0 | 1 << 8,
424 Instruction::RETURN | 1 << 8);
425
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800426 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000427}
428
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800429TEST_P(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000430 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
431 Instruction::CONST_4 | 0 | 0,
432 Instruction::CONST_4 | 1 << 8 | 1 << 12,
433 Instruction::RETURN | 1 << 8);
434
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800435 TestCode(GetParam(), data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000436}
437
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800438TEST_P(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000439 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
440 Instruction::CONST_4 | 0 | 0,
441 Instruction::CONST_4 | 1 << 8 | 1 << 12,
442 Instruction::IF_EQ, 3,
443 Instruction::RETURN | 0 << 8,
444 Instruction::RETURN | 1 << 8);
445
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800446 TestCode(GetParam(), data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000447}
448
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800449TEST_P(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000450 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
451 Instruction::CONST_4 | 0 | 0,
452 Instruction::CONST_4 | 1 << 8 | 1 << 12,
453 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
454 Instruction::RETURN | 0 << 8,
455 Instruction::RETURN | 1 << 8);
456
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800457 TestCode(GetParam(), data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000458}
459
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100460// Exercise bit-wise (one's complement) not-int instruction.
461#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800462TEST_P(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100463 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100464 const uint16_t input_lo = Low16Bits(input); \
465 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100466 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
467 Instruction::CONST | 0 << 8, input_lo, input_hi, \
468 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
469 Instruction::RETURN | 1 << 8); \
470 \
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800471 TestCode(GetParam(), data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100472}
473
474NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
475NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
476NOT_INT_TEST(ReturnNotInt0, 0, -1)
477NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100478NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
479NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
480NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
481NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100482
483#undef NOT_INT_TEST
484
Roland Levillain55dcfb52014-10-24 18:09:09 +0100485// Exercise bit-wise (one's complement) not-long instruction.
486#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800487TEST_P(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100488 const int64_t input = INPUT; \
489 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
490 const uint16_t word1 = High16Bits(Low32Bits(input)); \
491 const uint16_t word2 = Low16Bits(High32Bits(input)); \
492 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
493 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
494 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
495 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
496 Instruction::RETURN_WIDE | 2 << 8); \
497 \
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800498 TestCodeLong(GetParam(), data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100499}
500
501NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
502NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
503NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
504NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
505
506NOT_LONG_TEST(ReturnNotLongINT32_MIN,
507 INT64_C(-2147483648),
508 INT64_C(2147483647)) // (2^31) - 1
509NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
510 INT64_C(-2147483647),
511 INT64_C(2147483646)) // (2^31) - 2
512NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
513 INT64_C(2147483646),
514 INT64_C(-2147483647)) // -(2^31) - 1
515NOT_LONG_TEST(ReturnNotLongINT32_MAX,
516 INT64_C(2147483647),
517 INT64_C(-2147483648)) // -(2^31)
518
519// Note that the C++ compiler won't accept
520// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
521// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
522NOT_LONG_TEST(ReturnNotINT64_MIN,
523 INT64_C(-9223372036854775807)-1,
524 INT64_C(9223372036854775807)); // (2^63) - 1
525NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
526 INT64_C(-9223372036854775807),
527 INT64_C(9223372036854775806)); // (2^63) - 2
528NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
529 INT64_C(9223372036854775806),
530 INT64_C(-9223372036854775807)); // -(2^63) - 1
531NOT_LONG_TEST(ReturnNotLongINT64_MAX,
532 INT64_C(9223372036854775807),
533 INT64_C(-9223372036854775807)-1); // -(2^63)
534
535#undef NOT_LONG_TEST
536
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800537TEST_P(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000538 const int64_t input = INT64_C(4294967296); // 2^32
539 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
540 const uint16_t word1 = High16Bits(Low32Bits(input));
541 const uint16_t word2 = Low16Bits(High32Bits(input));
542 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
543 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
544 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
545 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
546 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
547 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
548 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
549 Instruction::RETURN_WIDE | 2 << 8);
550
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800551 TestCodeLong(GetParam(), data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000552}
553
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800554TEST_P(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000555 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
556 Instruction::CONST_4 | 3 << 12 | 0,
557 Instruction::CONST_4 | 4 << 12 | 1 << 8,
558 Instruction::ADD_INT, 1 << 8 | 0,
559 Instruction::RETURN);
560
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800561 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000562}
563
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800564TEST_P(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000565 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
566 Instruction::CONST_4 | 3 << 12 | 0,
567 Instruction::CONST_4 | 4 << 12 | 1 << 8,
568 Instruction::ADD_INT_2ADDR | 1 << 12,
569 Instruction::RETURN);
570
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800571 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000572}
573
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800574TEST_P(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000575 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
576 Instruction::CONST_4 | 4 << 12 | 0 << 8,
577 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
578 Instruction::RETURN);
579
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800580 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000581}
582
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800583TEST_P(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000584 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
585 Instruction::CONST_4 | 4 << 12 | 0 << 8,
586 Instruction::ADD_INT_LIT16, 3,
587 Instruction::RETURN);
588
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800589 TestCode(GetParam(), data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000590}
591
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800592TEST_P(CodegenTest, NonMaterializedCondition) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100593 ArenaPool pool;
594 ArenaAllocator allocator(&pool);
595
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100596 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100597 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
598 graph->AddBlock(entry);
599 graph->SetEntryBlock(entry);
600 entry->AddInstruction(new (&allocator) HGoto());
601
602 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
603 graph->AddBlock(first_block);
604 entry->AddSuccessor(first_block);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000605 HIntConstant* constant0 = graph->GetIntConstant(0);
606 HIntConstant* constant1 = graph->GetIntConstant(1);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100607 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
608 first_block->AddInstruction(equal);
609 first_block->AddInstruction(new (&allocator) HIf(equal));
610
611 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
612 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
613 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
614
615 graph->AddBlock(then);
616 graph->AddBlock(else_);
617 graph->AddBlock(exit);
618 first_block->AddSuccessor(then);
619 first_block->AddSuccessor(else_);
620 then->AddSuccessor(exit);
621 else_->AddSuccessor(exit);
622
623 exit->AddInstruction(new (&allocator) HExit());
624 then->AddInstruction(new (&allocator) HReturn(constant0));
625 else_->AddInstruction(new (&allocator) HReturn(constant1));
626
627 ASSERT_TRUE(equal->NeedsMaterialization());
628 graph->BuildDominatorTree();
629 PrepareForRegisterAllocation(graph).Run();
630 ASSERT_FALSE(equal->NeedsMaterialization());
631
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800632 auto hook_before_codegen = [](HGraph* graph_in) {
633 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
634 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100635 block->InsertInstructionBefore(move, block->GetLastInstruction());
636 };
637
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800638 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, 0);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100639}
640
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800641TEST_P(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100642 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
643 Instruction::CONST_4 | 3 << 12 | 0,
644 Instruction::CONST_4 | 4 << 12 | 1 << 8,
645 Instruction::MUL_INT, 1 << 8 | 0,
646 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100647
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800648 TestCode(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100649}
650
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800651TEST_P(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100652 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
653 Instruction::CONST_4 | 3 << 12 | 0,
654 Instruction::CONST_4 | 4 << 12 | 1 << 8,
655 Instruction::MUL_INT_2ADDR | 1 << 12,
656 Instruction::RETURN);
657
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800658 TestCode(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100659}
660
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800661TEST_P(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100662 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
663 Instruction::CONST_4 | 3 << 12 | 0,
664 Instruction::CONST_4 | 0 << 12 | 1 << 8,
665 Instruction::CONST_4 | 4 << 12 | 2 << 8,
666 Instruction::CONST_4 | 0 << 12 | 3 << 8,
667 Instruction::MUL_LONG, 2 << 8 | 0,
668 Instruction::RETURN_WIDE);
669
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800670 TestCodeLong(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100671}
672
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800673TEST_P(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100674 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
675 Instruction::CONST_4 | 3 << 12 | 0 << 8,
676 Instruction::CONST_4 | 0 << 12 | 1 << 8,
677 Instruction::CONST_4 | 4 << 12 | 2 << 8,
678 Instruction::CONST_4 | 0 << 12 | 3 << 8,
679 Instruction::MUL_LONG_2ADDR | 2 << 12,
680 Instruction::RETURN_WIDE);
681
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800682 TestCodeLong(GetParam(), data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100683}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100684
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800685TEST_P(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100686 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
687 Instruction::CONST_4 | 4 << 12 | 0 << 8,
688 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
689 Instruction::RETURN);
690
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800691 TestCode(GetParam(), data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100692}
693
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800694TEST_P(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100695 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
696 Instruction::CONST_4 | 4 << 12 | 0 << 8,
697 Instruction::MUL_INT_LIT16, 3,
698 Instruction::RETURN);
699
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800700 TestCode(GetParam(), data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100701}
702
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800703TEST_P(CodegenTest, MaterializedCondition1) {
Alexandre Rames92730742014-10-01 12:55:56 +0100704 // Check that condition are materialized correctly. A materialized condition
705 // should yield `1` if it evaluated to true, and `0` otherwise.
706 // We force the materialization of comparisons for different combinations of
707 // inputs and check the results.
708
709 int lhs[] = {1, 2, -1, 2, 0xabc};
710 int rhs[] = {2, 1, 2, -1, 0xabc};
711
712 for (size_t i = 0; i < arraysize(lhs); i++) {
713 ArenaPool pool;
714 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100715 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100716
717 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
718 graph->AddBlock(entry_block);
719 graph->SetEntryBlock(entry_block);
720 entry_block->AddInstruction(new (&allocator) HGoto());
721 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
722 graph->AddBlock(code_block);
723 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
724 graph->AddBlock(exit_block);
725 exit_block->AddInstruction(new (&allocator) HExit());
726
727 entry_block->AddSuccessor(code_block);
728 code_block->AddSuccessor(exit_block);
729 graph->SetExitBlock(exit_block);
730
David Brazdil8d5b8b22015-03-24 10:51:52 +0000731 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
732 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
733 HLessThan cmp_lt(cst_lhs, cst_rhs);
Alexandre Rames92730742014-10-01 12:55:56 +0100734 code_block->AddInstruction(&cmp_lt);
735 HReturn ret(&cmp_lt);
736 code_block->AddInstruction(&ret);
737
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800738 auto hook_before_codegen = [](HGraph* graph_in) {
739 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
740 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100741 block->InsertInstructionBefore(move, block->GetLastInstruction());
742 };
743
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800744 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]);
Alexandre Rames92730742014-10-01 12:55:56 +0100745 }
746}
747
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800748TEST_P(CodegenTest, MaterializedCondition2) {
Alexandre Rames92730742014-10-01 12:55:56 +0100749 // Check that HIf correctly interprets a materialized condition.
750 // We force the materialization of comparisons for different combinations of
751 // inputs. An HIf takes the materialized combination as input and returns a
752 // value that we verify.
753
754 int lhs[] = {1, 2, -1, 2, 0xabc};
755 int rhs[] = {2, 1, 2, -1, 0xabc};
756
757
758 for (size_t i = 0; i < arraysize(lhs); i++) {
759 ArenaPool pool;
760 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100761 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100762
763 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
764 graph->AddBlock(entry_block);
765 graph->SetEntryBlock(entry_block);
766 entry_block->AddInstruction(new (&allocator) HGoto());
767
768 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
769 graph->AddBlock(if_block);
770 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
771 graph->AddBlock(if_true_block);
772 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
773 graph->AddBlock(if_false_block);
774 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
775 graph->AddBlock(exit_block);
776 exit_block->AddInstruction(new (&allocator) HExit());
777
778 graph->SetEntryBlock(entry_block);
779 entry_block->AddSuccessor(if_block);
780 if_block->AddSuccessor(if_true_block);
781 if_block->AddSuccessor(if_false_block);
782 if_true_block->AddSuccessor(exit_block);
783 if_false_block->AddSuccessor(exit_block);
784 graph->SetExitBlock(exit_block);
785
David Brazdil8d5b8b22015-03-24 10:51:52 +0000786 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
787 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
788 HLessThan cmp_lt(cst_lhs, cst_rhs);
Alexandre Rames92730742014-10-01 12:55:56 +0100789 if_block->AddInstruction(&cmp_lt);
790 // We insert a temporary to separate the HIf from the HLessThan and force
791 // the materialization of the condition.
792 HTemporary force_materialization(0);
793 if_block->AddInstruction(&force_materialization);
794 HIf if_lt(&cmp_lt);
795 if_block->AddInstruction(&if_lt);
796
David Brazdil8d5b8b22015-03-24 10:51:52 +0000797 HIntConstant* cst_lt = graph->GetIntConstant(1);
798 HReturn ret_lt(cst_lt);
Alexandre Rames92730742014-10-01 12:55:56 +0100799 if_true_block->AddInstruction(&ret_lt);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000800 HIntConstant* cst_ge = graph->GetIntConstant(0);
801 HReturn ret_ge(cst_ge);
Alexandre Rames92730742014-10-01 12:55:56 +0100802 if_false_block->AddInstruction(&ret_ge);
803
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800804 auto hook_before_codegen = [](HGraph* graph_in) {
805 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
806 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100807 block->InsertInstructionBefore(move, block->GetLastInstruction());
808 };
809
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800810 RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]);
Alexandre Rames92730742014-10-01 12:55:56 +0100811 }
812}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100813
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800814TEST_P(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000815 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
816 Instruction::CONST_4 | 4 << 12 | 0 << 8,
817 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
818 Instruction::RETURN);
819
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800820 TestCode(GetParam(), data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000821}
822
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800823TEST_P(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000824 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
825 Instruction::CONST_4 | 4 << 12 | 0,
826 Instruction::CONST_4 | 2 << 12 | 1 << 8,
827 Instruction::DIV_INT_2ADDR | 1 << 12,
828 Instruction::RETURN);
829
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800830 TestCode(GetParam(), data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000831}
832
Phil Wangc2e1a5e2015-07-29 15:14:09 +0800833static ::std::vector<InstructionSet> GetTargetISAs() {
834 ::std::vector<InstructionSet> v;
835 // Add all ISAs that are executable on hardware or on simulator.
836 const ::std::vector<InstructionSet> executable_isa_candidates = {
837 kArm,
838 kArm64,
839 kThumb2,
840 kX86,
841 kX86_64,
842 kMips,
843 kMips64
844 };
845
846 for (auto target_isa : executable_isa_candidates) {
847 if (CanExecute(target_isa)) {
848 v.push_back(target_isa);
849 }
850 }
851
852 return v;
853}
854
855INSTANTIATE_TEST_CASE_P(MultipleTargets,
856 CodegenTest,
857 ::testing::ValuesIn(GetTargetISAs()));
858
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000859} // namespace art