blob: 792cfb539a620ba47de8726114efdce5929479c9 [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
Roland Levillain5daa4952017-07-03 17:23:56 +010082// Special ARM code generator for codegen testing in a limited code
83// generation environment (i.e. with no runtime support).
84//
85// Note: If we want to exercise certains HIR constructions
86// (e.g. reference field load in Baker read barrier configuration) in
87// codegen tests in the future, we should also:
88// - save the Thread Register (R9) and possibly the Marking Register
89// (R8) before entering the generated function (both registers are
90// callee-save in AAPCS);
91// - set these registers to meaningful values before or upon entering
92// the generated function (so that generated code using them is
93// correct);
94// - restore their original values before leaving the generated
95// function.
96
Alexandre Rames22aa54b2016-10-18 09:32:29 +010097// Provide our own codegen, that ensures the C calling conventions
98// are preserved. Currently, ART and C do not match as R4 is caller-save
99// in ART, and callee-save in C. Alternatively, we could use or write
100// the stub that saves and restores all registers, but it is easier
101// to just overwrite the code generator.
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100102class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
103 public:
104 TestCodeGeneratorARMVIXL(HGraph* graph,
105 const ArmInstructionSetFeatures& isa_features,
106 const CompilerOptions& compiler_options)
107 : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
108 AddAllocatedRegister(Location::RegisterLocation(arm::R6));
109 AddAllocatedRegister(Location::RegisterLocation(arm::R7));
110 }
111
112 void SetupBlockedRegisters() const OVERRIDE {
113 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
114 blocked_core_registers_[arm::R4] = true;
115 blocked_core_registers_[arm::R6] = false;
116 blocked_core_registers_[arm::R7] = false;
117 }
Roland Levillain5daa4952017-07-03 17:23:56 +0100118
119 void MaybeGenerateMarkingRegisterCheck(int code ATTRIBUTE_UNUSED,
120 Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE {
121 // When turned on, the marking register checks in
122 // CodeGeneratorARMVIXL::MaybeGenerateMarkingRegisterCheck expects the
123 // Thread Register and the Marking Register to be set to
124 // meaningful values. This is not the case in codegen testing, so
125 // just disable them entirely here (by doing nothing in this
126 // method).
127 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100128};
129#endif
130
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100131#ifdef ART_ENABLE_CODEGEN_arm64
132// Special ARM64 code generator for codegen testing in a limited code
133// generation environment (i.e. with no runtime support).
134//
135// Note: If we want to exercise certains HIR constructions
136// (e.g. reference field load in Baker read barrier configuration) in
137// codegen tests in the future, we should also:
138// - save the Thread Register (X19) and possibly the Marking Register
139// (X20) before entering the generated function (both registers are
140// callee-save in AAPCS64);
141// - set these registers to meaningful values before or upon entering
142// the generated function (so that generated code using them is
143// correct);
144// - restore their original values before leaving the generated
145// function.
146class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 {
147 public:
148 TestCodeGeneratorARM64(HGraph* graph,
149 const Arm64InstructionSetFeatures& isa_features,
150 const CompilerOptions& compiler_options)
151 : arm64::CodeGeneratorARM64(graph, isa_features, compiler_options) {}
152
153 void MaybeGenerateMarkingRegisterCheck(int codem ATTRIBUTE_UNUSED,
154 Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE {
155 // When turned on, the marking register checks in
156 // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck expect the
157 // Thread Register and the Marking Register to be set to
158 // meaningful values. This is not the case in codegen testing, so
159 // just disable them entirely here (by doing nothing in this
160 // method).
161 }
162};
163#endif
164
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100165#ifdef ART_ENABLE_CODEGEN_x86
166class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
167 public:
168 TestCodeGeneratorX86(HGraph* graph,
169 const X86InstructionSetFeatures& isa_features,
170 const CompilerOptions& compiler_options)
171 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
172 // Save edi, we need it for getting enough registers for long multiplication.
173 AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
174 }
175
176 void SetupBlockedRegisters() const OVERRIDE {
177 x86::CodeGeneratorX86::SetupBlockedRegisters();
178 // ebx is a callee-save register in C, but caller-save for ART.
179 blocked_core_registers_[x86::EBX] = true;
180
181 // Make edi available.
182 blocked_core_registers_[x86::EDI] = false;
183 }
184};
185#endif
186
187class InternalCodeAllocator : public CodeAllocator {
188 public:
189 InternalCodeAllocator() : size_(0) { }
190
191 virtual uint8_t* Allocate(size_t size) {
192 size_ = size;
193 memory_.reset(new uint8_t[size]);
194 return memory_.get();
195 }
196
197 size_t GetSize() const { return size_; }
Vladimir Markoca1e0382018-04-11 09:58:41 +0000198 ArrayRef<const uint8_t> GetMemory() const OVERRIDE {
199 return ArrayRef<const uint8_t>(memory_.get(), size_);
200 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100201
202 private:
203 size_t size_;
204 std::unique_ptr<uint8_t[]> memory_;
205
206 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
207};
208
209static bool CanExecuteOnHardware(InstructionSet target_isa) {
210 return (target_isa == kRuntimeISA)
211 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
Vladimir Marko33bff252017-11-01 14:35:42 +0000212 || (kRuntimeISA == InstructionSet::kArm && target_isa == InstructionSet::kThumb2);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100213}
214
215static bool CanExecute(InstructionSet target_isa) {
216 CodeSimulatorContainer simulator(target_isa);
217 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
218}
219
220template <typename Expected>
221inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
222
223template <>
224inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
225 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
226 return simulator->GetCReturnBool();
227}
228
229template <>
230inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
231 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
232 return simulator->GetCReturnInt32();
233}
234
235template <>
236inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
237 simulator->RunFrom(reinterpret_cast<intptr_t>(f));
238 return simulator->GetCReturnInt64();
239}
240
241template <typename Expected>
242static void VerifyGeneratedCode(InstructionSet target_isa,
243 Expected (*f)(),
244 bool has_result,
245 Expected expected) {
246 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
247
248 // Verify on simulator.
249 CodeSimulatorContainer simulator(target_isa);
250 if (simulator.CanSimulate()) {
251 Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
252 if (has_result) {
253 ASSERT_EQ(expected, result);
254 }
255 }
256
257 // Verify on hardware.
258 if (CanExecuteOnHardware(target_isa)) {
259 Expected result = f();
260 if (has_result) {
261 ASSERT_EQ(expected, result);
262 }
263 }
264}
265
266template <typename Expected>
267static void Run(const InternalCodeAllocator& allocator,
268 const CodeGenerator& codegen,
269 bool has_result,
270 Expected expected) {
271 InstructionSet target_isa = codegen.GetInstructionSet();
272
273 typedef Expected (*fptr)();
Vladimir Markoca1e0382018-04-11 09:58:41 +0000274 CommonCompilerTest::MakeExecutable(allocator.GetMemory().data(), allocator.GetMemory().size());
275 fptr f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(allocator.GetMemory().data()));
Vladimir Marko33bff252017-11-01 14:35:42 +0000276 if (target_isa == InstructionSet::kThumb2) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100277 // For thumb we need the bottom bit set.
278 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
279 }
280 VerifyGeneratedCode(target_isa, f, has_result, expected);
281}
282
283static void ValidateGraph(HGraph* graph) {
284 GraphChecker graph_checker(graph);
285 graph_checker.Run();
286 if (!graph_checker.IsValid()) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +0100287 for (const std::string& error : graph_checker.GetErrors()) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100288 std::cout << error << std::endl;
289 }
290 }
291 ASSERT_TRUE(graph_checker.IsValid());
292}
293
294template <typename Expected>
295static void RunCodeNoCheck(CodeGenerator* codegen,
296 HGraph* graph,
297 const std::function<void(HGraph*)>& hook_before_codegen,
298 bool has_result,
299 Expected expected) {
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100300 {
301 ScopedArenaAllocator local_allocator(graph->GetArenaStack());
302 SsaLivenessAnalysis liveness(graph, codegen, &local_allocator);
303 PrepareForRegisterAllocation(graph).Run();
304 liveness.Analyze();
305 std::unique_ptr<RegisterAllocator> register_allocator =
306 RegisterAllocator::Create(&local_allocator, codegen, liveness);
307 register_allocator->AllocateRegisters();
308 }
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100309 hook_before_codegen(graph);
310 InternalCodeAllocator allocator;
311 codegen->Compile(&allocator);
312 Run(allocator, *codegen, has_result, expected);
313}
314
315template <typename Expected>
316static void RunCode(CodeGenerator* codegen,
317 HGraph* graph,
318 std::function<void(HGraph*)> hook_before_codegen,
319 bool has_result,
320 Expected expected) {
321 ValidateGraph(graph);
322 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
323}
324
325template <typename Expected>
326static void RunCode(CodegenTargetConfig target_config,
327 HGraph* graph,
328 std::function<void(HGraph*)> hook_before_codegen,
329 bool has_result,
330 Expected expected) {
331 CompilerOptions compiler_options;
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100332 std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph,
333 compiler_options));
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100334 RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
335}
336
337#ifdef ART_ENABLE_CODEGEN_arm
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100338CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
339 std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
340 ArmInstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100341 return new (graph->GetAllocator())
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100342 TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
343}
344#endif
345
346#ifdef ART_ENABLE_CODEGEN_arm64
347CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
348 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
349 Arm64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100350 return new (graph->GetAllocator())
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100351 TestCodeGeneratorARM64(graph, *features_arm64.get(), compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100352}
353#endif
354
355#ifdef ART_ENABLE_CODEGEN_x86
356CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
357 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
358 X86InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100359 return new (graph->GetAllocator()) TestCodeGeneratorX86(
360 graph, *features_x86.get(), compiler_options);
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100361}
362#endif
363
364#ifdef ART_ENABLE_CODEGEN_x86_64
365CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
366 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
367 X86_64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100368 return new (graph->GetAllocator())
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100369 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
370}
371#endif
372
373#ifdef ART_ENABLE_CODEGEN_mips
374CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
375 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
376 MipsInstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100377 return new (graph->GetAllocator())
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100378 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
379}
380#endif
381
382#ifdef ART_ENABLE_CODEGEN_mips64
383CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
384 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
385 Mips64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100386 return new (graph->GetAllocator())
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100387 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
388}
389#endif
390
391} // namespace art
392
393#endif // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_