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