blob: 29ad3de6b3be2a5d9d5527124396d872bed0ce1e [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);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100137 ASSERT_NE(graph, nullptr);
Calin Juravle039b6e22014-10-23 12:32:11 +0100138 // Remove suspend checks, they cannot be executed in this context.
Calin Juravle48dee042014-10-22 15:54:12 +0100139 RemoveSuspendChecks(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100140 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
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100263// Exercise bit-wise (one's complement) not-int instruction.
264#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
265TEST(CodegenTest, TEST_NAME) { \
266 const int32_t input = INPUT; \
267 const uint16_t input_lo = input & 0x0000FFFF; \
268 const uint16_t input_hi = input >> 16; \
269 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
270 Instruction::CONST | 0 << 8, input_lo, input_hi, \
271 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
272 Instruction::RETURN | 1 << 8); \
273 \
274 TestCode(data, true, EXPECTED_OUTPUT); \
275}
276
277NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
278NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
279NOT_INT_TEST(ReturnNotInt0, 0, -1)
280NOT_INT_TEST(ReturnNotInt1, 1, -2)
281NOT_INT_TEST(ReturnNotIntINT_MIN, -2147483648, 2147483647) // (2^31) - 1
282NOT_INT_TEST(ReturnNotIntINT_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
283NOT_INT_TEST(ReturnNotIntINT_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
284NOT_INT_TEST(ReturnNotIntINT_MAX, 2147483647, -2147483648) // -(2^31)
285
286#undef NOT_INT_TEST
287
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000288TEST(CodegenTest, ReturnAdd1) {
289 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
290 Instruction::CONST_4 | 3 << 12 | 0,
291 Instruction::CONST_4 | 4 << 12 | 1 << 8,
292 Instruction::ADD_INT, 1 << 8 | 0,
293 Instruction::RETURN);
294
295 TestCode(data, true, 7);
296}
297
298TEST(CodegenTest, ReturnAdd2) {
299 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
300 Instruction::CONST_4 | 3 << 12 | 0,
301 Instruction::CONST_4 | 4 << 12 | 1 << 8,
302 Instruction::ADD_INT_2ADDR | 1 << 12,
303 Instruction::RETURN);
304
305 TestCode(data, true, 7);
306}
307
308TEST(CodegenTest, ReturnAdd3) {
309 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
310 Instruction::CONST_4 | 4 << 12 | 0 << 8,
311 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
312 Instruction::RETURN);
313
314 TestCode(data, true, 7);
315}
316
317TEST(CodegenTest, ReturnAdd4) {
318 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
319 Instruction::CONST_4 | 4 << 12 | 0 << 8,
320 Instruction::ADD_INT_LIT16, 3,
321 Instruction::RETURN);
322
323 TestCode(data, true, 7);
324}
325
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100326TEST(CodegenTest, NonMaterializedCondition) {
327 ArenaPool pool;
328 ArenaAllocator allocator(&pool);
329
330 HGraph* graph = new (&allocator) HGraph(&allocator);
331 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
332 graph->AddBlock(entry);
333 graph->SetEntryBlock(entry);
334 entry->AddInstruction(new (&allocator) HGoto());
335
336 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
337 graph->AddBlock(first_block);
338 entry->AddSuccessor(first_block);
339 HIntConstant* constant0 = new (&allocator) HIntConstant(0);
340 entry->AddInstruction(constant0);
341 HIntConstant* constant1 = new (&allocator) HIntConstant(1);
342 entry->AddInstruction(constant1);
343 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
344 first_block->AddInstruction(equal);
345 first_block->AddInstruction(new (&allocator) HIf(equal));
346
347 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
348 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
349 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
350
351 graph->AddBlock(then);
352 graph->AddBlock(else_);
353 graph->AddBlock(exit);
354 first_block->AddSuccessor(then);
355 first_block->AddSuccessor(else_);
356 then->AddSuccessor(exit);
357 else_->AddSuccessor(exit);
358
359 exit->AddInstruction(new (&allocator) HExit());
360 then->AddInstruction(new (&allocator) HReturn(constant0));
361 else_->AddInstruction(new (&allocator) HReturn(constant1));
362
363 ASSERT_TRUE(equal->NeedsMaterialization());
364 graph->BuildDominatorTree();
365 PrepareForRegisterAllocation(graph).Run();
366 ASSERT_FALSE(equal->NeedsMaterialization());
367
368 auto hook_before_codegen = [](HGraph* graph) {
369 HBasicBlock* block = graph->GetEntryBlock()->GetSuccessors().Get(0);
370 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
371 block->InsertInstructionBefore(move, block->GetLastInstruction());
372 };
373
374 RunCodeOptimized(graph, hook_before_codegen, true, 0);
375}
376
Calin Juravle34bacdf2014-10-07 20:23:36 +0100377#define MUL_TEST(TYPE, TEST_NAME) \
378 TEST(CodegenTest, Return ## TEST_NAME) { \
379 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
380 Instruction::CONST_4 | 3 << 12 | 0, \
381 Instruction::CONST_4 | 4 << 12 | 1 << 8, \
382 Instruction::MUL_ ## TYPE, 1 << 8 | 0, \
383 Instruction::RETURN); \
384 \
385 TestCode(data, true, 12); \
386 } \
387 \
388 TEST(CodegenTest, Return ## TEST_NAME ## 2addr) { \
389 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
390 Instruction::CONST_4 | 3 << 12 | 0, \
391 Instruction::CONST_4 | 4 << 12 | 1 << 8, \
392 Instruction::MUL_ ## TYPE ## _2ADDR | 1 << 12, \
393 Instruction::RETURN); \
394 \
395 TestCode(data, true, 12); \
396 }
397
398MUL_TEST(INT, MulInt);
399MUL_TEST(LONG, MulLong);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100400
401TEST(CodegenTest, ReturnMulIntLit8) {
402 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
403 Instruction::CONST_4 | 4 << 12 | 0 << 8,
404 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
405 Instruction::RETURN);
406
407 TestCode(data, true, 12);
408}
409
410TEST(CodegenTest, ReturnMulIntLit16) {
411 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
412 Instruction::CONST_4 | 4 << 12 | 0 << 8,
413 Instruction::MUL_INT_LIT16, 3,
414 Instruction::RETURN);
415
416 TestCode(data, true, 12);
417}
418
419
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000420} // namespace art