blob: c7974975814ebb4fb4f12d7c271ab2a1432b0449 [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
155 // Test for the 0 constant.
156 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100157 LiveRange* range = interval->GetFirstRange();
158 ASSERT_EQ(2u, 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
164 // Test for the 4 constant.
165 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
166 // 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();
169 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100170 // 9 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();
182 ASSERT_EQ(22u, range->GetStart());
183 ASSERT_EQ(24u, range->GetEnd());
184 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100185}
186
187TEST(LiveRangesTest, Loop) {
188 /*
189 * Test the following snippet:
190 * var a = 0;
191 * while (a == a) {
192 * a = 4;
193 * }
194 * return 5;
195 *
196 * Which becomes the following graph (numbered by lifetime position):
197 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100198 * 4: constant4
199 * 6: constant5
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100200 * 8: goto
201 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100202 * 12: goto
203 * |
204 * 14: phi
205 * 16: equal
206 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100207 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100208 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100209 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100210 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100211 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100212 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100213 */
214
215 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
216 Instruction::CONST_4 | 0 | 0,
217 Instruction::IF_EQ, 4,
218 Instruction::CONST_4 | 4 << 12 | 0,
219 Instruction::GOTO | 0xFD00,
220 Instruction::CONST_4 | 5 << 12 | 1 << 8,
221 Instruction::RETURN | 1 << 8);
222
223 ArenaPool pool;
224 ArenaAllocator allocator(&pool);
225 HGraph* graph = BuildGraph(data, &allocator);
226 SsaLivenessAnalysis liveness(*graph);
227 liveness.Analyze();
228
229 // Test for the 0 constant.
230 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100231 LiveRange* range = interval->GetFirstRange();
232 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100233 // Last use is the loop phi so instruction is live until
234 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100235 ASSERT_EQ(14u, range->GetEnd());
236 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100237
238 // Test for the 4 constant.
239 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100240 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100241 // The instruction is live until the end of the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242 ASSERT_EQ(4u, range->GetStart());
243 ASSERT_EQ(24u, range->GetEnd());
244 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100245
246 // Test for the 5 constant.
247 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100248 range = interval->GetFirstRange();
249 // The instruction is live until the return instruction after the loop.
250 ASSERT_EQ(6u, range->GetStart());
251 ASSERT_EQ(26u, range->GetEnd());
252 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100253
254 // Test for the phi.
255 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100256 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100257 // Instruction is consumed by the if.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100258 ASSERT_EQ(14u, range->GetStart());
259 ASSERT_EQ(16u, range->GetEnd());
260 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100261}
262
263} // namespace art