blob: 017117a83637f7266257ec4ce3c9142beeb1366f [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"
18#include "dex_file.h"
19#include "dex_instruction.h"
20#include "nodes.h"
21#include "optimizing_unit_test.h"
22#include "ssa_liveness_analysis.h"
23#include "utils/arena_allocator.h"
24
25#include "gtest/gtest.h"
26
27namespace art {
28
29static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
30 HGraphBuilder builder(allocator);
31 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
32 HGraph* graph = builder.BuildGraph(*item);
33 graph->BuildDominatorTree();
34 graph->TransformToSSA();
35 graph->FindNaturalLoops();
36 return graph;
37}
38
39TEST(LiveRangesTest, CFG1) {
40 /*
41 * Test the following snippet:
42 * return 0;
43 *
44 * Which becomes the following graph (numbered by lifetime position):
45 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010046 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010047 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010048 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010049 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010050 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010051 */
52 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
53 Instruction::CONST_4 | 0 | 0,
54 Instruction::RETURN);
55
56 ArenaPool pool;
57 ArenaAllocator allocator(&pool);
58 HGraph* graph = BuildGraph(data, &allocator);
59 SsaLivenessAnalysis liveness(*graph);
60 liveness.Analyze();
61
62 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010063 LiveRange* range = interval->GetFirstRange();
64 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010065 // Last use is the return instruction.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010066 ASSERT_EQ(8u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010067 HBasicBlock* block = graph->GetBlocks().Get(1);
68 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069 ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
70 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010071}
72
73TEST(LiveRangesTest, CFG2) {
74 /*
75 * Test the following snippet:
76 * var a = 0;
77 * if (0 == 0) {
78 * } else {
79 * }
80 * return a;
81 *
82 * Which becomes the following graph (numbered by lifetime position):
83 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010084 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010085 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010086 * 8: equal
87 * 10: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010088 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010089 * 14: goto 18: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010090 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010091 * 22: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010092 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093 * 26: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010094 */
95 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
96 Instruction::CONST_4 | 0 | 0,
97 Instruction::IF_EQ, 3,
98 Instruction::GOTO | 0x100,
99 Instruction::RETURN | 0 << 8);
100
101 ArenaPool pool;
102 ArenaAllocator allocator(&pool);
103 HGraph* graph = BuildGraph(data, &allocator);
104 SsaLivenessAnalysis liveness(*graph);
105 liveness.Analyze();
106
107 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100108 LiveRange* range = interval->GetFirstRange();
109 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100110 // Last use is the return instruction.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100111 ASSERT_EQ(22u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100112 HBasicBlock* block = graph->GetBlocks().Get(3);
113 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100114 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
115 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100116}
117
118TEST(LiveRangesTest, CFG3) {
119 /*
120 * Test the following snippet:
121 * var a = 0;
122 * if (0 == 0) {
123 * } else {
124 * a = 4;
125 * }
126 * return a;
127 *
128 * Which becomes the following graph (numbered by lifetime position):
129 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100130 * 4: constant4
131 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100132 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100133 * 10: equal
134 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100135 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100136 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100137 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100138 * 22: phi
139 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100140 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100141 * 38: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100142 */
143 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
144 Instruction::CONST_4 | 0 | 0,
145 Instruction::IF_EQ, 3,
146 Instruction::CONST_4 | 4 << 12 | 0,
147 Instruction::RETURN | 0 << 8);
148
149 ArenaPool pool;
150 ArenaAllocator allocator(&pool);
151 HGraph* graph = BuildGraph(data, &allocator);
152 SsaLivenessAnalysis liveness(*graph);
153 liveness.Analyze();
154
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100155 // Test for the 4 constant.
156 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100157 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100158 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100159 // Last use is the phi at the return block so instruction is live until
160 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100161 ASSERT_EQ(18u, range->GetEnd());
162 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100163
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100164 // Test for the 0 constant.
165 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100166 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167 // First range starts from the definition and ends at the if block.
168 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100169 ASSERT_EQ(2u, range->GetStart());
170 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100171 ASSERT_EQ(14u, range->GetEnd());
172 // Second range is the else block.
173 range = range->GetNext();
174 ASSERT_EQ(18u, range->GetStart());
175 // Last use is the phi at the return block.
176 ASSERT_EQ(22u, range->GetEnd());
177 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100178
179 // Test for the phi.
180 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100181 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100182 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(3)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100183 ASSERT_EQ(22u, range->GetStart());
184 ASSERT_EQ(24u, range->GetEnd());
185 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100186}
187
188TEST(LiveRangesTest, Loop) {
189 /*
190 * Test the following snippet:
191 * var a = 0;
192 * while (a == a) {
193 * a = 4;
194 * }
195 * return 5;
196 *
197 * Which becomes the following graph (numbered by lifetime position):
198 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100199 * 4: constant4
200 * 6: constant5
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100201 * 8: goto
202 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100203 * 12: goto
204 * |
205 * 14: phi
206 * 16: equal
207 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100208 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100209 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100210 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100211 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100212 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100213 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100214 */
215
216 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
217 Instruction::CONST_4 | 0 | 0,
218 Instruction::IF_EQ, 4,
219 Instruction::CONST_4 | 4 << 12 | 0,
220 Instruction::GOTO | 0xFD00,
221 Instruction::CONST_4 | 5 << 12 | 1 << 8,
222 Instruction::RETURN | 1 << 8);
223
224 ArenaPool pool;
225 ArenaAllocator allocator(&pool);
226 HGraph* graph = BuildGraph(data, &allocator);
227 SsaLivenessAnalysis liveness(*graph);
228 liveness.Analyze();
229
230 // Test for the 0 constant.
231 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100232 LiveRange* range = interval->GetFirstRange();
233 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100234 // Last use is the loop phi so instruction is live until
235 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100236 ASSERT_EQ(14u, range->GetEnd());
237 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100238
239 // Test for the 4 constant.
240 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100241 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100242 // The instruction is live until the end of the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100243 ASSERT_EQ(4u, range->GetStart());
244 ASSERT_EQ(24u, range->GetEnd());
245 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100246
247 // Test for the 5 constant.
248 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100249 range = interval->GetFirstRange();
250 // The instruction is live until the return instruction after the loop.
251 ASSERT_EQ(6u, range->GetStart());
252 ASSERT_EQ(26u, range->GetEnd());
253 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100254
255 // Test for the phi.
256 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100257 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100258 // Instruction is consumed by the if.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100259 ASSERT_EQ(14u, range->GetStart());
260 ASSERT_EQ(16u, range->GetEnd());
261 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100262}
263
264} // namespace art