blob: 987c5f27b7e09a8c9bd6a77ec86910feb784bdc6 [file] [log] [blame]
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001/*
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
17#include "builder.h"
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010018#include "code_generator.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010019#include "dex_file.h"
20#include "dex_instruction.h"
21#include "nodes.h"
22#include "optimizing_unit_test.h"
23#include "ssa_liveness_analysis.h"
24#include "utils/arena_allocator.h"
25
26#include "gtest/gtest.h"
27
28namespace art {
29
30static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
31 HGraphBuilder builder(allocator);
32 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
33 HGraph* graph = builder.BuildGraph(*item);
34 graph->BuildDominatorTree();
35 graph->TransformToSSA();
36 graph->FindNaturalLoops();
37 return graph;
38}
39
40TEST(LiveRangesTest, CFG1) {
41 /*
42 * Test the following snippet:
43 * return 0;
44 *
45 * Which becomes the following graph (numbered by lifetime position):
46 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010047 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010048 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010049 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010050 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010051 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010052 */
53 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
54 Instruction::CONST_4 | 0 | 0,
55 Instruction::RETURN);
56
57 ArenaPool pool;
58 ArenaAllocator allocator(&pool);
59 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010060
61 CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, InstructionSet::kX86);
62 SsaLivenessAnalysis liveness(*graph, codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010063 liveness.Analyze();
64
65 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010066 LiveRange* range = interval->GetFirstRange();
67 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010068 // Last use is the return instruction.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010069 ASSERT_EQ(9u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010070 HBasicBlock* block = graph->GetBlocks().Get(1);
71 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010072 ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
73 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010074}
75
76TEST(LiveRangesTest, CFG2) {
77 /*
78 * Test the following snippet:
79 * var a = 0;
80 * if (0 == 0) {
81 * } else {
82 * }
83 * return a;
84 *
85 * Which becomes the following graph (numbered by lifetime position):
86 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010087 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010088 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010089 * 8: equal
90 * 10: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010091 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010092 * 14: goto 18: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010093 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010094 * 22: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010095 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010096 * 26: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010097 */
98 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
99 Instruction::CONST_4 | 0 | 0,
100 Instruction::IF_EQ, 3,
101 Instruction::GOTO | 0x100,
102 Instruction::RETURN | 0 << 8);
103
104 ArenaPool pool;
105 ArenaAllocator allocator(&pool);
106 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100107 CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, InstructionSet::kX86);
108 SsaLivenessAnalysis liveness(*graph, codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100109 liveness.Analyze();
110
111 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100112 LiveRange* range = interval->GetFirstRange();
113 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100114 // Last use is the return instruction.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100115 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100116 HBasicBlock* block = graph->GetBlocks().Get(3);
117 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
119 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100120}
121
122TEST(LiveRangesTest, CFG3) {
123 /*
124 * Test the following snippet:
125 * var a = 0;
126 * if (0 == 0) {
127 * } else {
128 * a = 4;
129 * }
130 * return a;
131 *
132 * Which becomes the following graph (numbered by lifetime position):
133 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100134 * 4: constant4
135 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100136 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100137 * 10: equal
138 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100139 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100140 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100141 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 * 22: phi
143 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100144 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 * 38: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100146 */
147 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
148 Instruction::CONST_4 | 0 | 0,
149 Instruction::IF_EQ, 3,
150 Instruction::CONST_4 | 4 << 12 | 0,
151 Instruction::RETURN | 0 << 8);
152
153 ArenaPool pool;
154 ArenaAllocator allocator(&pool);
155 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100156 CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, InstructionSet::kX86);
157 SsaLivenessAnalysis liveness(*graph, codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100158 liveness.Analyze();
159
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100160 // Test for the 4 constant.
161 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100162 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100163 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100164 // Last use is the phi at the return block so instruction is live until
165 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100166 ASSERT_EQ(18u, range->GetEnd());
167 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100168
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100169 // Test for the 0 constant.
170 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100171 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100172 // First range starts from the definition and ends at the if block.
173 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100174 ASSERT_EQ(2u, range->GetStart());
175 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100176 ASSERT_EQ(14u, range->GetEnd());
177 // Second range is the else block.
178 range = range->GetNext();
179 ASSERT_EQ(18u, range->GetStart());
180 // Last use is the phi at the return block.
181 ASSERT_EQ(22u, range->GetEnd());
182 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100183
184 // Test for the phi.
185 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100186 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100187 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(3)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100188 ASSERT_EQ(22u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100189 ASSERT_EQ(25u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100190 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100191}
192
193TEST(LiveRangesTest, Loop) {
194 /*
195 * Test the following snippet:
196 * var a = 0;
197 * while (a == a) {
198 * a = 4;
199 * }
200 * return 5;
201 *
202 * Which becomes the following graph (numbered by lifetime position):
203 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100204 * 4: constant4
205 * 6: constant5
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100206 * 8: goto
207 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100208 * 12: goto
209 * |
210 * 14: phi
211 * 16: equal
212 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100213 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100214 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100215 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100216 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100217 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100218 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100219 */
220
221 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
222 Instruction::CONST_4 | 0 | 0,
223 Instruction::IF_EQ, 4,
224 Instruction::CONST_4 | 4 << 12 | 0,
225 Instruction::GOTO | 0xFD00,
226 Instruction::CONST_4 | 5 << 12 | 1 << 8,
227 Instruction::RETURN | 1 << 8);
228
229 ArenaPool pool;
230 ArenaAllocator allocator(&pool);
231 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100232 CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, InstructionSet::kX86);
233 SsaLivenessAnalysis liveness(*graph, codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100234 liveness.Analyze();
235
236 // Test for the 0 constant.
237 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100238 LiveRange* range = interval->GetFirstRange();
239 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100240 // Last use is the loop phi so instruction is live until
241 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242 ASSERT_EQ(14u, range->GetEnd());
243 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100244
245 // Test for the 4 constant.
246 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100247 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100248 // The instruction is live until the end of the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100249 ASSERT_EQ(4u, range->GetStart());
250 ASSERT_EQ(24u, range->GetEnd());
251 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100252
253 // Test for the 5 constant.
254 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 range = interval->GetFirstRange();
256 // The instruction is live until the return instruction after the loop.
257 ASSERT_EQ(6u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100258 ASSERT_EQ(27u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100259 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100260
261 // Test for the phi.
262 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100264 // Instruction is consumed by the if.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100265 ASSERT_EQ(14u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100266 ASSERT_EQ(17u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100267 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100268}
269
270} // namespace art