blob: dde39d46f3c2a495d51b10c80251cc08f3f89ce9 [file] [log] [blame]
Alexandre Rames22aa54b2016-10-18 09:32:29 +01001/*
2 * Copyright (C) 2016 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
17#ifndef ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
18#define ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
19
Alexandre Rames22aa54b2016-10-18 09:32:29 +010020#include "arch/arm/registers_arm.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010021#include "arch/instruction_set.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010022#include "arch/mips/registers_mips.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010023#include "arch/mips64/registers_mips64.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010024#include "arch/x86/registers_x86.h"
Andreas Gampe71da4872017-07-26 10:02:07 -070025#include "code_simulator.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010026#include "code_simulator_container.h"
27#include "common_compiler_test.h"
28#include "graph_checker.h"
29#include "prepare_for_register_allocation.h"
30#include "ssa_liveness_analysis.h"
31
32#ifdef ART_ENABLE_CODEGEN_arm
Alexandre Rames22aa54b2016-10-18 09:32:29 +010033#include "code_generator_arm_vixl.h"
34#endif
35
36#ifdef ART_ENABLE_CODEGEN_arm64
37#include "code_generator_arm64.h"
38#endif
39
40#ifdef ART_ENABLE_CODEGEN_x86
41#include "code_generator_x86.h"
42#endif
43
44#ifdef ART_ENABLE_CODEGEN_x86_64
45#include "code_generator_x86_64.h"
46#endif
47
48#ifdef ART_ENABLE_CODEGEN_mips
49#include "code_generator_mips.h"
50#endif
51
52#ifdef ART_ENABLE_CODEGEN_mips64
53#include "code_generator_mips64.h"
54#endif
55
56namespace art {
57
58typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
59
60class CodegenTargetConfig {
61 public:
62 CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
63 : isa_(isa), create_codegen_(create_codegen) {
64 }
65 InstructionSet GetInstructionSet() const { return isa_; }
66 CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
67 return create_codegen_(graph, compiler_options);
68 }
69
70 private:
Alexandre Rames22aa54b2016-10-18 09:32:29 +010071 InstructionSet isa_;
72 CreateCodegenFn create_codegen_;
73};
74
75#ifdef ART_ENABLE_CODEGEN_arm
Roland Levillain5daa4952017-07-03 17:23:56 +010076// Special ARM code generator for codegen testing in a limited code
77// generation environment (i.e. with no runtime support).
78//
79// Note: If we want to exercise certains HIR constructions
80// (e.g. reference field load in Baker read barrier configuration) in
81// codegen tests in the future, we should also:
82// - save the Thread Register (R9) and possibly the Marking Register
83// (R8) before entering the generated function (both registers are
84// callee-save in AAPCS);
85// - set these registers to meaningful values before or upon entering
86// the generated function (so that generated code using them is
87// correct);
88// - restore their original values before leaving the generated
89// function.
90
Alexandre Rames22aa54b2016-10-18 09:32:29 +010091// Provide our own codegen, that ensures the C calling conventions
92// are preserved. Currently, ART and C do not match as R4 is caller-save
93// in ART, and callee-save in C. Alternatively, we could use or write
94// the stub that saves and restores all registers, but it is easier
95// to just overwrite the code generator.
Alexandre Rames22aa54b2016-10-18 09:32:29 +010096class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
97 public:
Vladimir Markoa0431112018-06-25 09:32:54 +010098 TestCodeGeneratorARMVIXL(HGraph* graph, const CompilerOptions& compiler_options)
99 : arm::CodeGeneratorARMVIXL(graph, compiler_options) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100100 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
101 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
102 }
103
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100104 void SetupBlockedRegisters() const override {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100105 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
106 blocked_core_registers_[arm::R4] = true;
107 blocked_core_registers_[arm::R6] = false;
108 blocked_core_registers_[arm::R7] = false;
109 }
Roland Levillain5daa4952017-07-03 17:23:56 +0100110
111 void MaybeGenerateMarkingRegisterCheck(int code ATTRIBUTE_UNUSED,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100112 Location temp_loc ATTRIBUTE_UNUSED) override {
Roland Levillain5daa4952017-07-03 17:23:56 +0100113 // When turned on, the marking register checks in
114 // CodeGeneratorARMVIXL::MaybeGenerateMarkingRegisterCheck expects the
115 // Thread Register and the Marking Register to be set to
116 // meaningful values. This is not the case in codegen testing, so
117 // just disable them entirely here (by doing nothing in this
118 // method).
119 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100120};
121#endif
122
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100123#ifdef ART_ENABLE_CODEGEN_arm64
124// Special ARM64 code generator for codegen testing in a limited code
125// generation environment (i.e. with no runtime support).
126//
127// Note: If we want to exercise certains HIR constructions
128// (e.g. reference field load in Baker read barrier configuration) in
129// codegen tests in the future, we should also:
130// - save the Thread Register (X19) and possibly the Marking Register
131// (X20) before entering the generated function (both registers are
132// callee-save in AAPCS64);
133// - set these registers to meaningful values before or upon entering
134// the generated function (so that generated code using them is
135// correct);
136// - restore their original values before leaving the generated
137// function.
138class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 {
139 public:
Vladimir Markoa0431112018-06-25 09:32:54 +0100140 TestCodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
141 : arm64::CodeGeneratorARM64(graph, compiler_options) {}
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100142
143 void MaybeGenerateMarkingRegisterCheck(int codem ATTRIBUTE_UNUSED,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100144 Location temp_loc ATTRIBUTE_UNUSED) override {
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100145 // When turned on, the marking register checks in
146 // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck expect the
147 // Thread Register and the Marking Register to be set to
148 // meaningful values. This is not the case in codegen testing, so
149 // just disable them entirely here (by doing nothing in this
150 // method).
151 }
152};
153#endif
154
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100155#ifdef ART_ENABLE_CODEGEN_x86
156class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
157 public:
Vladimir Markoa0431112018-06-25 09:32:54 +0100158 TestCodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
159 : x86::CodeGeneratorX86(graph, compiler_options) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100160 // Save edi, we need it for getting enough registers for long multiplication.
161 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
162 }
163
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100164 void SetupBlockedRegisters() const override {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100165 x86::CodeGeneratorX86::SetupBlockedRegisters();
166 // ebx is a callee-save register in C, but caller-save for ART.
167 blocked_core_registers_[x86::EBX] = true;
168
169 // Make edi available.
170 blocked_core_registers_[x86::EDI] = false;
171 }
172};
173#endif
174
175class InternalCodeAllocator : public CodeAllocator {
176 public:
177 InternalCodeAllocator() : size_(0) { }
178
Yi Kong39402542019-03-24 02:47:16 -0700179 uint8_t* Allocate(size_t size) override {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100180 size_ = size;
181 memory_.reset(new uint8_t[size]);
182 return memory_.get();
183 }
184
185 size_t GetSize() const { return size_; }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100186 ArrayRef<const uint8_t> GetMemory() const override {
Vladimir Markoca1e0382018-04-11 09:58:41 +0000187 return ArrayRef<const uint8_t>(memory_.get(), size_);
188 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100189
190 private:
191 size_t size_;
192 std::unique_ptr<uint8_t[]> memory_;
193
194 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
195};
196
197static bool CanExecuteOnHardware(InstructionSet target_isa) {
198 return (target_isa == kRuntimeISA)
199 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
Vladimir Marko33bff252017-11-01 14:35:42 +0000200 || (kRuntimeISA == InstructionSet::kArm && target_isa == InstructionSet::kThumb2);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100201}
202
203static bool CanExecute(InstructionSet target_isa) {
204 CodeSimulatorContainer simulator(target_isa);
205 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
206}
207
208template <typename Expected>
209inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
210
211template <>
212inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
213 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
214 return simulator->GetCReturnBool();
215}
216
217template <>
218inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
219 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
220 return simulator->GetCReturnInt32();
221}
222
223template <>
224inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
225 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
226 return simulator->GetCReturnInt64();
227}
228
229template <typename Expected>
230static void VerifyGeneratedCode(InstructionSet target_isa,
231 Expected (*f)(),
232 bool has_result,
233 Expected expected) {
234 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
235
236 // Verify on simulator.
237 CodeSimulatorContainer simulator(target_isa);
238 if (simulator.CanSimulate()) {
239 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
240 if (has_result) {
241 ASSERT_EQ(expected, result);
242 }
243 }
244
245 // Verify on hardware.
246 if (CanExecuteOnHardware(target_isa)) {
247 Expected result = f();
248 if (has_result) {
249 ASSERT_EQ(expected, result);
250 }
251 }
252}
253
254template <typename Expected>
255static void Run(const InternalCodeAllocator& allocator,
256 const CodeGenerator& codegen,
257 bool has_result,
258 Expected expected) {
259 InstructionSet target_isa = codegen.GetInstructionSet();
260
261 typedef Expected (*fptr)();
Vladimir Markoca1e0382018-04-11 09:58:41 +0000262 CommonCompilerTest::MakeExecutable(allocator.GetMemory().data(), allocator.GetMemory().size());
263 fptr f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(allocator.GetMemory().data()));
Vladimir Marko33bff252017-11-01 14:35:42 +0000264 if (target_isa == InstructionSet::kThumb2) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100265 // For thumb we need the bottom bit set.
266 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
267 }
268 VerifyGeneratedCode(target_isa, f, has_result, expected);
269}
270
271static void ValidateGraph(HGraph* graph) {
272 GraphChecker graph_checker(graph);
273 graph_checker.Run();
274 if (!graph_checker.IsValid()) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +0100275 for (const std::string& error : graph_checker.GetErrors()) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100276 std::cout << error << std::endl;
277 }
278 }
279 ASSERT_TRUE(graph_checker.IsValid());
280}
281
282template <typename Expected>
283static void RunCodeNoCheck(CodeGenerator* codegen,
284 HGraph* graph,
285 const std::function<void(HGraph*)>& hook_before_codegen,
286 bool has_result,
287 Expected expected) {
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100288 {
289 ScopedArenaAllocator local_allocator(graph->GetArenaStack());
290 SsaLivenessAnalysis liveness(graph, codegen, &local_allocator);
Nicolas Geoffray61ba8d22018-08-07 09:55:57 +0100291 PrepareForRegisterAllocation(graph, codegen->GetCompilerOptions()).Run();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100292 liveness.Analyze();
293 std::unique_ptr<RegisterAllocator> register_allocator =
294 RegisterAllocator::Create(&local_allocator, codegen, liveness);
295 register_allocator->AllocateRegisters();
296 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100297 hook_before_codegen(graph);
298 InternalCodeAllocator allocator;
299 codegen->Compile(&allocator);
300 Run(allocator, *codegen, has_result, expected);
301}
302
303template <typename Expected>
304static void RunCode(CodeGenerator* codegen,
305 HGraph* graph,
306 std::function<void(HGraph*)> hook_before_codegen,
307 bool has_result,
308 Expected expected) {
309 ValidateGraph(graph);
310 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
311}
312
313template <typename Expected>
314static void RunCode(CodegenTargetConfig target_config,
Vladimir Markoa0431112018-06-25 09:32:54 +0100315 const CompilerOptions& compiler_options,
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100316 HGraph* graph,
317 std::function<void(HGraph*)> hook_before_codegen,
318 bool has_result,
319 Expected expected) {
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100320 std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph,
321 compiler_options));
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100322 RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
323}
324
325#ifdef ART_ENABLE_CODEGEN_arm
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100326CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100327 return new (graph->GetAllocator()) TestCodeGeneratorARMVIXL(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100328}
329#endif
330
331#ifdef ART_ENABLE_CODEGEN_arm64
332CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100333 return new (graph->GetAllocator()) TestCodeGeneratorARM64(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100334}
335#endif
336
337#ifdef ART_ENABLE_CODEGEN_x86
338CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100339 return new (graph->GetAllocator()) TestCodeGeneratorX86(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100340}
341#endif
342
343#ifdef ART_ENABLE_CODEGEN_x86_64
344CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100345 return new (graph->GetAllocator()) x86_64::CodeGeneratorX86_64(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100346}
347#endif
348
349#ifdef ART_ENABLE_CODEGEN_mips
350CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100351 return new (graph->GetAllocator()) mips::CodeGeneratorMIPS(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100352}
353#endif
354
355#ifdef ART_ENABLE_CODEGEN_mips64
356CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100357 return new (graph->GetAllocator()) mips64::CodeGeneratorMIPS64(graph, compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100358}
359#endif
360
361} // namespace art
362
363#endif // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_