blob: 21e634de04b12997c3a978978a91735c3e7d7bb4 [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 Geoffray8a16d972014-09-11 10:30:02 +010019#include "code_generator_x86.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010020#include "dex_file.h"
21#include "dex_instruction.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24#include "ssa_liveness_analysis.h"
25#include "utils/arena_allocator.h"
26
27#include "gtest/gtest.h"
28
29namespace art {
30
31static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
32 HGraphBuilder builder(allocator);
33 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
34 HGraph* graph = builder.BuildGraph(*item);
35 graph->BuildDominatorTree();
36 graph->TransformToSSA();
37 graph->FindNaturalLoops();
38 return graph;
39}
40
41TEST(LiveRangesTest, CFG1) {
42 /*
43 * Test the following snippet:
44 * return 0;
45 *
46 * Which becomes the following graph (numbered by lifetime position):
47 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010048 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010049 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010050 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010051 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010052 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010053 */
54 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
55 Instruction::CONST_4 | 0 | 0,
56 Instruction::RETURN);
57
58 ArenaPool pool;
59 ArenaAllocator allocator(&pool);
60 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010061
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010062 x86::CodeGeneratorX86 codegen(graph);
63 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010064 liveness.Analyze();
65
66 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010067 LiveRange* range = interval->GetFirstRange();
68 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010069 // Last use is the return instruction.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010070 ASSERT_EQ(9u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010071 HBasicBlock* block = graph->GetBlocks().Get(1);
72 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010073 ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
74 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010075}
76
77TEST(LiveRangesTest, CFG2) {
78 /*
79 * Test the following snippet:
80 * var a = 0;
81 * if (0 == 0) {
82 * } else {
83 * }
84 * return a;
85 *
86 * Which becomes the following graph (numbered by lifetime position):
87 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010088 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010089 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010090 * 8: equal
91 * 10: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010092 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093 * 14: goto 18: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010094 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010095 * 22: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010096 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010097 * 26: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010098 */
99 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
100 Instruction::CONST_4 | 0 | 0,
101 Instruction::IF_EQ, 3,
102 Instruction::GOTO | 0x100,
103 Instruction::RETURN | 0 << 8);
104
105 ArenaPool pool;
106 ArenaAllocator allocator(&pool);
107 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100108 x86::CodeGeneratorX86 codegen(graph);
109 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100110 liveness.Analyze();
111
112 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100113 LiveRange* range = interval->GetFirstRange();
114 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100115 // Last use is the return instruction.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100116 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100117 HBasicBlock* block = graph->GetBlocks().Get(3);
118 ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100119 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
120 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100121}
122
123TEST(LiveRangesTest, CFG3) {
124 /*
125 * Test the following snippet:
126 * var a = 0;
127 * if (0 == 0) {
128 * } else {
129 * a = 4;
130 * }
131 * return a;
132 *
133 * Which becomes the following graph (numbered by lifetime position):
134 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100135 * 4: constant4
136 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100137 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100138 * 10: equal
139 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100140 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100141 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100142 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100143 * 22: phi
144 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100145 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100146 * 38: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100147 */
148 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
149 Instruction::CONST_4 | 0 | 0,
150 Instruction::IF_EQ, 3,
151 Instruction::CONST_4 | 4 << 12 | 0,
152 Instruction::RETURN | 0 << 8);
153
154 ArenaPool pool;
155 ArenaAllocator allocator(&pool);
156 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100157 x86::CodeGeneratorX86 codegen(graph);
158 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100159 liveness.Analyze();
160
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100161 // Test for the 4 constant.
162 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100163 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100164 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100165 // Last use is the phi at the return block so instruction is live until
166 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167 ASSERT_EQ(18u, range->GetEnd());
168 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100169
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100170 // Test for the 0 constant.
171 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100172 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100173 // First range starts from the definition and ends at the if block.
174 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100175 ASSERT_EQ(2u, range->GetStart());
176 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100177 ASSERT_EQ(14u, range->GetEnd());
178 // Second range is the else block.
179 range = range->GetNext();
180 ASSERT_EQ(18u, range->GetStart());
181 // Last use is the phi at the return block.
182 ASSERT_EQ(22u, range->GetEnd());
183 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100184
185 // Test for the phi.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100186 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100187 range = interval->GetFirstRange();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100188 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100189 ASSERT_EQ(22u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100190 ASSERT_EQ(25u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100191 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100192}
193
194TEST(LiveRangesTest, Loop) {
195 /*
196 * Test the following snippet:
197 * var a = 0;
198 * while (a == a) {
199 * a = 4;
200 * }
201 * return 5;
202 *
203 * Which becomes the following graph (numbered by lifetime position):
204 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100205 * 4: constant4
206 * 6: constant5
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100207 * 8: goto
208 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100209 * 12: goto
210 * |
211 * 14: phi
212 * 16: equal
213 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100214 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100215 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100216 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100217 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100218 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100219 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100220 */
221
222 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
223 Instruction::CONST_4 | 0 | 0,
224 Instruction::IF_EQ, 4,
225 Instruction::CONST_4 | 4 << 12 | 0,
226 Instruction::GOTO | 0xFD00,
227 Instruction::CONST_4 | 5 << 12 | 1 << 8,
228 Instruction::RETURN | 1 << 8);
229
230 ArenaPool pool;
231 ArenaAllocator allocator(&pool);
232 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100233 x86::CodeGeneratorX86 codegen(graph);
234 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100235 liveness.Analyze();
236
237 // Test for the 0 constant.
238 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100239 LiveRange* range = interval->GetFirstRange();
240 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100241 // Last use is the loop phi so instruction is live until
242 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100243 ASSERT_EQ(14u, range->GetEnd());
244 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100245
246 // Test for the 4 constant.
247 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100248 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100249 // The instruction is live until the end of the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100250 ASSERT_EQ(4u, range->GetStart());
251 ASSERT_EQ(24u, range->GetEnd());
252 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100253
254 // Test for the 5 constant.
255 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100256 range = interval->GetFirstRange();
257 // The instruction is live until the return instruction after the loop.
258 ASSERT_EQ(6u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100259 ASSERT_EQ(27u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100260 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100261
262 // Test for the phi.
263 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100264 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100265 // Instruction is consumed by the if.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100266 ASSERT_EQ(14u, range->GetStart());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100267 ASSERT_EQ(17u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100268 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100269}
270
271} // namespace art