blob: cd954043f557ee23dfb697c3a8aa73f27c0545b7 [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
20#include "arch/arm/instruction_set_features_arm.h"
21#include "arch/arm/registers_arm.h"
22#include "arch/arm64/instruction_set_features_arm64.h"
23#include "arch/instruction_set.h"
24#include "arch/mips/instruction_set_features_mips.h"
25#include "arch/mips/registers_mips.h"
26#include "arch/mips64/instruction_set_features_mips64.h"
27#include "arch/mips64/registers_mips64.h"
28#include "arch/x86/instruction_set_features_x86.h"
29#include "arch/x86/registers_x86.h"
30#include "arch/x86_64/instruction_set_features_x86_64.h"
31#include "code_simulator_container.h"
32#include "common_compiler_test.h"
33#include "graph_checker.h"
34#include "prepare_for_register_allocation.h"
35#include "ssa_liveness_analysis.h"
36
37#ifdef ART_ENABLE_CODEGEN_arm
38#include "code_generator_arm.h"
39#include "code_generator_arm_vixl.h"
40#endif
41
42#ifdef ART_ENABLE_CODEGEN_arm64
43#include "code_generator_arm64.h"
44#endif
45
46#ifdef ART_ENABLE_CODEGEN_x86
47#include "code_generator_x86.h"
48#endif
49
50#ifdef ART_ENABLE_CODEGEN_x86_64
51#include "code_generator_x86_64.h"
52#endif
53
54#ifdef ART_ENABLE_CODEGEN_mips
55#include "code_generator_mips.h"
56#endif
57
58#ifdef ART_ENABLE_CODEGEN_mips64
59#include "code_generator_mips64.h"
60#endif
61
62namespace art {
63
64typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
65
66class CodegenTargetConfig {
67 public:
68 CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
69 : isa_(isa), create_codegen_(create_codegen) {
70 }
71 InstructionSet GetInstructionSet() const { return isa_; }
72 CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
73 return create_codegen_(graph, compiler_options);
74 }
75
76 private:
77 CodegenTargetConfig() {}
78 InstructionSet isa_;
79 CreateCodegenFn create_codegen_;
80};
81
82#ifdef ART_ENABLE_CODEGEN_arm
83// Provide our own codegen, that ensures the C calling conventions
84// are preserved. Currently, ART and C do not match as R4 is caller-save
85// in ART, and callee-save in C. Alternatively, we could use or write
86// the stub that saves and restores all registers, but it is easier
87// to just overwrite the code generator.
88class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
89 public:
90 TestCodeGeneratorARM(HGraph* graph,
91 const ArmInstructionSetFeatures& isa_features,
92 const CompilerOptions& compiler_options)
93 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
94 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
95 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
96 }
97
98 void SetupBlockedRegisters() const OVERRIDE {
99 arm::CodeGeneratorARM::SetupBlockedRegisters();
100 blocked_core_registers_[arm::R4] = true;
101 blocked_core_registers_[arm::R6] = false;
102 blocked_core_registers_[arm::R7] = false;
103 }
104};
105
106// A way to test the VIXL32-based code generator on ARM. This will replace
107// TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one.
108class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
109 public:
110 TestCodeGeneratorARMVIXL(HGraph* graph,
111 const ArmInstructionSetFeatures& isa_features,
112 const CompilerOptions& compiler_options)
113 : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
114 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
115 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
116 }
117
118 void SetupBlockedRegisters() const OVERRIDE {
119 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
120 blocked_core_registers_[arm::R4] = true;
121 blocked_core_registers_[arm::R6] = false;
122 blocked_core_registers_[arm::R7] = false;
123 }
124};
125#endif
126
127#ifdef ART_ENABLE_CODEGEN_x86
128class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
129 public:
130 TestCodeGeneratorX86(HGraph* graph,
131 const X86InstructionSetFeatures& isa_features,
132 const CompilerOptions& compiler_options)
133 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
134 // Save edi, we need it for getting enough registers for long multiplication.
135 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
136 }
137
138 void SetupBlockedRegisters() const OVERRIDE {
139 x86::CodeGeneratorX86::SetupBlockedRegisters();
140 // ebx is a callee-save register in C, but caller-save for ART.
141 blocked_core_registers_[x86::EBX] = true;
142
143 // Make edi available.
144 blocked_core_registers_[x86::EDI] = false;
145 }
146};
147#endif
148
149class InternalCodeAllocator : public CodeAllocator {
150 public:
151 InternalCodeAllocator() : size_(0) { }
152
153 virtual uint8_t* Allocate(size_t size) {
154 size_ = size;
155 memory_.reset(new uint8_t[size]);
156 return memory_.get();
157 }
158
159 size_t GetSize() const { return size_; }
160 uint8_t* GetMemory() const { return memory_.get(); }
161
162 private:
163 size_t size_;
164 std::unique_ptr<uint8_t[]> memory_;
165
166 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
167};
168
169static bool CanExecuteOnHardware(InstructionSet target_isa) {
170 return (target_isa == kRuntimeISA)
171 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
172 || (kRuntimeISA == kArm && target_isa == kThumb2);
173}
174
175static bool CanExecute(InstructionSet target_isa) {
176 CodeSimulatorContainer simulator(target_isa);
177 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
178}
179
180template <typename Expected>
181inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
182
183template <>
184inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
185 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
186 return simulator->GetCReturnBool();
187}
188
189template <>
190inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
191 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
192 return simulator->GetCReturnInt32();
193}
194
195template <>
196inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
197 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
198 return simulator->GetCReturnInt64();
199}
200
201template <typename Expected>
202static void VerifyGeneratedCode(InstructionSet target_isa,
203 Expected (*f)(),
204 bool has_result,
205 Expected expected) {
206 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
207
208 // Verify on simulator.
209 CodeSimulatorContainer simulator(target_isa);
210 if (simulator.CanSimulate()) {
211 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
212 if (has_result) {
213 ASSERT_EQ(expected, result);
214 }
215 }
216
217 // Verify on hardware.
218 if (CanExecuteOnHardware(target_isa)) {
219 Expected result = f();
220 if (has_result) {
221 ASSERT_EQ(expected, result);
222 }
223 }
224}
225
226template <typename Expected>
227static void Run(const InternalCodeAllocator& allocator,
228 const CodeGenerator& codegen,
229 bool has_result,
230 Expected expected) {
231 InstructionSet target_isa = codegen.GetInstructionSet();
232
233 typedef Expected (*fptr)();
234 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
235 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
236 if (target_isa == kThumb2) {
237 // For thumb we need the bottom bit set.
238 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
239 }
240 VerifyGeneratedCode(target_isa, f, has_result, expected);
241}
242
243static void ValidateGraph(HGraph* graph) {
244 GraphChecker graph_checker(graph);
245 graph_checker.Run();
246 if (!graph_checker.IsValid()) {
247 for (const auto& error : graph_checker.GetErrors()) {
248 std::cout << error << std::endl;
249 }
250 }
251 ASSERT_TRUE(graph_checker.IsValid());
252}
253
254template <typename Expected>
255static void RunCodeNoCheck(CodeGenerator* codegen,
256 HGraph* graph,
257 const std::function<void(HGraph*)>& hook_before_codegen,
258 bool has_result,
259 Expected expected) {
260 SsaLivenessAnalysis liveness(graph, codegen);
261 PrepareForRegisterAllocation(graph).Run();
262 liveness.Analyze();
263 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
264 hook_before_codegen(graph);
265 InternalCodeAllocator allocator;
266 codegen->Compile(&allocator);
267 Run(allocator, *codegen, has_result, expected);
268}
269
270template <typename Expected>
271static void RunCode(CodeGenerator* codegen,
272 HGraph* graph,
273 std::function<void(HGraph*)> hook_before_codegen,
274 bool has_result,
275 Expected expected) {
276 ValidateGraph(graph);
277 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
278}
279
280template <typename Expected>
281static void RunCode(CodegenTargetConfig target_config,
282 HGraph* graph,
283 std::function<void(HGraph*)> hook_before_codegen,
284 bool has_result,
285 Expected expected) {
286 CompilerOptions compiler_options;
287 std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options));
288 RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
289}
290
291#ifdef ART_ENABLE_CODEGEN_arm
292CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
293 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
294 ArmInstructionSetFeatures::FromCppDefines());
295 return new (graph->GetArena()) TestCodeGeneratorARM(graph,
296 *features_arm.get(),
297 compiler_options);
298}
299
300CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
301 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
302 ArmInstructionSetFeatures::FromCppDefines());
303 return new (graph->GetArena())
304 TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
305}
306#endif
307
308#ifdef ART_ENABLE_CODEGEN_arm64
309CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
310 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
311 Arm64InstructionSetFeatures::FromCppDefines());
312 return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
313 *features_arm64.get(),
314 compiler_options);
315}
316#endif
317
318#ifdef ART_ENABLE_CODEGEN_x86
319CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
320 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
321 X86InstructionSetFeatures::FromCppDefines());
322 return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
323}
324#endif
325
326#ifdef ART_ENABLE_CODEGEN_x86_64
327CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
328 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
329 X86_64InstructionSetFeatures::FromCppDefines());
330 return new (graph->GetArena())
331 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
332}
333#endif
334
335#ifdef ART_ENABLE_CODEGEN_mips
336CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
337 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
338 MipsInstructionSetFeatures::FromCppDefines());
339 return new (graph->GetArena())
340 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
341}
342#endif
343
344#ifdef ART_ENABLE_CODEGEN_mips64
345CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
346 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
347 Mips64InstructionSetFeatures::FromCppDefines());
348 return new (graph->GetArena())
349 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
350}
351#endif
352
353} // namespace art
354
355#endif // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_