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