blob: 362c7fdc054d5b87f2e63a7d20186e8496275b91 [file] [log] [blame]
Vladimir Markobfea9c22014-01-17 17:49:33 +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
17#include <vector>
18
19#include "compiler_internals.h"
20#include "dataflow_iterator.h"
21#include "dataflow_iterator-inl.h"
Vladimir Markoaf6925b2014-10-31 16:37:32 +000022#include "dex/mir_field_info.h"
Vladimir Markobfea9c22014-01-17 17:49:33 +000023#include "gtest/gtest.h"
24
25namespace art {
26
Vladimir Marko7baa6f82014-10-09 18:01:24 +010027class MirOptimizationTest : public testing::Test {
Vladimir Markobfea9c22014-01-17 17:49:33 +000028 protected:
Vladimir Markobfea9c22014-01-17 17:49:33 +000029 struct BBDef {
30 static constexpr size_t kMaxSuccessors = 4;
31 static constexpr size_t kMaxPredecessors = 4;
32
33 BBType type;
34 size_t num_successors;
35 BasicBlockId successors[kMaxPredecessors];
36 size_t num_predecessors;
37 BasicBlockId predecessors[kMaxPredecessors];
38 };
39
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010040 struct MethodDef {
41 uint16_t method_idx;
42 uintptr_t declaring_dex_file;
43 uint16_t declaring_class_idx;
44 uint16_t declaring_method_idx;
45 InvokeType invoke_type;
46 InvokeType sharp_type;
47 bool is_referrers_class;
48 bool is_initialized;
49 };
50
Vladimir Markobfea9c22014-01-17 17:49:33 +000051 struct MIRDef {
Vladimir Markobfea9c22014-01-17 17:49:33 +000052 BasicBlockId bbid;
Vladimir Marko7baa6f82014-10-09 18:01:24 +010053 Instruction::Code opcode;
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010054 uint32_t field_or_method_info;
Vladimir Marko7baa6f82014-10-09 18:01:24 +010055 uint32_t vA;
56 uint32_t vB;
57 uint32_t vC;
Vladimir Markobfea9c22014-01-17 17:49:33 +000058 };
59
60#define DEF_SUCC0() \
61 0u, { }
62#define DEF_SUCC1(s1) \
63 1u, { s1 }
64#define DEF_SUCC2(s1, s2) \
65 2u, { s1, s2 }
66#define DEF_SUCC3(s1, s2, s3) \
67 3u, { s1, s2, s3 }
68#define DEF_SUCC4(s1, s2, s3, s4) \
69 4u, { s1, s2, s3, s4 }
70#define DEF_PRED0() \
71 0u, { }
72#define DEF_PRED1(p1) \
73 1u, { p1 }
74#define DEF_PRED2(p1, p2) \
75 2u, { p1, p2 }
76#define DEF_PRED3(p1, p2, p3) \
77 3u, { p1, p2, p3 }
78#define DEF_PRED4(p1, p2, p3, p4) \
79 4u, { p1, p2, p3, p4 }
80#define DEF_BB(type, succ, pred) \
81 { type, succ, pred }
82
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010083#define DEF_SGET_SPUT(bb, opcode, vA, field_info) \
84 { bb, opcode, field_info, vA, 0u, 0u }
85#define DEF_IGET_IPUT(bb, opcode, vA, vB, field_info) \
86 { bb, opcode, field_info, vA, vB, 0u }
87#define DEF_AGET_APUT(bb, opcode, vA, vB, vC) \
88 { bb, opcode, 0u, vA, vB, vC }
89#define DEF_INVOKE(bb, opcode, vC, method_info) \
90 { bb, opcode, method_info, 0u, 0u, vC }
Vladimir Marko8b858e12014-11-27 14:52:37 +000091#define DEF_OTHER0(bb, opcode) \
92 { bb, opcode, 0u, 0u, 0u, 0u }
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010093#define DEF_OTHER1(bb, opcode, vA) \
94 { bb, opcode, 0u, vA, 0u, 0u }
95#define DEF_OTHER2(bb, opcode, vA, vB) \
96 { bb, opcode, 0u, vA, vB, 0u }
97
Vladimir Markobfea9c22014-01-17 17:49:33 +000098 void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
99 cu_.mir_graph->block_id_map_.clear();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100100 cu_.mir_graph->block_list_.clear();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000101 ASSERT_LT(3u, count); // null, entry, exit and at least one bytecode block.
102 ASSERT_EQ(kNullBlock, defs[0].type);
103 ASSERT_EQ(kEntryBlock, defs[1].type);
104 ASSERT_EQ(kExitBlock, defs[2].type);
105 for (size_t i = 0u; i != count; ++i) {
106 const BBDef* def = &defs[i];
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100107 BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000108 if (def->num_successors <= 2) {
109 bb->successor_block_list_type = kNotUsed;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000110 bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
111 bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
112 } else {
113 bb->successor_block_list_type = kPackedSwitch;
114 bb->fall_through = 0u;
115 bb->taken = 0u;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100116 bb->successor_blocks.reserve(def->num_successors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000117 for (size_t j = 0u; j != def->num_successors; ++j) {
118 SuccessorBlockInfo* successor_block_info =
119 static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
120 kArenaAllocSuccessor));
121 successor_block_info->block = j;
122 successor_block_info->key = 0u; // Not used by class init check elimination.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100123 bb->successor_blocks.push_back(successor_block_info);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000124 }
125 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100126 bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000127 if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
128 bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
129 cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
130 }
131 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100132 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
133 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000134 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100135 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000136 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
137 }
138
139 template <size_t count>
140 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
141 DoPrepareBasicBlocks(defs, count);
142 }
143
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100144 void PrepareSingleBlock() {
145 static const BBDef bbs[] = {
146 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
147 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
148 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
149 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
150 };
151 PrepareBasicBlocks(bbs);
152 }
153
154 void PrepareDiamond() {
155 static const BBDef bbs[] = {
156 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
157 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
158 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
159 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)),
160 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
161 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
162 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),
163 };
164 PrepareBasicBlocks(bbs);
165 }
166
167 void PrepareLoop() {
168 static const BBDef bbs[] = {
169 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
170 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
171 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
172 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
173 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
174 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
175 };
176 PrepareBasicBlocks(bbs);
177 }
178
Vladimir Marko8b858e12014-11-27 14:52:37 +0000179 void PrepareNestedLoopsWhile_While() {
180 static const BBDef bbs[] = {
181 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
182 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
183 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(8)),
184 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
185 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED2(3, 7)), // Outer while loop head.
186 DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head.
187 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // "taken" loops to inner head.
188 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(5)), // "taken" loops to outer head.
189 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
190 };
191 PrepareBasicBlocks(bbs);
192 }
193
194 void PrepareNestedLoopsWhile_WhileWhile() {
195 static const BBDef bbs[] = {
196 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
197 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
198 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(10)),
199 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
200 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)), // Outer while loop head.
201 DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head 1.
202 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // Loops to inner head 1.
203 DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)), // Inner while loop head 2.
204 DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED1(7)), // loops to inner head 2.
205 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)), // loops to outer head.
206 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
207 };
208 PrepareBasicBlocks(bbs);
209 }
210
211 void PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge() {
212 // Extra edge from the first inner loop body to second inner loop body (6u->8u).
213 static const BBDef bbs[] = {
214 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
215 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
216 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(10)),
217 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
218 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)), // Outer while loop head.
219 DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head 1.
220 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED1(5)), // Loops to inner head 1.
221 DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)), // Inner while loop head 2.
222 DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED2(7, 6)), // loops to inner head 2.
223 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)), // loops to outer head.
224 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
225 };
226 PrepareBasicBlocks(bbs);
227 }
228
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100229 void PrepareCatch() {
230 static const BBDef bbs[] = {
231 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
232 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
233 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
234 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)), // The top.
235 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // The throwing insn.
236 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Catch handler.
237 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)), // The merged block.
238 };
239 PrepareBasicBlocks(bbs);
240 BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
241 catch_handler->catch_entry = true;
242 // Add successor block info to the check block.
243 BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
244 check_bb->successor_block_list_type = kCatch;
245 SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
246 (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
247 successor_block_info->block = catch_handler->id;
248 check_bb->successor_blocks.push_back(successor_block_info);
249 }
250
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100251 void DoPrepareMethods(const MethodDef* defs, size_t count) {
252 cu_.mir_graph->method_lowering_infos_.clear();
253 cu_.mir_graph->method_lowering_infos_.reserve(count);
254 for (size_t i = 0u; i != count; ++i) {
255 const MethodDef* def = &defs[i];
256 MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type);
257 if (def->declaring_dex_file != 0u) {
258 method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
259 method_info.declaring_class_idx_ = def->declaring_class_idx;
260 method_info.declaring_method_idx_ = def->declaring_method_idx;
261 }
262 ASSERT_EQ(def->invoke_type != kStatic, def->sharp_type != kStatic);
263 method_info.flags_ =
264 ((def->invoke_type == kStatic) ? MirMethodLoweringInfo::kFlagIsStatic : 0u) |
265 MirMethodLoweringInfo::kFlagFastPath |
266 (static_cast<uint16_t>(def->invoke_type) << MirMethodLoweringInfo::kBitInvokeTypeBegin) |
267 (static_cast<uint16_t>(def->sharp_type) << MirMethodLoweringInfo::kBitSharpTypeBegin) |
268 ((def->is_referrers_class) ? MirMethodLoweringInfo::kFlagIsReferrersClass : 0u) |
269 ((def->is_initialized == kStatic) ? MirMethodLoweringInfo::kFlagClassIsInitialized : 0u);
270 ASSERT_EQ(def->declaring_dex_file != 0u, method_info.IsResolved());
271 cu_.mir_graph->method_lowering_infos_.push_back(method_info);
272 }
273 }
274
275 template <size_t count>
276 void PrepareMethods(const MethodDef (&defs)[count]) {
277 DoPrepareMethods(defs, count);
278 }
279
Vladimir Markobfea9c22014-01-17 17:49:33 +0000280 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
281 mir_count_ = count;
282 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
283 uint64_t merged_df_flags = 0u;
284 for (size_t i = 0u; i != count; ++i) {
285 const MIRDef* def = &defs[i];
286 MIR* mir = &mirs_[i];
287 mir->dalvikInsn.opcode = def->opcode;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100288 ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size());
289 BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700290 bb->AppendMIR(mir);
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000291 if (IsInstructionIGetOrIPut(def->opcode)) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100292 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->ifield_lowering_infos_.size());
293 mir->meta.ifield_lowering_info = def->field_or_method_info;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000294 ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_or_method_info].MemAccessType(),
295 IGetOrIPutMemAccessType(def->opcode));
296 } else if (IsInstructionSGetOrSPut(def->opcode)) {
297 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size());
298 mir->meta.sfield_lowering_info = def->field_or_method_info;
299 ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_or_method_info].MemAccessType(),
300 SGetOrSPutMemAccessType(def->opcode));
301 } else if (IsInstructionInvoke(def->opcode)) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100302 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->method_lowering_infos_.size());
303 mir->meta.method_lowering_info = def->field_or_method_info;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000304 }
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100305 mir->dalvikInsn.vA = def->vA;
306 mir->dalvikInsn.vB = def->vB;
307 mir->dalvikInsn.vC = def->vC;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000308 mir->ssa_rep = nullptr;
309 mir->offset = 2 * i; // All insns need to be at least 2 code units long.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000310 mir->optimization_flags = 0u;
Jean Christophe Beylercc794c32014-05-02 09:34:13 -0700311 merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000312 }
313 cu_.mir_graph->merged_df_flags_ = merged_df_flags;
314
315 code_item_ = static_cast<DexFile::CodeItem*>(
316 cu_.arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
317 memset(code_item_, 0, sizeof(DexFile::CodeItem));
318 code_item_->insns_size_in_code_units_ = 2u * count;
Razvan A Lupusoru75035972014-09-11 15:24:59 -0700319 cu_.mir_graph->current_code_item_ = code_item_;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000320 }
321
322 template <size_t count>
323 void PrepareMIRs(const MIRDef (&defs)[count]) {
324 DoPrepareMIRs(defs, count);
325 }
326
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100327 MirOptimizationTest()
Vladimir Markobfea9c22014-01-17 17:49:33 +0000328 : pool_(),
329 cu_(&pool_),
330 mir_count_(0u),
331 mirs_(nullptr),
332 code_item_(nullptr) {
333 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100334 cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000335 }
336
337 ArenaPool pool_;
338 CompilationUnit cu_;
339 size_t mir_count_;
340 MIR* mirs_;
341 DexFile::CodeItem* code_item_;
342};
343
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100344class ClassInitCheckEliminationTest : public MirOptimizationTest {
345 protected:
346 struct SFieldDef {
347 uint16_t field_idx;
348 uintptr_t declaring_dex_file;
349 uint16_t declaring_class_idx;
350 uint16_t declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000351 DexMemAccessType type;
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100352 };
353
354 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
355 cu_.mir_graph->sfield_lowering_infos_.clear();
356 cu_.mir_graph->sfield_lowering_infos_.reserve(count);
357 for (size_t i = 0u; i != count; ++i) {
358 const SFieldDef* def = &defs[i];
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000359 MirSFieldLoweringInfo field_info(def->field_idx, def->type);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100360 if (def->declaring_dex_file != 0u) {
361 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
362 field_info.declaring_class_idx_ = def->declaring_class_idx;
363 field_info.declaring_field_idx_ = def->declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000364 // We don't care about the volatile flag in these tests.
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100365 }
366 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100367 ASSERT_FALSE(field_info.IsClassInitialized());
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100368 cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
369 }
370 }
371
372 template <size_t count>
373 void PrepareSFields(const SFieldDef (&defs)[count]) {
374 DoPrepareSFields(defs, count);
375 }
376
377 void PerformClassInitCheckElimination() {
378 cu_.mir_graph->ComputeDFSOrders();
379 bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
380 ASSERT_TRUE(gate_result);
381 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
382 bool change = false;
383 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
384 change = cu_.mir_graph->EliminateClassInitChecks(bb);
385 }
386 cu_.mir_graph->EliminateClassInitChecksEnd();
387 }
388
389 ClassInitCheckEliminationTest()
390 : MirOptimizationTest() {
391 }
392};
393
394class NullCheckEliminationTest : public MirOptimizationTest {
395 protected:
396 struct IFieldDef {
397 uint16_t field_idx;
398 uintptr_t declaring_dex_file;
399 uint16_t declaring_class_idx;
400 uint16_t declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000401 DexMemAccessType type;
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100402 };
403
404 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
405 cu_.mir_graph->ifield_lowering_infos_.clear();
406 cu_.mir_graph->ifield_lowering_infos_.reserve(count);
407 for (size_t i = 0u; i != count; ++i) {
408 const IFieldDef* def = &defs[i];
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000409 MirIFieldLoweringInfo field_info(def->field_idx, def->type);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100410 if (def->declaring_dex_file != 0u) {
411 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
412 field_info.declaring_class_idx_ = def->declaring_class_idx;
413 field_info.declaring_field_idx_ = def->declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000414 // We don't care about the volatile flag in these tests.
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100415 }
416 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
417 cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
418 }
419 }
420
421 template <size_t count>
422 void PrepareIFields(const IFieldDef (&defs)[count]) {
423 DoPrepareIFields(defs, count);
424 }
425
426 void PerformNullCheckElimination() {
427 // Make vregs in range [100, 1000) input registers, i.e. requiring a null check.
428 code_item_->registers_size_ = 1000;
429 code_item_->ins_size_ = 900;
430
431 cu_.mir_graph->ComputeDFSOrders();
432 bool gate_result = cu_.mir_graph->EliminateNullChecksGate();
433 ASSERT_TRUE(gate_result);
434 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
435 bool change = false;
436 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
437 change = cu_.mir_graph->EliminateNullChecks(bb);
438 }
439 cu_.mir_graph->EliminateNullChecksEnd();
440 }
441
442 NullCheckEliminationTest()
443 : MirOptimizationTest() {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100444 static const MethodDef methods[] = {
445 { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false }, // Dummy.
446 };
447 PrepareMethods(methods);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100448 }
449};
450
Vladimir Marko8b858e12014-11-27 14:52:37 +0000451class SuspendCheckEliminationTest : public MirOptimizationTest {
452 protected:
453 bool IsBackEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
454 BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
455 return target_bb != NullBasicBlockId && cu_.mir_graph->IsBackEdge(branch, target_bb);
456 }
457
458 bool IsSuspendCheckEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
459 BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
460 return cu_.mir_graph->IsSuspendCheckEdge(branch, target_bb);
461 }
462
463 void PerformSuspendCheckElimination() {
464 cu_.mir_graph->SSATransformationStart();
465 cu_.mir_graph->ComputeDFSOrders();
466 cu_.mir_graph->ComputeDominators();
467 cu_.mir_graph->ComputeTopologicalSortOrder();
468 cu_.mir_graph->SSATransformationEnd();
469 bool gate_result = cu_.mir_graph->EliminateSuspendChecksGate();
470 ASSERT_TRUE(gate_result);
471 TopologicalSortIterator iterator(cu_.mir_graph.get());
472 bool change = false;
473 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
474 change = cu_.mir_graph->EliminateSuspendChecks(bb);
475 }
476 cu_.mir_graph->EliminateSuspendChecksEnd();
477 }
478
479 SuspendCheckEliminationTest()
480 : MirOptimizationTest() {
481 static const MethodDef methods[] = {
482 { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false }, // Dummy.
483 };
484 PrepareMethods(methods);
485 }
486};
487
Vladimir Markobfea9c22014-01-17 17:49:33 +0000488TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
489 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000490 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
491 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
492 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
493 { 3u, 1u, 3u, 3u, kDexMemAccessWord }, // Same declaring class as sfield[4].
494 { 4u, 1u, 3u, 4u, kDexMemAccessWord }, // Same declaring class as sfield[3].
495 { 5u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000496 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000497 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100498 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 5u), // Unresolved.
499 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
500 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
501 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
502 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
503 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
504 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
505 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
506 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
507 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
508 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
Vladimir Markobfea9c22014-01-17 17:49:33 +0000509 };
510 static const bool expected_ignore_clinit_check[] = {
Vladimir Markof418f322014-07-09 14:45:36 +0100511 false, false, false, false, true, true, true, true, true, false, true
Vladimir Markobfea9c22014-01-17 17:49:33 +0000512 };
513
514 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100515 PrepareSingleBlock();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000516 PrepareMIRs(mirs);
517 PerformClassInitCheckElimination();
518 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
519 for (size_t i = 0u; i != arraysize(mirs); ++i) {
520 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100521 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
522 EXPECT_EQ(expected_ignore_clinit_check[i],
523 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
524 }
525}
526
527TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) {
528 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000529 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
530 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
531 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100532 };
533 static const MethodDef methods[] = {
534 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
535 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
536 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
537 };
538 static const MIRDef mirs[] = {
539 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
540 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
541 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
542 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
543 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
544 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
545 };
546 static const bool expected_class_initialized[] = {
547 false, true, false, true, false, true
548 };
549 static const bool expected_class_in_dex_cache[] = {
550 false, false, false, false, false, false
551 };
552
553 PrepareSFields(sfields);
554 PrepareMethods(methods);
555 PrepareSingleBlock();
556 PrepareMIRs(mirs);
557 PerformClassInitCheckElimination();
558 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
559 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
560 for (size_t i = 0u; i != arraysize(mirs); ++i) {
561 EXPECT_EQ(expected_class_initialized[i],
562 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
563 EXPECT_EQ(expected_class_in_dex_cache[i],
564 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000565 }
566}
567
568TEST_F(ClassInitCheckEliminationTest, Diamond) {
569 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000570 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
571 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
572 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
573 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
574 { 4u, 1u, 4u, 4u, kDexMemAccessWord },
575 { 5u, 1u, 5u, 5u, kDexMemAccessWord },
576 { 6u, 1u, 6u, 6u, kDexMemAccessWord },
577 { 7u, 1u, 7u, 7u, kDexMemAccessWord },
578 { 8u, 1u, 8u, 8u, kDexMemAccessWord }, // Same declaring class as sfield[9].
579 { 9u, 1u, 8u, 9u, kDexMemAccessWord }, // Same declaring class as sfield[8].
580 { 10u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000581 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000582 static const MIRDef mirs[] = {
583 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100584 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 10u), // Unresolved.
585 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 10u), // Unresolved.
586 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
587 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Eliminated (BB #3 dominates #6).
588 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 1u),
589 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Not eliminated (BB #4 doesn't dominate #6).
590 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
591 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // Eliminated (BB #3 dominates #4).
592 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
593 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 3u), // Eliminated (BB #3 dominates #5).
594 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
595 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 4u), // Eliminated (BB #3 dominates #6).
596 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 5u),
597 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 5u), // Not eliminated (BB #4 doesn't dominate #6).
598 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 6u),
599 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 6u), // Not eliminated (BB #5 doesn't dominate #6).
600 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 7u),
601 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 7u),
602 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 7u), // Eliminated (initialized in both #3 and #4).
603 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 8u),
604 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 9u),
605 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 8u), // Eliminated (with sfield[9] in BB #5).
606 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 9u), // Eliminated (with sfield[8] in BB #4).
Vladimir Markobfea9c22014-01-17 17:49:33 +0000607 };
608 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100609 false, true, // Unresolved: sfield[10]
Vladimir Markobfea9c22014-01-17 17:49:33 +0000610 false, true, // sfield[0]
611 false, false, // sfield[1]
612 false, true, // sfield[2]
613 false, true, // sfield[3]
614 false, true, // sfield[4]
615 false, false, // sfield[5]
616 false, false, // sfield[6]
617 false, false, true, // sfield[7]
618 false, false, true, true, // sfield[8], sfield[9]
619 };
620
621 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100622 PrepareDiamond();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000623 PrepareMIRs(mirs);
624 PerformClassInitCheckElimination();
625 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
626 for (size_t i = 0u; i != arraysize(mirs); ++i) {
627 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100628 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
629 EXPECT_EQ(expected_ignore_clinit_check[i],
630 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
631 }
632}
633
634TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) {
635 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000636 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
637 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
638 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
639 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
640 { 4u, 1u, 4u, 4u, kDexMemAccessWord },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100641 };
642 static const MethodDef methods[] = {
643 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
644 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
645 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
646 { 3u, 1u, 3u, 3u, kStatic, kStatic, false, false },
647 { 4u, 1u, 4u, 4u, kStatic, kStatic, false, false },
648 };
649 static const MIRDef mirs[] = {
650 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
651 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
652 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
653 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
654 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 1u),
655 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
656 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
657 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 2u),
658 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 3u),
659 DEF_SGET_SPUT(5u, Instruction::SPUT, 0u, 3u),
660 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u),
661 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 4u),
662 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 4u),
663 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 4u),
664 };
665 static const bool expected_class_initialized[] = {
666 false, true, // BB #3 SPUT, BB#6 INVOKE_STATIC
667 false, true, // BB #3 INVOKE_STATIC, BB#6 SPUT
668 false, false, true, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
669 false, false, true, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
670 false, false, true, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
671 };
672 static const bool expected_class_in_dex_cache[] = {
673 false, false, // BB #3 SPUT, BB#6 INVOKE_STATIC
674 false, false, // BB #3 INVOKE_STATIC, BB#6 SPUT
675 false, false, false, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
676 false, false, false, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
677 false, false, false, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
678 };
679
680 PrepareSFields(sfields);
681 PrepareMethods(methods);
682 PrepareDiamond();
683 PrepareMIRs(mirs);
684 PerformClassInitCheckElimination();
685 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
686 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
687 for (size_t i = 0u; i != arraysize(mirs); ++i) {
688 EXPECT_EQ(expected_class_initialized[i],
689 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
690 EXPECT_EQ(expected_class_in_dex_cache[i],
691 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000692 }
693}
694
695TEST_F(ClassInitCheckEliminationTest, Loop) {
696 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000697 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
698 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
699 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000700 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000701 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100702 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
703 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 0u), // Eliminated.
704 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
705 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 1u), // Eliminated.
706 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
707 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // Eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000708 };
709 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100710 false, true, false, true, false, true,
Vladimir Markobfea9c22014-01-17 17:49:33 +0000711 };
712
713 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100714 PrepareLoop();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000715 PrepareMIRs(mirs);
716 PerformClassInitCheckElimination();
717 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
718 for (size_t i = 0u; i != arraysize(mirs); ++i) {
719 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100720 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
721 EXPECT_EQ(expected_ignore_clinit_check[i],
722 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
723 }
724}
725
726TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) {
727 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000728 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100729 };
730 static const MethodDef methods[] = {
731 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
732 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
733 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
734 };
735 static const MIRDef mirs[] = {
736 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
737 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
738 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
739 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
740 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
741 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
742 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u),
743 };
744 static const bool expected_class_initialized[] = {
745 false, true, false, true, false, true, true,
746 };
747 static const bool expected_class_in_dex_cache[] = {
748 false, false, false, false, false, false, false,
749 };
750
751 PrepareSFields(sfields);
752 PrepareMethods(methods);
753 PrepareLoop();
754 PrepareMIRs(mirs);
755 PerformClassInitCheckElimination();
756 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
757 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
758 for (size_t i = 0u; i != arraysize(mirs); ++i) {
759 EXPECT_EQ(expected_class_initialized[i],
760 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
761 EXPECT_EQ(expected_class_in_dex_cache[i],
762 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000763 }
764}
765
766TEST_F(ClassInitCheckEliminationTest, Catch) {
767 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000768 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
769 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
770 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
771 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000772 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000773 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100774 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u), // Before the exception edge.
775 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u), // Before the exception edge.
776 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // After the exception edge.
777 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 3u), // After the exception edge.
778 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u), // In catch handler; eliminated.
779 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // In catch handler; not eliminated.
780 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Class init check eliminated.
781 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Class init check eliminated.
782 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 2u), // Class init check eliminated.
783 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u), // Class init check not eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000784 };
785 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko0a810d22014-07-11 14:44:36 +0100786 false, false, false, false, true, false, true, true, true, false
Vladimir Markobfea9c22014-01-17 17:49:33 +0000787 };
788
789 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100790 PrepareCatch();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000791 PrepareMIRs(mirs);
792 PerformClassInitCheckElimination();
793 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
794 for (size_t i = 0u; i != arraysize(mirs); ++i) {
795 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100796 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
797 EXPECT_EQ(expected_ignore_clinit_check[i],
798 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000799 }
800}
801
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100802TEST_F(NullCheckEliminationTest, SingleBlock) {
803 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000804 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
805 { 1u, 1u, 0u, 1u, kDexMemAccessWord },
806 { 2u, 1u, 0u, 2u, kDexMemAccessObject },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100807 };
808 static const MIRDef mirs[] = {
809 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 0u, 100u, 2u),
810 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 0u, 1u),
811 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 2u, 100u, 2u), // Differs from 0u (no LVN here).
812 DEF_IGET_IPUT(3u, Instruction::IGET, 3u, 2u, 1u),
813 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 101u, 0u),
814 DEF_IGET_IPUT(3u, Instruction::IGET, 5u, 102u, 0u),
815 DEF_IGET_IPUT(3u, Instruction::IGET, 6u, 103u, 0u),
816 DEF_IGET_IPUT(3u, Instruction::IGET, 7u, 103u, 1u),
817 DEF_IGET_IPUT(3u, Instruction::IPUT, 8u, 104u, 0u),
818 DEF_IGET_IPUT(3u, Instruction::IPUT, 9u, 104u, 1u),
819 DEF_IGET_IPUT(3u, Instruction::IGET, 10u, 105u, 0u),
820 DEF_IGET_IPUT(3u, Instruction::IPUT, 11u, 105u, 1u),
821 DEF_IGET_IPUT(3u, Instruction::IPUT, 12u, 106u, 0u),
822 DEF_IGET_IPUT(3u, Instruction::IGET, 13u, 106u, 1u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100823 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 107, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100824 DEF_IGET_IPUT(3u, Instruction::IGET, 15u, 107u, 1u),
825 DEF_IGET_IPUT(3u, Instruction::IGET, 16u, 108u, 0u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100826 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 108, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100827 DEF_AGET_APUT(3u, Instruction::AGET, 18u, 109u, 110u),
828 DEF_AGET_APUT(3u, Instruction::APUT, 19u, 109u, 111u),
829 DEF_OTHER2(3u, Instruction::ARRAY_LENGTH, 20u, 112u),
830 DEF_AGET_APUT(3u, Instruction::AGET, 21u, 112u, 113u),
831 DEF_OTHER1(3u, Instruction::MONITOR_ENTER, 114u),
832 DEF_OTHER1(3u, Instruction::MONITOR_EXIT, 114u),
833 };
834 static const bool expected_ignore_null_check[] = {
835 false, false, true, false /* Not doing LVN. */,
836 false, true /* Set before running NCE. */,
837 false, true, // IGET, IGET
838 false, true, // IPUT, IPUT
839 false, true, // IGET, IPUT
840 false, true, // IPUT, IGET
841 false, true, // INVOKE, IGET
842 false, true, // IGET, INVOKE
843 false, true, // AGET, APUT
844 false, true, // ARRAY_LENGTH, AGET
845 false, true, // MONITOR_ENTER, MONITOR_EXIT
846 };
847
848 PrepareIFields(ifields);
849 PrepareSingleBlock();
850 PrepareMIRs(mirs);
851
852 // Mark IGET 5u as null-checked to test that NCE doesn't clear this flag.
853 mirs_[5u].optimization_flags |= MIR_IGNORE_NULL_CHECK;
854
855 PerformNullCheckElimination();
856 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
857 for (size_t i = 0u; i != arraysize(mirs); ++i) {
858 EXPECT_EQ(expected_ignore_null_check[i],
859 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
860 }
861}
862
863TEST_F(NullCheckEliminationTest, Diamond) {
864 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000865 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
866 { 1u, 1u, 0u, 1u, kDexMemAccessWord },
867 { 2u, 1u, 0u, 2u, kDexMemAccessObject }, // int[].
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100868 };
869 static const MIRDef mirs[] = {
870 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
871 DEF_IGET_IPUT(3u, Instruction::IPUT, 0u, 100u, 0u),
872 DEF_IGET_IPUT(6u, Instruction::IGET, 1u, 100u, 1u), // Eliminated (BB #3 dominates #6).
873 DEF_IGET_IPUT(3u, Instruction::IGET, 2u, 101u, 0u),
874 DEF_IGET_IPUT(4u, Instruction::IPUT, 3u, 101u, 0u), // Eliminated (BB #3 dominates #4).
875 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
876 DEF_IGET_IPUT(5u, Instruction::IPUT, 5u, 102u, 1u), // Eliminated (BB #3 dominates #5).
877 DEF_IGET_IPUT(4u, Instruction::IPUT, 6u, 103u, 0u),
878 DEF_IGET_IPUT(6u, Instruction::IPUT, 7u, 103u, 1u), // Not eliminated (going through BB #5).
879 DEF_IGET_IPUT(5u, Instruction::IGET, 8u, 104u, 1u),
880 DEF_IGET_IPUT(6u, Instruction::IGET, 9u, 104u, 0u), // Not eliminated (going through BB #4).
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100881 DEF_INVOKE(4u, Instruction::INVOKE_DIRECT, 105u, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100882 DEF_IGET_IPUT(5u, Instruction::IGET, 11u, 105u, 1u),
883 DEF_IGET_IPUT(6u, Instruction::IPUT, 12u, 105u, 0u), // Eliminated.
884 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 13u, 106u, 2u),
885 DEF_OTHER1(3u, Instruction::IF_EQZ, 13u), // Last insn in the BB #3.
886 DEF_OTHER2(5u, Instruction::NEW_ARRAY, 13u, 107u),
887 DEF_AGET_APUT(6u, Instruction::AGET, 16u, 13u, 108u), // Eliminated.
888 };
889 static const bool expected_ignore_null_check[] = {
890 false, true, // BB #3 IPUT, BB #6 IGET
891 false, true, // BB #3 IGET, BB #4 IPUT
892 false, true, // BB #3 IGET, BB #5 IPUT
893 false, false, // BB #4 IPUT, BB #6 IPUT
894 false, false, // BB #5 IGET, BB #6 IGET
895 false, false, true, // BB #4 INVOKE, BB #5 IGET, BB #6 IPUT
896 false, false, // BB #3 IGET_OBJECT & IF_EQZ
897 false, true, // BB #5 NEW_ARRAY, BB #6 AGET
898 };
899
900 PrepareIFields(ifields);
901 PrepareDiamond();
902 PrepareMIRs(mirs);
903 PerformNullCheckElimination();
904 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
905 for (size_t i = 0u; i != arraysize(mirs); ++i) {
906 EXPECT_EQ(expected_ignore_null_check[i],
907 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
908 }
909}
910
911TEST_F(NullCheckEliminationTest, Loop) {
912 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000913 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
914 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100915 };
916 static const MIRDef mirs[] = {
917 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u),
918 DEF_IGET_IPUT(4u, Instruction::IGET, 1u, 101u, 0u),
919 DEF_IGET_IPUT(5u, Instruction::IGET, 2u, 100u, 1u), // Eliminated.
920 DEF_IGET_IPUT(5u, Instruction::IGET, 3u, 101u, 1u), // Eliminated.
921 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
922 DEF_IGET_IPUT(4u, Instruction::IGET, 5u, 102u, 1u), // Not eliminated (MOVE_OBJECT_16).
923 DEF_OTHER2(4u, Instruction::MOVE_OBJECT_16, 102u, 103u),
924 };
925 static const bool expected_ignore_null_check[] = {
926 false, false, true, true,
927 false, false, false,
928 };
929
930 PrepareIFields(ifields);
931 PrepareLoop();
932 PrepareMIRs(mirs);
933 PerformNullCheckElimination();
934 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
935 for (size_t i = 0u; i != arraysize(mirs); ++i) {
936 EXPECT_EQ(expected_ignore_null_check[i],
937 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
938 }
939}
940
941TEST_F(NullCheckEliminationTest, Catch) {
942 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000943 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
944 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100945 };
946 static const MIRDef mirs[] = {
947 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u), // Before the exception edge.
948 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 101u, 0u), // Before the exception edge.
949 DEF_IGET_IPUT(4u, Instruction::IGET, 2u, 102u, 0u), // After the exception edge.
950 DEF_IGET_IPUT(4u, Instruction::IGET, 3u, 103u, 0u), // After the exception edge.
951 DEF_IGET_IPUT(5u, Instruction::IGET, 4u, 100u, 1u), // In catch handler; eliminated.
952 DEF_IGET_IPUT(5u, Instruction::IGET, 5u, 102u, 1u), // In catch handler; not eliminated.
953 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 100u, 0u), // Null check eliminated.
954 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 101u, 1u), // Null check eliminated.
955 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 102u, 0u), // Null check eliminated.
956 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 103u, 1u), // Null check not eliminated.
957 };
958 static const bool expected_ignore_null_check[] = {
959 false, false, false, false, true, false, true, true, true, false
960 };
961
962 PrepareIFields(ifields);
963 PrepareCatch();
964 PrepareMIRs(mirs);
965 PerformNullCheckElimination();
966 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
967 for (size_t i = 0u; i != arraysize(mirs); ++i) {
968 EXPECT_EQ(expected_ignore_null_check[i],
969 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
970 }
971}
972
Vladimir Marko8b858e12014-11-27 14:52:37 +0000973TEST_F(SuspendCheckEliminationTest, LoopNoElimination) {
974 static const MIRDef mirs[] = {
975 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u), // Force the pass to run.
976 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge back.
977 };
978
979 PrepareLoop();
980 PrepareMIRs(mirs);
981 PerformSuspendCheckElimination();
982 ASSERT_TRUE(IsBackEdge(4u, 4u));
983 EXPECT_TRUE(IsSuspendCheckEdge(4u, 4u)); // Suspend point on loop to self.
984}
985
986TEST_F(SuspendCheckEliminationTest, LoopElimination) {
987 static const MIRDef mirs[] = {
988 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in the loop.
989 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge back.
990 };
991
992 PrepareLoop();
993 PrepareMIRs(mirs);
994 PerformSuspendCheckElimination();
995 ASSERT_TRUE(IsBackEdge(4u, 4u));
996 EXPECT_FALSE(IsSuspendCheckEdge(4u, 4u)); // No suspend point on loop to self.
997}
998
999TEST_F(SuspendCheckEliminationTest, While_While_NoElimination) {
1000 static const MIRDef mirs[] = {
1001 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u), // Force the pass to run.
1002 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1003 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
1004 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1005 DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
1006 };
1007
1008 PrepareNestedLoopsWhile_While();
1009 PrepareMIRs(mirs);
1010 PerformSuspendCheckElimination();
1011 ASSERT_TRUE(IsBackEdge(6u, 5u));
1012 EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
1013 ASSERT_TRUE(IsBackEdge(7u, 4u));
1014 EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
1015}
1016
1017TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopHead) {
1018 static const MIRDef mirs[] = {
1019 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in outer loop head.
1020 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1021 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
1022 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1023 DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
1024 };
1025
1026 PrepareNestedLoopsWhile_While();
1027 PrepareMIRs(mirs);
1028 PerformSuspendCheckElimination();
1029 ASSERT_TRUE(IsBackEdge(6u, 5u));
1030 EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
1031 ASSERT_TRUE(IsBackEdge(7u, 4u));
1032 EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
1033}
1034
1035TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopBody) {
1036 static const MIRDef mirs[] = {
1037 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1038 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
1039 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1040 DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in outer loop body.
1041 DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
1042 };
1043
1044 PrepareNestedLoopsWhile_While();
1045 PrepareMIRs(mirs);
1046 PerformSuspendCheckElimination();
1047 ASSERT_TRUE(IsBackEdge(6u, 5u));
1048 EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
1049 ASSERT_TRUE(IsBackEdge(7u, 4u));
1050 EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
1051}
1052
1053TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopHead) {
1054 static const MIRDef mirs[] = {
1055 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1056 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in inner loop head.
1057 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
1058 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1059 DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
1060 };
1061
1062 PrepareNestedLoopsWhile_While();
1063 PrepareMIRs(mirs);
1064 PerformSuspendCheckElimination();
1065 ASSERT_TRUE(IsBackEdge(6u, 5u));
1066 EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
1067 ASSERT_TRUE(IsBackEdge(7u, 4u));
1068 EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
1069}
1070
1071TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopBody) {
1072 static const MIRDef mirs[] = {
1073 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1074 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
1075 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in inner loop body.
1076 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1077 DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
1078 };
1079
1080 PrepareNestedLoopsWhile_While();
1081 PrepareMIRs(mirs);
1082 PerformSuspendCheckElimination();
1083 ASSERT_TRUE(IsBackEdge(6u, 5u));
1084 EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
1085 ASSERT_TRUE(IsBackEdge(7u, 4u));
1086 EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
1087}
1088
1089TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopHead) {
1090 static const MIRDef mirs[] = {
1091 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1092 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop head.
1093 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
1094 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1095 DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
1096 DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
1097 DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
1098 };
1099
1100 PrepareNestedLoopsWhile_WhileWhile();
1101 PrepareMIRs(mirs);
1102 PerformSuspendCheckElimination();
1103 ASSERT_TRUE(IsBackEdge(6u, 5u));
1104 EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
1105 ASSERT_TRUE(IsBackEdge(8u, 7u));
1106 EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
1107 ASSERT_TRUE(IsBackEdge(9u, 4u));
1108 EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
1109}
1110
1111TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopBody) {
1112 static const MIRDef mirs[] = {
1113 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1114 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
1115 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop body.
1116 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1117 DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
1118 DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
1119 DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
1120 };
1121
1122 PrepareNestedLoopsWhile_WhileWhile();
1123 PrepareMIRs(mirs);
1124 PerformSuspendCheckElimination();
1125 ASSERT_TRUE(IsBackEdge(6u, 5u));
1126 EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
1127 ASSERT_TRUE(IsBackEdge(8u, 7u));
1128 EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
1129 ASSERT_TRUE(IsBackEdge(9u, 4u));
1130 EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
1131}
1132
1133TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInFirstInnerLoopBody) {
1134 static const MIRDef mirs[] = {
1135 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1136 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
1137 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop body.
1138 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1139 DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
1140 DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
1141 DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
1142 };
1143
1144 PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
1145 PrepareMIRs(mirs);
1146 PerformSuspendCheckElimination();
1147 ASSERT_TRUE(IsBackEdge(6u, 5u));
1148 EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
1149 ASSERT_TRUE(IsBackEdge(8u, 7u));
1150 EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u)); // Unaffected by the extra edge.
1151 ASSERT_TRUE(IsBackEdge(9u, 4u));
1152 EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
1153}
1154
1155TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInSecondInnerLoopHead) {
1156 static const MIRDef mirs[] = {
1157 DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
1158 DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
1159 DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
1160 DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in second inner loop head.
1161 DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
1162 DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
1163 DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
1164 };
1165
1166 PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
1167 PrepareMIRs(mirs);
1168 PerformSuspendCheckElimination();
1169 ASSERT_TRUE(IsBackEdge(6u, 5u));
1170 EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
1171 ASSERT_TRUE(IsBackEdge(8u, 7u));
1172 EXPECT_FALSE(IsSuspendCheckEdge(8u, 7u)); // Unaffected by the extra edge.
1173 ASSERT_TRUE(IsBackEdge(9u, 4u));
1174 EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
1175}
Vladimir Marko7baa6f82014-10-09 18:01:24 +01001176
Vladimir Markobfea9c22014-01-17 17:49:33 +00001177} // namespace art