blob: 8bb12de3874de82081ac1fce5d78762678eeeb8f [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 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
Nicolas Geoffray360231a2014-10-08 21:07:48 +010017#include <functional>
18
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000019#include "builder.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010020#include "code_generator_arm.h"
21#include "code_generator_x86.h"
22#include "code_generator_x86_64.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000023#include "common_compiler_test.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000024#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000025#include "dex_instruction.h"
26#include "instruction_set.h"
27#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000028#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010029#include "prepare_for_register_allocation.h"
30#include "register_allocator.h"
31#include "ssa_liveness_analysis.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032
33#include "gtest/gtest.h"
34
35namespace art {
36
Nicolas Geoffray787c3072014-03-17 10:20:19 +000037class InternalCodeAllocator : public CodeAllocator {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000038 public:
Nicolas Geoffray787c3072014-03-17 10:20:19 +000039 InternalCodeAllocator() { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040
41 virtual uint8_t* Allocate(size_t size) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000042 size_ = size;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000043 memory_.reset(new uint8_t[size]);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000044 return memory_.get();
45 }
46
Nicolas Geoffray787c3072014-03-17 10:20:19 +000047 size_t GetSize() const { return size_; }
48 uint8_t* GetMemory() const { return memory_.get(); }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000049
50 private:
Nicolas Geoffray787c3072014-03-17 10:20:19 +000051 size_t size_;
Ian Rogers700a4022014-05-19 16:49:03 -070052 std::unique_ptr<uint8_t[]> memory_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000053
Nicolas Geoffray787c3072014-03-17 10:20:19 +000054 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000055};
56
Nicolas Geoffray8d486732014-07-16 16:23:40 +010057static void Run(const InternalCodeAllocator& allocator,
58 const CodeGenerator& codegen,
59 bool has_result,
60 int32_t expected) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010061 typedef int32_t (*fptr)();
62 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
Dave Allison20dfc792014-06-16 20:44:29 -070063 fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
Nicolas Geoffray8d486732014-07-16 16:23:40 +010064 if (codegen.GetInstructionSet() == kThumb2) {
65 // For thumb we need the bottom bit set.
66 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
67 }
Dave Allison20dfc792014-06-16 20:44:29 -070068 int32_t result = f();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010069 if (has_result) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +010070 ASSERT_EQ(result, expected);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010071 }
72}
73
Nicolas Geoffray360231a2014-10-08 21:07:48 +010074static void RunCodeBaseline(HGraph* graph, bool has_result, int32_t expected) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +000075 InternalCodeAllocator allocator;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010076
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010077 x86::CodeGeneratorX86 codegenX86(graph);
Nicolas Geoffray73e80c32014-07-22 17:47:56 +010078 // We avoid doing a stack overflow check that requires the runtime being setup,
79 // by making sure the compiler knows the methods we are running are leaf methods.
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010080 codegenX86.CompileBaseline(&allocator, true);
81 if (kRuntimeISA == kX86) {
82 Run(allocator, codegenX86, has_result, expected);
83 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010084
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010085 arm::CodeGeneratorARM codegenARM(graph);
86 codegenARM.CompileBaseline(&allocator, true);
87 if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) {
88 Run(allocator, codegenARM, has_result, expected);
89 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010090
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010091 x86_64::CodeGeneratorX86_64 codegenX86_64(graph);
92 codegenX86_64.CompileBaseline(&allocator, true);
93 if (kRuntimeISA == kX86_64) {
94 Run(allocator, codegenX86_64, has_result, expected);
95 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000096}
97
Nicolas Geoffray360231a2014-10-08 21:07:48 +010098static void RunCodeOptimized(CodeGenerator* codegen,
99 HGraph* graph,
100 std::function<void(HGraph*)> hook_before_codegen,
101 bool has_result,
102 int32_t expected) {
103 SsaLivenessAnalysis liveness(*graph, codegen);
104 liveness.Analyze();
105
106 RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
107 register_allocator.AllocateRegisters();
108 hook_before_codegen(graph);
109
110 InternalCodeAllocator allocator;
111 codegen->CompileOptimized(&allocator);
112 Run(allocator, *codegen, has_result, expected);
113}
114
115static void RunCodeOptimized(HGraph* graph,
116 std::function<void(HGraph*)> hook_before_codegen,
117 bool has_result,
118 int32_t expected) {
119 if (kRuntimeISA == kX86) {
120 x86::CodeGeneratorX86 codegenX86(graph);
121 RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected);
122 } else if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) {
123 arm::CodeGeneratorARM codegenARM(graph);
124 RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected);
125 } else if (kRuntimeISA == kX86_64) {
126 x86_64::CodeGeneratorX86_64 codegenX86_64(graph);
127 RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
128 }
129}
130
131static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) {
132 ArenaPool pool;
133 ArenaAllocator arena(&pool);
134 HGraphBuilder builder(&arena);
135 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
136 HGraph* graph = builder.BuildGraph(*item);
137 // Remove suspend checks, they cannot be executed in this context.
138 RemoveSuspendChecks(graph);
139 ASSERT_NE(graph, nullptr);
140 RunCodeBaseline(graph, has_result, expected);
141}
142
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000143TEST(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000144 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
145 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000146}
147
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000148TEST(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000149 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000151 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000152
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000153 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000154}
155
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000156TEST(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000157 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000158 Instruction::GOTO | 0x100,
159 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000160 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000161
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000162 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000163}
164
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000165TEST(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000166 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000167 Instruction::GOTO | 0x200,
168 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000169 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000170
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000171 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000172
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000173 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000174 Instruction::GOTO_16, 3,
175 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000176 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000177
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000178 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000179
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000180 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000181 Instruction::GOTO_32, 4, 0,
182 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000183 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000184
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000185 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000186}
187
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000188TEST(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000189 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000190 Instruction::RETURN_VOID,
191 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000192 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000193
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000194 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000195}
196
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000197TEST(CodegenTest, CFG5) {
198 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
199 Instruction::CONST_4 | 0 | 0,
200 Instruction::IF_EQ, 3,
201 Instruction::GOTO | 0x100,
202 Instruction::RETURN_VOID);
203
204 TestCode(data);
205}
206
207TEST(CodegenTest, IntConstant) {
208 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
209 Instruction::CONST_4 | 0 | 0,
210 Instruction::RETURN_VOID);
211
212 TestCode(data);
213}
214
215TEST(CodegenTest, Return1) {
216 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
217 Instruction::CONST_4 | 0 | 0,
218 Instruction::RETURN | 0);
219
220 TestCode(data, true, 0);
221}
222
223TEST(CodegenTest, Return2) {
224 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
225 Instruction::CONST_4 | 0 | 0,
226 Instruction::CONST_4 | 0 | 1 << 8,
227 Instruction::RETURN | 1 << 8);
228
229 TestCode(data, true, 0);
230}
231
232TEST(CodegenTest, Return3) {
233 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
234 Instruction::CONST_4 | 0 | 0,
235 Instruction::CONST_4 | 1 << 8 | 1 << 12,
236 Instruction::RETURN | 1 << 8);
237
238 TestCode(data, true, 1);
239}
240
241TEST(CodegenTest, ReturnIf1) {
242 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
243 Instruction::CONST_4 | 0 | 0,
244 Instruction::CONST_4 | 1 << 8 | 1 << 12,
245 Instruction::IF_EQ, 3,
246 Instruction::RETURN | 0 << 8,
247 Instruction::RETURN | 1 << 8);
248
249 TestCode(data, true, 1);
250}
251
252TEST(CodegenTest, ReturnIf2) {
253 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
254 Instruction::CONST_4 | 0 | 0,
255 Instruction::CONST_4 | 1 << 8 | 1 << 12,
256 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
257 Instruction::RETURN | 0 << 8,
258 Instruction::RETURN | 1 << 8);
259
260 TestCode(data, true, 0);
261}
262
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000263TEST(CodegenTest, ReturnAdd1) {
264 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
265 Instruction::CONST_4 | 3 << 12 | 0,
266 Instruction::CONST_4 | 4 << 12 | 1 << 8,
267 Instruction::ADD_INT, 1 << 8 | 0,
268 Instruction::RETURN);
269
270 TestCode(data, true, 7);
271}
272
273TEST(CodegenTest, ReturnAdd2) {
274 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
275 Instruction::CONST_4 | 3 << 12 | 0,
276 Instruction::CONST_4 | 4 << 12 | 1 << 8,
277 Instruction::ADD_INT_2ADDR | 1 << 12,
278 Instruction::RETURN);
279
280 TestCode(data, true, 7);
281}
282
283TEST(CodegenTest, ReturnAdd3) {
284 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
285 Instruction::CONST_4 | 4 << 12 | 0 << 8,
286 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
287 Instruction::RETURN);
288
289 TestCode(data, true, 7);
290}
291
292TEST(CodegenTest, ReturnAdd4) {
293 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
294 Instruction::CONST_4 | 4 << 12 | 0 << 8,
295 Instruction::ADD_INT_LIT16, 3,
296 Instruction::RETURN);
297
298 TestCode(data, true, 7);
299}
300
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100301TEST(CodegenTest, NonMaterializedCondition) {
302 ArenaPool pool;
303 ArenaAllocator allocator(&pool);
304
305 HGraph* graph = new (&allocator) HGraph(&allocator);
306 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
307 graph->AddBlock(entry);
308 graph->SetEntryBlock(entry);
309 entry->AddInstruction(new (&allocator) HGoto());
310
311 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
312 graph->AddBlock(first_block);
313 entry->AddSuccessor(first_block);
314 HIntConstant* constant0 = new (&allocator) HIntConstant(0);
315 entry->AddInstruction(constant0);
316 HIntConstant* constant1 = new (&allocator) HIntConstant(1);
317 entry->AddInstruction(constant1);
318 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
319 first_block->AddInstruction(equal);
320 first_block->AddInstruction(new (&allocator) HIf(equal));
321
322 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
323 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
324 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
325
326 graph->AddBlock(then);
327 graph->AddBlock(else_);
328 graph->AddBlock(exit);
329 first_block->AddSuccessor(then);
330 first_block->AddSuccessor(else_);
331 then->AddSuccessor(exit);
332 else_->AddSuccessor(exit);
333
334 exit->AddInstruction(new (&allocator) HExit());
335 then->AddInstruction(new (&allocator) HReturn(constant0));
336 else_->AddInstruction(new (&allocator) HReturn(constant1));
337
338 ASSERT_TRUE(equal->NeedsMaterialization());
339 graph->BuildDominatorTree();
340 PrepareForRegisterAllocation(graph).Run();
341 ASSERT_FALSE(equal->NeedsMaterialization());
342
343 auto hook_before_codegen = [](HGraph* graph) {
344 HBasicBlock* block = graph->GetEntryBlock()->GetSuccessors().Get(0);
345 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
346 block->InsertInstructionBefore(move, block->GetLastInstruction());
347 };
348
349 RunCodeOptimized(graph, hook_before_codegen, true, 0);
350}
351
Calin Juravle34bacdf2014-10-07 20:23:36 +0100352#define MUL_TEST(TYPE, TEST_NAME) \
353 TEST(CodegenTest, Return ## TEST_NAME) { \
354 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
355 Instruction::CONST_4 | 3 << 12 | 0, \
356 Instruction::CONST_4 | 4 << 12 | 1 << 8, \
357 Instruction::MUL_ ## TYPE, 1 << 8 | 0, \
358 Instruction::RETURN); \
359 \
360 TestCode(data, true, 12); \
361 } \
362 \
363 TEST(CodegenTest, Return ## TEST_NAME ## 2addr) { \
364 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
365 Instruction::CONST_4 | 3 << 12 | 0, \
366 Instruction::CONST_4 | 4 << 12 | 1 << 8, \
367 Instruction::MUL_ ## TYPE ## _2ADDR | 1 << 12, \
368 Instruction::RETURN); \
369 \
370 TestCode(data, true, 12); \
371 }
372
373MUL_TEST(INT, MulInt);
374MUL_TEST(LONG, MulLong);
375// MUL_TEST(FLOAT, Float);
376// MUL_TEST(DOUBLE, Double);
377
378TEST(CodegenTest, ReturnMulIntLit8) {
379 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
380 Instruction::CONST_4 | 4 << 12 | 0 << 8,
381 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
382 Instruction::RETURN);
383
384 TestCode(data, true, 12);
385}
386
387TEST(CodegenTest, ReturnMulIntLit16) {
388 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
389 Instruction::CONST_4 | 4 << 12 | 0 << 8,
390 Instruction::MUL_INT_LIT16, 3,
391 Instruction::RETURN);
392
393 TestCode(data, true, 12);
394}
395
396
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000397} // namespace art