blob: cada2e679b85f45786a580866f9d8dd2a9ed875d [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"
Andreas Gampe71da4872017-07-26 10:02:07 -070031#include "code_simulator.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010032#include "code_simulator_container.h"
33#include "common_compiler_test.h"
34#include "graph_checker.h"
35#include "prepare_for_register_allocation.h"
36#include "ssa_liveness_analysis.h"
37
38#ifdef ART_ENABLE_CODEGEN_arm
Alexandre Rames22aa54b2016-10-18 09:32:29 +010039#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:
Alexandre Rames22aa54b2016-10-18 09:32:29 +010077 InstructionSet isa_;
78 CreateCodegenFn create_codegen_;
79};
80
81#ifdef ART_ENABLE_CODEGEN_arm
82// Provide our own codegen, that ensures the C calling conventions
83// are preserved. Currently, ART and C do not match as R4 is caller-save
84// in ART, and callee-save in C. Alternatively, we could use or write
85// the stub that saves and restores all registers, but it is easier
86// to just overwrite the code generator.
Alexandre Rames22aa54b2016-10-18 09:32:29 +010087class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
88 public:
89 TestCodeGeneratorARMVIXL(HGraph* graph,
90 const ArmInstructionSetFeatures& isa_features,
91 const CompilerOptions& compiler_options)
92 : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
93 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
94 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
95 }
96
97 void SetupBlockedRegisters() const OVERRIDE {
98 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
99 blocked_core_registers_[arm::R4] = true;
100 blocked_core_registers_[arm::R6] = false;
101 blocked_core_registers_[arm::R7] = false;
102 }
103};
104#endif
105
106#ifdef ART_ENABLE_CODEGEN_x86
107class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
108 public:
109 TestCodeGeneratorX86(HGraph* graph,
110 const X86InstructionSetFeatures& isa_features,
111 const CompilerOptions& compiler_options)
112 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
113 // Save edi, we need it for getting enough registers for long multiplication.
114 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
115 }
116
117 void SetupBlockedRegisters() const OVERRIDE {
118 x86::CodeGeneratorX86::SetupBlockedRegisters();
119 // ebx is a callee-save register in C, but caller-save for ART.
120 blocked_core_registers_[x86::EBX] = true;
121
122 // Make edi available.
123 blocked_core_registers_[x86::EDI] = false;
124 }
125};
126#endif
127
128class InternalCodeAllocator : public CodeAllocator {
129 public:
130 InternalCodeAllocator() : size_(0) { }
131
132 virtual uint8_t* Allocate(size_t size) {
133 size_ = size;
134 memory_.reset(new uint8_t[size]);
135 return memory_.get();
136 }
137
138 size_t GetSize() const { return size_; }
139 uint8_t* GetMemory() const { return memory_.get(); }
140
141 private:
142 size_t size_;
143 std::unique_ptr<uint8_t[]> memory_;
144
145 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
146};
147
148static bool CanExecuteOnHardware(InstructionSet target_isa) {
149 return (target_isa == kRuntimeISA)
150 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
151 || (kRuntimeISA == kArm && target_isa == kThumb2);
152}
153
154static bool CanExecute(InstructionSet target_isa) {
155 CodeSimulatorContainer simulator(target_isa);
156 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
157}
158
159template <typename Expected>
160inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
161
162template <>
163inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
164 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
165 return simulator->GetCReturnBool();
166}
167
168template <>
169inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
170 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
171 return simulator->GetCReturnInt32();
172}
173
174template <>
175inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
176 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
177 return simulator->GetCReturnInt64();
178}
179
180template <typename Expected>
181static void VerifyGeneratedCode(InstructionSet target_isa,
182 Expected (*f)(),
183 bool has_result,
184 Expected expected) {
185 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
186
187 // Verify on simulator.
188 CodeSimulatorContainer simulator(target_isa);
189 if (simulator.CanSimulate()) {
190 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
191 if (has_result) {
192 ASSERT_EQ(expected, result);
193 }
194 }
195
196 // Verify on hardware.
197 if (CanExecuteOnHardware(target_isa)) {
198 Expected result = f();
199 if (has_result) {
200 ASSERT_EQ(expected, result);
201 }
202 }
203}
204
205template <typename Expected>
206static void Run(const InternalCodeAllocator& allocator,
207 const CodeGenerator& codegen,
208 bool has_result,
209 Expected expected) {
210 InstructionSet target_isa = codegen.GetInstructionSet();
211
212 typedef Expected (*fptr)();
213 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
214 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
215 if (target_isa == kThumb2) {
216 // For thumb we need the bottom bit set.
217 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
218 }
219 VerifyGeneratedCode(target_isa, f, has_result, expected);
220}
221
222static void ValidateGraph(HGraph* graph) {
223 GraphChecker graph_checker(graph);
224 graph_checker.Run();
225 if (!graph_checker.IsValid()) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +0100226 for (const std::string& error : graph_checker.GetErrors()) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100227 std::cout << error << std::endl;
228 }
229 }
230 ASSERT_TRUE(graph_checker.IsValid());
231}
232
233template <typename Expected>
234static void RunCodeNoCheck(CodeGenerator* codegen,
235 HGraph* graph,
236 const std::function<void(HGraph*)>& hook_before_codegen,
237 bool has_result,
238 Expected expected) {
239 SsaLivenessAnalysis liveness(graph, codegen);
240 PrepareForRegisterAllocation(graph).Run();
241 liveness.Analyze();
242 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
243 hook_before_codegen(graph);
244 InternalCodeAllocator allocator;
245 codegen->Compile(&allocator);
246 Run(allocator, *codegen, has_result, expected);
247}
248
249template <typename Expected>
250static void RunCode(CodeGenerator* codegen,
251 HGraph* graph,
252 std::function<void(HGraph*)> hook_before_codegen,
253 bool has_result,
254 Expected expected) {
255 ValidateGraph(graph);
256 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
257}
258
259template <typename Expected>
260static void RunCode(CodegenTargetConfig target_config,
261 HGraph* graph,
262 std::function<void(HGraph*)> hook_before_codegen,
263 bool has_result,
264 Expected expected) {
265 CompilerOptions compiler_options;
266 std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options));
267 RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
268}
269
270#ifdef ART_ENABLE_CODEGEN_arm
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100271CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
272 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
273 ArmInstructionSetFeatures::FromCppDefines());
274 return new (graph->GetArena())
275 TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
276}
277#endif
278
279#ifdef ART_ENABLE_CODEGEN_arm64
280CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
281 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
282 Arm64InstructionSetFeatures::FromCppDefines());
283 return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
284 *features_arm64.get(),
285 compiler_options);
286}
287#endif
288
289#ifdef ART_ENABLE_CODEGEN_x86
290CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
291 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
292 X86InstructionSetFeatures::FromCppDefines());
293 return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
294}
295#endif
296
297#ifdef ART_ENABLE_CODEGEN_x86_64
298CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
299 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
300 X86_64InstructionSetFeatures::FromCppDefines());
301 return new (graph->GetArena())
302 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
303}
304#endif
305
306#ifdef ART_ENABLE_CODEGEN_mips
307CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
308 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
309 MipsInstructionSetFeatures::FromCppDefines());
310 return new (graph->GetArena())
311 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
312}
313#endif
314
315#ifdef ART_ENABLE_CODEGEN_mips64
316CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
317 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
318 Mips64InstructionSetFeatures::FromCppDefines());
319 return new (graph->GetArena())
320 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
321}
322#endif
323
324} // namespace art
325
326#endif // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_