blob: 8874fafa0f2862a70935d537aed9e293528781cb [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"
22#include "gtest/gtest.h"
23
24namespace art {
25
Vladimir Marko7baa6f82014-10-09 18:01:24 +010026class MirOptimizationTest : public testing::Test {
Vladimir Markobfea9c22014-01-17 17:49:33 +000027 protected:
Vladimir Markobfea9c22014-01-17 17:49:33 +000028 struct BBDef {
29 static constexpr size_t kMaxSuccessors = 4;
30 static constexpr size_t kMaxPredecessors = 4;
31
32 BBType type;
33 size_t num_successors;
34 BasicBlockId successors[kMaxPredecessors];
35 size_t num_predecessors;
36 BasicBlockId predecessors[kMaxPredecessors];
37 };
38
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010039 struct MethodDef {
40 uint16_t method_idx;
41 uintptr_t declaring_dex_file;
42 uint16_t declaring_class_idx;
43 uint16_t declaring_method_idx;
44 InvokeType invoke_type;
45 InvokeType sharp_type;
46 bool is_referrers_class;
47 bool is_initialized;
48 };
49
Vladimir Markobfea9c22014-01-17 17:49:33 +000050 struct MIRDef {
Vladimir Markobfea9c22014-01-17 17:49:33 +000051 BasicBlockId bbid;
Vladimir Marko7baa6f82014-10-09 18:01:24 +010052 Instruction::Code opcode;
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010053 uint32_t field_or_method_info;
Vladimir Marko7baa6f82014-10-09 18:01:24 +010054 uint32_t vA;
55 uint32_t vB;
56 uint32_t vC;
Vladimir Markobfea9c22014-01-17 17:49:33 +000057 };
58
59#define DEF_SUCC0() \
60 0u, { }
61#define DEF_SUCC1(s1) \
62 1u, { s1 }
63#define DEF_SUCC2(s1, s2) \
64 2u, { s1, s2 }
65#define DEF_SUCC3(s1, s2, s3) \
66 3u, { s1, s2, s3 }
67#define DEF_SUCC4(s1, s2, s3, s4) \
68 4u, { s1, s2, s3, s4 }
69#define DEF_PRED0() \
70 0u, { }
71#define DEF_PRED1(p1) \
72 1u, { p1 }
73#define DEF_PRED2(p1, p2) \
74 2u, { p1, p2 }
75#define DEF_PRED3(p1, p2, p3) \
76 3u, { p1, p2, p3 }
77#define DEF_PRED4(p1, p2, p3, p4) \
78 4u, { p1, p2, p3, p4 }
79#define DEF_BB(type, succ, pred) \
80 { type, succ, pred }
81
Vladimir Marko66c6d7b2014-10-16 15:41:48 +010082#define DEF_SGET_SPUT(bb, opcode, vA, field_info) \
83 { bb, opcode, field_info, vA, 0u, 0u }
84#define DEF_IGET_IPUT(bb, opcode, vA, vB, field_info) \
85 { bb, opcode, field_info, vA, vB, 0u }
86#define DEF_AGET_APUT(bb, opcode, vA, vB, vC) \
87 { bb, opcode, 0u, vA, vB, vC }
88#define DEF_INVOKE(bb, opcode, vC, method_info) \
89 { bb, opcode, method_info, 0u, 0u, vC }
90#define DEF_OTHER1(bb, opcode, vA) \
91 { bb, opcode, 0u, vA, 0u, 0u }
92#define DEF_OTHER2(bb, opcode, vA, vB) \
93 { bb, opcode, 0u, vA, vB, 0u }
94
Vladimir Markobfea9c22014-01-17 17:49:33 +000095 void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
96 cu_.mir_graph->block_id_map_.clear();
Vladimir Markoe39c54e2014-09-22 14:50:02 +010097 cu_.mir_graph->block_list_.clear();
Vladimir Markobfea9c22014-01-17 17:49:33 +000098 ASSERT_LT(3u, count); // null, entry, exit and at least one bytecode block.
99 ASSERT_EQ(kNullBlock, defs[0].type);
100 ASSERT_EQ(kEntryBlock, defs[1].type);
101 ASSERT_EQ(kExitBlock, defs[2].type);
102 for (size_t i = 0u; i != count; ++i) {
103 const BBDef* def = &defs[i];
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100104 BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000105 if (def->num_successors <= 2) {
106 bb->successor_block_list_type = kNotUsed;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000107 bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
108 bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
109 } else {
110 bb->successor_block_list_type = kPackedSwitch;
111 bb->fall_through = 0u;
112 bb->taken = 0u;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100113 bb->successor_blocks.reserve(def->num_successors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000114 for (size_t j = 0u; j != def->num_successors; ++j) {
115 SuccessorBlockInfo* successor_block_info =
116 static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
117 kArenaAllocSuccessor));
118 successor_block_info->block = j;
119 successor_block_info->key = 0u; // Not used by class init check elimination.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100120 bb->successor_blocks.push_back(successor_block_info);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000121 }
122 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100123 bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000124 if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
125 bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
126 cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
127 }
128 }
129 cu_.mir_graph->num_blocks_ = count;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100130 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
131 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000132 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100133 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000134 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
135 }
136
137 template <size_t count>
138 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
139 DoPrepareBasicBlocks(defs, count);
140 }
141
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100142 void PrepareSingleBlock() {
143 static const BBDef bbs[] = {
144 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
145 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
146 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
147 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
148 };
149 PrepareBasicBlocks(bbs);
150 }
151
152 void PrepareDiamond() {
153 static const BBDef bbs[] = {
154 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
155 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
156 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
157 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)),
158 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
159 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
160 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),
161 };
162 PrepareBasicBlocks(bbs);
163 }
164
165 void PrepareLoop() {
166 static const BBDef bbs[] = {
167 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
168 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
169 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
170 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
171 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
172 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
173 };
174 PrepareBasicBlocks(bbs);
175 }
176
177 void PrepareCatch() {
178 static const BBDef bbs[] = {
179 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
180 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
181 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
182 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)), // The top.
183 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // The throwing insn.
184 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Catch handler.
185 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)), // The merged block.
186 };
187 PrepareBasicBlocks(bbs);
188 BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
189 catch_handler->catch_entry = true;
190 // Add successor block info to the check block.
191 BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
192 check_bb->successor_block_list_type = kCatch;
193 SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
194 (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
195 successor_block_info->block = catch_handler->id;
196 check_bb->successor_blocks.push_back(successor_block_info);
197 }
198
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100199 void DoPrepareMethods(const MethodDef* defs, size_t count) {
200 cu_.mir_graph->method_lowering_infos_.clear();
201 cu_.mir_graph->method_lowering_infos_.reserve(count);
202 for (size_t i = 0u; i != count; ++i) {
203 const MethodDef* def = &defs[i];
204 MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type);
205 if (def->declaring_dex_file != 0u) {
206 method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
207 method_info.declaring_class_idx_ = def->declaring_class_idx;
208 method_info.declaring_method_idx_ = def->declaring_method_idx;
209 }
210 ASSERT_EQ(def->invoke_type != kStatic, def->sharp_type != kStatic);
211 method_info.flags_ =
212 ((def->invoke_type == kStatic) ? MirMethodLoweringInfo::kFlagIsStatic : 0u) |
213 MirMethodLoweringInfo::kFlagFastPath |
214 (static_cast<uint16_t>(def->invoke_type) << MirMethodLoweringInfo::kBitInvokeTypeBegin) |
215 (static_cast<uint16_t>(def->sharp_type) << MirMethodLoweringInfo::kBitSharpTypeBegin) |
216 ((def->is_referrers_class) ? MirMethodLoweringInfo::kFlagIsReferrersClass : 0u) |
217 ((def->is_initialized == kStatic) ? MirMethodLoweringInfo::kFlagClassIsInitialized : 0u);
218 ASSERT_EQ(def->declaring_dex_file != 0u, method_info.IsResolved());
219 cu_.mir_graph->method_lowering_infos_.push_back(method_info);
220 }
221 }
222
223 template <size_t count>
224 void PrepareMethods(const MethodDef (&defs)[count]) {
225 DoPrepareMethods(defs, count);
226 }
227
Vladimir Markobfea9c22014-01-17 17:49:33 +0000228 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
229 mir_count_ = count;
230 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
231 uint64_t merged_df_flags = 0u;
232 for (size_t i = 0u; i != count; ++i) {
233 const MIRDef* def = &defs[i];
234 MIR* mir = &mirs_[i];
235 mir->dalvikInsn.opcode = def->opcode;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100236 ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size());
237 BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700238 bb->AppendMIR(mir);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000239 if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100240 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size());
241 mir->meta.sfield_lowering_info = def->field_or_method_info;
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100242 } else if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100243 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->ifield_lowering_infos_.size());
244 mir->meta.ifield_lowering_info = def->field_or_method_info;
245 } else if (def->opcode >= Instruction::INVOKE_VIRTUAL &&
246 def->opcode < Instruction::INVOKE_INTERFACE_RANGE &&
247 def->opcode != Instruction::RETURN_VOID_BARRIER) {
248 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->method_lowering_infos_.size());
249 mir->meta.method_lowering_info = def->field_or_method_info;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000250 }
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100251 mir->dalvikInsn.vA = def->vA;
252 mir->dalvikInsn.vB = def->vB;
253 mir->dalvikInsn.vC = def->vC;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000254 mir->ssa_rep = nullptr;
255 mir->offset = 2 * i; // All insns need to be at least 2 code units long.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000256 mir->optimization_flags = 0u;
Jean Christophe Beylercc794c32014-05-02 09:34:13 -0700257 merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000258 }
259 cu_.mir_graph->merged_df_flags_ = merged_df_flags;
260
261 code_item_ = static_cast<DexFile::CodeItem*>(
262 cu_.arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
263 memset(code_item_, 0, sizeof(DexFile::CodeItem));
264 code_item_->insns_size_in_code_units_ = 2u * count;
Razvan A Lupusoru75035972014-09-11 15:24:59 -0700265 cu_.mir_graph->current_code_item_ = code_item_;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000266 }
267
268 template <size_t count>
269 void PrepareMIRs(const MIRDef (&defs)[count]) {
270 DoPrepareMIRs(defs, count);
271 }
272
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100273 MirOptimizationTest()
Vladimir Markobfea9c22014-01-17 17:49:33 +0000274 : pool_(),
275 cu_(&pool_),
276 mir_count_(0u),
277 mirs_(nullptr),
278 code_item_(nullptr) {
279 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100280 cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000281 }
282
283 ArenaPool pool_;
284 CompilationUnit cu_;
285 size_t mir_count_;
286 MIR* mirs_;
287 DexFile::CodeItem* code_item_;
288};
289
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100290class ClassInitCheckEliminationTest : public MirOptimizationTest {
291 protected:
292 struct SFieldDef {
293 uint16_t field_idx;
294 uintptr_t declaring_dex_file;
295 uint16_t declaring_class_idx;
296 uint16_t declaring_field_idx;
297 };
298
299 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
300 cu_.mir_graph->sfield_lowering_infos_.clear();
301 cu_.mir_graph->sfield_lowering_infos_.reserve(count);
302 for (size_t i = 0u; i != count; ++i) {
303 const SFieldDef* def = &defs[i];
304 MirSFieldLoweringInfo field_info(def->field_idx);
305 if (def->declaring_dex_file != 0u) {
306 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
307 field_info.declaring_class_idx_ = def->declaring_class_idx;
308 field_info.declaring_field_idx_ = def->declaring_field_idx;
309 field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic;
310 }
311 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100312 ASSERT_FALSE(field_info.IsClassInitialized());
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100313 cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
314 }
315 }
316
317 template <size_t count>
318 void PrepareSFields(const SFieldDef (&defs)[count]) {
319 DoPrepareSFields(defs, count);
320 }
321
322 void PerformClassInitCheckElimination() {
323 cu_.mir_graph->ComputeDFSOrders();
324 bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
325 ASSERT_TRUE(gate_result);
326 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
327 bool change = false;
328 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
329 change = cu_.mir_graph->EliminateClassInitChecks(bb);
330 }
331 cu_.mir_graph->EliminateClassInitChecksEnd();
332 }
333
334 ClassInitCheckEliminationTest()
335 : MirOptimizationTest() {
336 }
337};
338
339class NullCheckEliminationTest : public MirOptimizationTest {
340 protected:
341 struct IFieldDef {
342 uint16_t field_idx;
343 uintptr_t declaring_dex_file;
344 uint16_t declaring_class_idx;
345 uint16_t declaring_field_idx;
346 };
347
348 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
349 cu_.mir_graph->ifield_lowering_infos_.clear();
350 cu_.mir_graph->ifield_lowering_infos_.reserve(count);
351 for (size_t i = 0u; i != count; ++i) {
352 const IFieldDef* def = &defs[i];
353 MirIFieldLoweringInfo field_info(def->field_idx);
354 if (def->declaring_dex_file != 0u) {
355 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
356 field_info.declaring_class_idx_ = def->declaring_class_idx;
357 field_info.declaring_field_idx_ = def->declaring_field_idx;
358 }
359 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
360 cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
361 }
362 }
363
364 template <size_t count>
365 void PrepareIFields(const IFieldDef (&defs)[count]) {
366 DoPrepareIFields(defs, count);
367 }
368
369 void PerformNullCheckElimination() {
370 // Make vregs in range [100, 1000) input registers, i.e. requiring a null check.
371 code_item_->registers_size_ = 1000;
372 code_item_->ins_size_ = 900;
373
374 cu_.mir_graph->ComputeDFSOrders();
375 bool gate_result = cu_.mir_graph->EliminateNullChecksGate();
376 ASSERT_TRUE(gate_result);
377 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
378 bool change = false;
379 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
380 change = cu_.mir_graph->EliminateNullChecks(bb);
381 }
382 cu_.mir_graph->EliminateNullChecksEnd();
383 }
384
385 NullCheckEliminationTest()
386 : MirOptimizationTest() {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100387 static const MethodDef methods[] = {
388 { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false }, // Dummy.
389 };
390 PrepareMethods(methods);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100391 }
392};
393
Vladimir Markobfea9c22014-01-17 17:49:33 +0000394TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
395 static const SFieldDef sfields[] = {
396 { 0u, 1u, 0u, 0u },
397 { 1u, 1u, 1u, 1u },
398 { 2u, 1u, 2u, 2u },
399 { 3u, 1u, 3u, 3u }, // Same declaring class as sfield[4].
400 { 4u, 1u, 3u, 4u }, // Same declaring class as sfield[3].
401 { 5u, 0u, 0u, 0u }, // Unresolved.
402 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000403 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100404 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 5u), // Unresolved.
405 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
406 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
407 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
408 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
409 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
410 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
411 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
412 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
413 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
414 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
Vladimir Markobfea9c22014-01-17 17:49:33 +0000415 };
416 static const bool expected_ignore_clinit_check[] = {
Vladimir Markof418f322014-07-09 14:45:36 +0100417 false, false, false, false, true, true, true, true, true, false, true
Vladimir Markobfea9c22014-01-17 17:49:33 +0000418 };
419
420 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100421 PrepareSingleBlock();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000422 PrepareMIRs(mirs);
423 PerformClassInitCheckElimination();
424 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
425 for (size_t i = 0u; i != arraysize(mirs); ++i) {
426 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100427 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
428 EXPECT_EQ(expected_ignore_clinit_check[i],
429 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
430 }
431}
432
433TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) {
434 static const SFieldDef sfields[] = {
435 { 0u, 1u, 0u, 0u },
436 { 1u, 1u, 1u, 1u },
437 { 2u, 1u, 2u, 2u },
438 };
439 static const MethodDef methods[] = {
440 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
441 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
442 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
443 };
444 static const MIRDef mirs[] = {
445 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
446 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
447 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
448 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
449 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
450 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
451 };
452 static const bool expected_class_initialized[] = {
453 false, true, false, true, false, true
454 };
455 static const bool expected_class_in_dex_cache[] = {
456 false, false, false, false, false, false
457 };
458
459 PrepareSFields(sfields);
460 PrepareMethods(methods);
461 PrepareSingleBlock();
462 PrepareMIRs(mirs);
463 PerformClassInitCheckElimination();
464 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
465 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
466 for (size_t i = 0u; i != arraysize(mirs); ++i) {
467 EXPECT_EQ(expected_class_initialized[i],
468 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
469 EXPECT_EQ(expected_class_in_dex_cache[i],
470 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000471 }
472}
473
474TEST_F(ClassInitCheckEliminationTest, Diamond) {
475 static const SFieldDef sfields[] = {
476 { 0u, 1u, 0u, 0u },
477 { 1u, 1u, 1u, 1u },
478 { 2u, 1u, 2u, 2u },
479 { 3u, 1u, 3u, 3u },
480 { 4u, 1u, 4u, 4u },
481 { 5u, 1u, 5u, 5u },
482 { 6u, 1u, 6u, 6u },
483 { 7u, 1u, 7u, 7u },
484 { 8u, 1u, 8u, 8u }, // Same declaring class as sfield[9].
485 { 9u, 1u, 8u, 9u }, // Same declaring class as sfield[8].
486 { 10u, 0u, 0u, 0u }, // Unresolved.
487 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000488 static const MIRDef mirs[] = {
489 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100490 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 10u), // Unresolved.
491 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 10u), // Unresolved.
492 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
493 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Eliminated (BB #3 dominates #6).
494 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 1u),
495 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Not eliminated (BB #4 doesn't dominate #6).
496 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
497 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // Eliminated (BB #3 dominates #4).
498 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
499 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 3u), // Eliminated (BB #3 dominates #5).
500 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
501 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 4u), // Eliminated (BB #3 dominates #6).
502 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 5u),
503 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 5u), // Not eliminated (BB #4 doesn't dominate #6).
504 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 6u),
505 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 6u), // Not eliminated (BB #5 doesn't dominate #6).
506 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 7u),
507 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 7u),
508 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 7u), // Eliminated (initialized in both #3 and #4).
509 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 8u),
510 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 9u),
511 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 8u), // Eliminated (with sfield[9] in BB #5).
512 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 9u), // Eliminated (with sfield[8] in BB #4).
Vladimir Markobfea9c22014-01-17 17:49:33 +0000513 };
514 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100515 false, true, // Unresolved: sfield[10]
Vladimir Markobfea9c22014-01-17 17:49:33 +0000516 false, true, // sfield[0]
517 false, false, // sfield[1]
518 false, true, // sfield[2]
519 false, true, // sfield[3]
520 false, true, // sfield[4]
521 false, false, // sfield[5]
522 false, false, // sfield[6]
523 false, false, true, // sfield[7]
524 false, false, true, true, // sfield[8], sfield[9]
525 };
526
527 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100528 PrepareDiamond();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000529 PrepareMIRs(mirs);
530 PerformClassInitCheckElimination();
531 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
532 for (size_t i = 0u; i != arraysize(mirs); ++i) {
533 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100534 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
535 EXPECT_EQ(expected_ignore_clinit_check[i],
536 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
537 }
538}
539
540TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) {
541 static const SFieldDef sfields[] = {
542 { 0u, 1u, 0u, 0u },
543 { 1u, 1u, 1u, 1u },
544 { 2u, 1u, 2u, 2u },
545 { 3u, 1u, 3u, 3u },
546 { 4u, 1u, 4u, 4u },
547 };
548 static const MethodDef methods[] = {
549 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
550 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
551 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
552 { 3u, 1u, 3u, 3u, kStatic, kStatic, false, false },
553 { 4u, 1u, 4u, 4u, kStatic, kStatic, false, false },
554 };
555 static const MIRDef mirs[] = {
556 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
557 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
558 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
559 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
560 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 1u),
561 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
562 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
563 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 2u),
564 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 3u),
565 DEF_SGET_SPUT(5u, Instruction::SPUT, 0u, 3u),
566 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u),
567 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 4u),
568 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 4u),
569 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 4u),
570 };
571 static const bool expected_class_initialized[] = {
572 false, true, // BB #3 SPUT, BB#6 INVOKE_STATIC
573 false, true, // BB #3 INVOKE_STATIC, BB#6 SPUT
574 false, false, true, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
575 false, false, true, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
576 false, false, true, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
577 };
578 static const bool expected_class_in_dex_cache[] = {
579 false, false, // BB #3 SPUT, BB#6 INVOKE_STATIC
580 false, false, // BB #3 INVOKE_STATIC, BB#6 SPUT
581 false, false, false, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
582 false, false, false, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
583 false, false, false, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
584 };
585
586 PrepareSFields(sfields);
587 PrepareMethods(methods);
588 PrepareDiamond();
589 PrepareMIRs(mirs);
590 PerformClassInitCheckElimination();
591 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
592 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
593 for (size_t i = 0u; i != arraysize(mirs); ++i) {
594 EXPECT_EQ(expected_class_initialized[i],
595 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
596 EXPECT_EQ(expected_class_in_dex_cache[i],
597 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000598 }
599}
600
601TEST_F(ClassInitCheckEliminationTest, Loop) {
602 static const SFieldDef sfields[] = {
603 { 0u, 1u, 0u, 0u },
604 { 1u, 1u, 1u, 1u },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100605 { 2u, 1u, 2u, 2u },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000606 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000607 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100608 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
609 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 0u), // Eliminated.
610 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
611 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 1u), // Eliminated.
612 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
613 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // Eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000614 };
615 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100616 false, true, false, true, false, true,
Vladimir Markobfea9c22014-01-17 17:49:33 +0000617 };
618
619 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100620 PrepareLoop();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000621 PrepareMIRs(mirs);
622 PerformClassInitCheckElimination();
623 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
624 for (size_t i = 0u; i != arraysize(mirs); ++i) {
625 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100626 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
627 EXPECT_EQ(expected_ignore_clinit_check[i],
628 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
629 }
630}
631
632TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) {
633 static const SFieldDef sfields[] = {
634 { 0u, 1u, 0u, 0u },
635 };
636 static const MethodDef methods[] = {
637 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
638 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
639 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
640 };
641 static const MIRDef mirs[] = {
642 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
643 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
644 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
645 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
646 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
647 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
648 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u),
649 };
650 static const bool expected_class_initialized[] = {
651 false, true, false, true, false, true, true,
652 };
653 static const bool expected_class_in_dex_cache[] = {
654 false, false, false, false, false, false, false,
655 };
656
657 PrepareSFields(sfields);
658 PrepareMethods(methods);
659 PrepareLoop();
660 PrepareMIRs(mirs);
661 PerformClassInitCheckElimination();
662 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
663 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
664 for (size_t i = 0u; i != arraysize(mirs); ++i) {
665 EXPECT_EQ(expected_class_initialized[i],
666 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
667 EXPECT_EQ(expected_class_in_dex_cache[i],
668 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000669 }
670}
671
672TEST_F(ClassInitCheckEliminationTest, Catch) {
673 static const SFieldDef sfields[] = {
674 { 0u, 1u, 0u, 0u },
675 { 1u, 1u, 1u, 1u },
Vladimir Marko0a810d22014-07-11 14:44:36 +0100676 { 2u, 1u, 2u, 2u },
677 { 3u, 1u, 3u, 3u },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000678 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000679 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100680 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u), // Before the exception edge.
681 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u), // Before the exception edge.
682 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // After the exception edge.
683 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 3u), // After the exception edge.
684 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u), // In catch handler; eliminated.
685 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // In catch handler; not eliminated.
686 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Class init check eliminated.
687 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Class init check eliminated.
688 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 2u), // Class init check eliminated.
689 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u), // Class init check not eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000690 };
691 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko0a810d22014-07-11 14:44:36 +0100692 false, false, false, false, true, false, true, true, true, false
Vladimir Markobfea9c22014-01-17 17:49:33 +0000693 };
694
695 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100696 PrepareCatch();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000697 PrepareMIRs(mirs);
698 PerformClassInitCheckElimination();
699 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
700 for (size_t i = 0u; i != arraysize(mirs); ++i) {
701 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100702 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
703 EXPECT_EQ(expected_ignore_clinit_check[i],
704 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000705 }
706}
707
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100708TEST_F(NullCheckEliminationTest, SingleBlock) {
709 static const IFieldDef ifields[] = {
710 { 0u, 1u, 0u, 0u },
711 { 1u, 1u, 0u, 1u },
712 { 2u, 1u, 0u, 2u }, // Object.
713 };
714 static const MIRDef mirs[] = {
715 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 0u, 100u, 2u),
716 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 0u, 1u),
717 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 2u, 100u, 2u), // Differs from 0u (no LVN here).
718 DEF_IGET_IPUT(3u, Instruction::IGET, 3u, 2u, 1u),
719 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 101u, 0u),
720 DEF_IGET_IPUT(3u, Instruction::IGET, 5u, 102u, 0u),
721 DEF_IGET_IPUT(3u, Instruction::IGET, 6u, 103u, 0u),
722 DEF_IGET_IPUT(3u, Instruction::IGET, 7u, 103u, 1u),
723 DEF_IGET_IPUT(3u, Instruction::IPUT, 8u, 104u, 0u),
724 DEF_IGET_IPUT(3u, Instruction::IPUT, 9u, 104u, 1u),
725 DEF_IGET_IPUT(3u, Instruction::IGET, 10u, 105u, 0u),
726 DEF_IGET_IPUT(3u, Instruction::IPUT, 11u, 105u, 1u),
727 DEF_IGET_IPUT(3u, Instruction::IPUT, 12u, 106u, 0u),
728 DEF_IGET_IPUT(3u, Instruction::IGET, 13u, 106u, 1u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100729 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 107, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100730 DEF_IGET_IPUT(3u, Instruction::IGET, 15u, 107u, 1u),
731 DEF_IGET_IPUT(3u, Instruction::IGET, 16u, 108u, 0u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100732 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 108, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100733 DEF_AGET_APUT(3u, Instruction::AGET, 18u, 109u, 110u),
734 DEF_AGET_APUT(3u, Instruction::APUT, 19u, 109u, 111u),
735 DEF_OTHER2(3u, Instruction::ARRAY_LENGTH, 20u, 112u),
736 DEF_AGET_APUT(3u, Instruction::AGET, 21u, 112u, 113u),
737 DEF_OTHER1(3u, Instruction::MONITOR_ENTER, 114u),
738 DEF_OTHER1(3u, Instruction::MONITOR_EXIT, 114u),
739 };
740 static const bool expected_ignore_null_check[] = {
741 false, false, true, false /* Not doing LVN. */,
742 false, true /* Set before running NCE. */,
743 false, true, // IGET, IGET
744 false, true, // IPUT, IPUT
745 false, true, // IGET, IPUT
746 false, true, // IPUT, IGET
747 false, true, // INVOKE, IGET
748 false, true, // IGET, INVOKE
749 false, true, // AGET, APUT
750 false, true, // ARRAY_LENGTH, AGET
751 false, true, // MONITOR_ENTER, MONITOR_EXIT
752 };
753
754 PrepareIFields(ifields);
755 PrepareSingleBlock();
756 PrepareMIRs(mirs);
757
758 // Mark IGET 5u as null-checked to test that NCE doesn't clear this flag.
759 mirs_[5u].optimization_flags |= MIR_IGNORE_NULL_CHECK;
760
761 PerformNullCheckElimination();
762 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
763 for (size_t i = 0u; i != arraysize(mirs); ++i) {
764 EXPECT_EQ(expected_ignore_null_check[i],
765 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
766 }
767}
768
769TEST_F(NullCheckEliminationTest, Diamond) {
770 static const IFieldDef ifields[] = {
771 { 0u, 1u, 0u, 0u },
772 { 1u, 1u, 0u, 1u },
773 { 2u, 1u, 0u, 2u }, // int[].
774 };
775 static const MIRDef mirs[] = {
776 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
777 DEF_IGET_IPUT(3u, Instruction::IPUT, 0u, 100u, 0u),
778 DEF_IGET_IPUT(6u, Instruction::IGET, 1u, 100u, 1u), // Eliminated (BB #3 dominates #6).
779 DEF_IGET_IPUT(3u, Instruction::IGET, 2u, 101u, 0u),
780 DEF_IGET_IPUT(4u, Instruction::IPUT, 3u, 101u, 0u), // Eliminated (BB #3 dominates #4).
781 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
782 DEF_IGET_IPUT(5u, Instruction::IPUT, 5u, 102u, 1u), // Eliminated (BB #3 dominates #5).
783 DEF_IGET_IPUT(4u, Instruction::IPUT, 6u, 103u, 0u),
784 DEF_IGET_IPUT(6u, Instruction::IPUT, 7u, 103u, 1u), // Not eliminated (going through BB #5).
785 DEF_IGET_IPUT(5u, Instruction::IGET, 8u, 104u, 1u),
786 DEF_IGET_IPUT(6u, Instruction::IGET, 9u, 104u, 0u), // Not eliminated (going through BB #4).
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100787 DEF_INVOKE(4u, Instruction::INVOKE_DIRECT, 105u, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100788 DEF_IGET_IPUT(5u, Instruction::IGET, 11u, 105u, 1u),
789 DEF_IGET_IPUT(6u, Instruction::IPUT, 12u, 105u, 0u), // Eliminated.
790 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 13u, 106u, 2u),
791 DEF_OTHER1(3u, Instruction::IF_EQZ, 13u), // Last insn in the BB #3.
792 DEF_OTHER2(5u, Instruction::NEW_ARRAY, 13u, 107u),
793 DEF_AGET_APUT(6u, Instruction::AGET, 16u, 13u, 108u), // Eliminated.
794 };
795 static const bool expected_ignore_null_check[] = {
796 false, true, // BB #3 IPUT, BB #6 IGET
797 false, true, // BB #3 IGET, BB #4 IPUT
798 false, true, // BB #3 IGET, BB #5 IPUT
799 false, false, // BB #4 IPUT, BB #6 IPUT
800 false, false, // BB #5 IGET, BB #6 IGET
801 false, false, true, // BB #4 INVOKE, BB #5 IGET, BB #6 IPUT
802 false, false, // BB #3 IGET_OBJECT & IF_EQZ
803 false, true, // BB #5 NEW_ARRAY, BB #6 AGET
804 };
805
806 PrepareIFields(ifields);
807 PrepareDiamond();
808 PrepareMIRs(mirs);
809 PerformNullCheckElimination();
810 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
811 for (size_t i = 0u; i != arraysize(mirs); ++i) {
812 EXPECT_EQ(expected_ignore_null_check[i],
813 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
814 }
815}
816
817TEST_F(NullCheckEliminationTest, Loop) {
818 static const IFieldDef ifields[] = {
819 { 0u, 1u, 0u, 0u },
820 { 1u, 1u, 1u, 1u },
821 };
822 static const MIRDef mirs[] = {
823 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u),
824 DEF_IGET_IPUT(4u, Instruction::IGET, 1u, 101u, 0u),
825 DEF_IGET_IPUT(5u, Instruction::IGET, 2u, 100u, 1u), // Eliminated.
826 DEF_IGET_IPUT(5u, Instruction::IGET, 3u, 101u, 1u), // Eliminated.
827 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
828 DEF_IGET_IPUT(4u, Instruction::IGET, 5u, 102u, 1u), // Not eliminated (MOVE_OBJECT_16).
829 DEF_OTHER2(4u, Instruction::MOVE_OBJECT_16, 102u, 103u),
830 };
831 static const bool expected_ignore_null_check[] = {
832 false, false, true, true,
833 false, false, false,
834 };
835
836 PrepareIFields(ifields);
837 PrepareLoop();
838 PrepareMIRs(mirs);
839 PerformNullCheckElimination();
840 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
841 for (size_t i = 0u; i != arraysize(mirs); ++i) {
842 EXPECT_EQ(expected_ignore_null_check[i],
843 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
844 }
845}
846
847TEST_F(NullCheckEliminationTest, Catch) {
848 static const IFieldDef ifields[] = {
849 { 0u, 1u, 0u, 0u },
850 { 1u, 1u, 1u, 1u },
851 };
852 static const MIRDef mirs[] = {
853 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u), // Before the exception edge.
854 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 101u, 0u), // Before the exception edge.
855 DEF_IGET_IPUT(4u, Instruction::IGET, 2u, 102u, 0u), // After the exception edge.
856 DEF_IGET_IPUT(4u, Instruction::IGET, 3u, 103u, 0u), // After the exception edge.
857 DEF_IGET_IPUT(5u, Instruction::IGET, 4u, 100u, 1u), // In catch handler; eliminated.
858 DEF_IGET_IPUT(5u, Instruction::IGET, 5u, 102u, 1u), // In catch handler; not eliminated.
859 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 100u, 0u), // Null check eliminated.
860 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 101u, 1u), // Null check eliminated.
861 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 102u, 0u), // Null check eliminated.
862 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 103u, 1u), // Null check not eliminated.
863 };
864 static const bool expected_ignore_null_check[] = {
865 false, false, false, false, true, false, true, true, true, false
866 };
867
868 PrepareIFields(ifields);
869 PrepareCatch();
870 PrepareMIRs(mirs);
871 PerformNullCheckElimination();
872 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
873 for (size_t i = 0u; i != arraysize(mirs); ++i) {
874 EXPECT_EQ(expected_ignore_null_check[i],
875 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
876 }
877}
878
879// Undefine MIR_DEF for null check elimination.
880#undef MIR_DEF
881
Vladimir Markobfea9c22014-01-17 17:49:33 +0000882} // namespace art