blob: c794cc61f84127a51a425a1bfdc3beb665d3b7ca [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 }
91#define DEF_OTHER1(bb, opcode, vA) \
92 { bb, opcode, 0u, vA, 0u, 0u }
93#define DEF_OTHER2(bb, opcode, vA, vB) \
94 { bb, opcode, 0u, vA, vB, 0u }
95
Vladimir Markobfea9c22014-01-17 17:49:33 +000096 void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
97 cu_.mir_graph->block_id_map_.clear();
Vladimir Markoe39c54e2014-09-22 14:50:02 +010098 cu_.mir_graph->block_list_.clear();
Vladimir Markobfea9c22014-01-17 17:49:33 +000099 ASSERT_LT(3u, count); // null, entry, exit and at least one bytecode block.
100 ASSERT_EQ(kNullBlock, defs[0].type);
101 ASSERT_EQ(kEntryBlock, defs[1].type);
102 ASSERT_EQ(kExitBlock, defs[2].type);
103 for (size_t i = 0u; i != count; ++i) {
104 const BBDef* def = &defs[i];
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100105 BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000106 if (def->num_successors <= 2) {
107 bb->successor_block_list_type = kNotUsed;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000108 bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
109 bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
110 } else {
111 bb->successor_block_list_type = kPackedSwitch;
112 bb->fall_through = 0u;
113 bb->taken = 0u;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100114 bb->successor_blocks.reserve(def->num_successors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000115 for (size_t j = 0u; j != def->num_successors; ++j) {
116 SuccessorBlockInfo* successor_block_info =
117 static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
118 kArenaAllocSuccessor));
119 successor_block_info->block = j;
120 successor_block_info->key = 0u; // Not used by class init check elimination.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100121 bb->successor_blocks.push_back(successor_block_info);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000122 }
123 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100124 bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000125 if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
126 bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
127 cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
128 }
129 }
130 cu_.mir_graph->num_blocks_ = count;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100131 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
132 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000133 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100134 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
Vladimir Markobfea9c22014-01-17 17:49:33 +0000135 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
136 }
137
138 template <size_t count>
139 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
140 DoPrepareBasicBlocks(defs, count);
141 }
142
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100143 void PrepareSingleBlock() {
144 static const BBDef bbs[] = {
145 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
146 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
147 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
148 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
149 };
150 PrepareBasicBlocks(bbs);
151 }
152
153 void PrepareDiamond() {
154 static const BBDef bbs[] = {
155 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
156 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
157 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
158 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)),
159 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
160 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
161 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),
162 };
163 PrepareBasicBlocks(bbs);
164 }
165
166 void PrepareLoop() {
167 static const BBDef bbs[] = {
168 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
169 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
170 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
171 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
172 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
173 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
174 };
175 PrepareBasicBlocks(bbs);
176 }
177
178 void PrepareCatch() {
179 static const BBDef bbs[] = {
180 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
181 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
182 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
183 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)), // The top.
184 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // The throwing insn.
185 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Catch handler.
186 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)), // The merged block.
187 };
188 PrepareBasicBlocks(bbs);
189 BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
190 catch_handler->catch_entry = true;
191 // Add successor block info to the check block.
192 BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
193 check_bb->successor_block_list_type = kCatch;
194 SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
195 (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
196 successor_block_info->block = catch_handler->id;
197 check_bb->successor_blocks.push_back(successor_block_info);
198 }
199
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100200 void DoPrepareMethods(const MethodDef* defs, size_t count) {
201 cu_.mir_graph->method_lowering_infos_.clear();
202 cu_.mir_graph->method_lowering_infos_.reserve(count);
203 for (size_t i = 0u; i != count; ++i) {
204 const MethodDef* def = &defs[i];
205 MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type);
206 if (def->declaring_dex_file != 0u) {
207 method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
208 method_info.declaring_class_idx_ = def->declaring_class_idx;
209 method_info.declaring_method_idx_ = def->declaring_method_idx;
210 }
211 ASSERT_EQ(def->invoke_type != kStatic, def->sharp_type != kStatic);
212 method_info.flags_ =
213 ((def->invoke_type == kStatic) ? MirMethodLoweringInfo::kFlagIsStatic : 0u) |
214 MirMethodLoweringInfo::kFlagFastPath |
215 (static_cast<uint16_t>(def->invoke_type) << MirMethodLoweringInfo::kBitInvokeTypeBegin) |
216 (static_cast<uint16_t>(def->sharp_type) << MirMethodLoweringInfo::kBitSharpTypeBegin) |
217 ((def->is_referrers_class) ? MirMethodLoweringInfo::kFlagIsReferrersClass : 0u) |
218 ((def->is_initialized == kStatic) ? MirMethodLoweringInfo::kFlagClassIsInitialized : 0u);
219 ASSERT_EQ(def->declaring_dex_file != 0u, method_info.IsResolved());
220 cu_.mir_graph->method_lowering_infos_.push_back(method_info);
221 }
222 }
223
224 template <size_t count>
225 void PrepareMethods(const MethodDef (&defs)[count]) {
226 DoPrepareMethods(defs, count);
227 }
228
Vladimir Markobfea9c22014-01-17 17:49:33 +0000229 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
230 mir_count_ = count;
231 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
232 uint64_t merged_df_flags = 0u;
233 for (size_t i = 0u; i != count; ++i) {
234 const MIRDef* def = &defs[i];
235 MIR* mir = &mirs_[i];
236 mir->dalvikInsn.opcode = def->opcode;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100237 ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size());
238 BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700239 bb->AppendMIR(mir);
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000240 if (IsInstructionIGetOrIPut(def->opcode)) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100241 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->ifield_lowering_infos_.size());
242 mir->meta.ifield_lowering_info = def->field_or_method_info;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000243 ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_or_method_info].MemAccessType(),
244 IGetOrIPutMemAccessType(def->opcode));
245 } else if (IsInstructionSGetOrSPut(def->opcode)) {
246 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size());
247 mir->meta.sfield_lowering_info = def->field_or_method_info;
248 ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_or_method_info].MemAccessType(),
249 SGetOrSPutMemAccessType(def->opcode));
250 } else if (IsInstructionInvoke(def->opcode)) {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100251 ASSERT_LT(def->field_or_method_info, cu_.mir_graph->method_lowering_infos_.size());
252 mir->meta.method_lowering_info = def->field_or_method_info;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000253 }
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100254 mir->dalvikInsn.vA = def->vA;
255 mir->dalvikInsn.vB = def->vB;
256 mir->dalvikInsn.vC = def->vC;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000257 mir->ssa_rep = nullptr;
258 mir->offset = 2 * i; // All insns need to be at least 2 code units long.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000259 mir->optimization_flags = 0u;
Jean Christophe Beylercc794c32014-05-02 09:34:13 -0700260 merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode);
Vladimir Markobfea9c22014-01-17 17:49:33 +0000261 }
262 cu_.mir_graph->merged_df_flags_ = merged_df_flags;
263
264 code_item_ = static_cast<DexFile::CodeItem*>(
265 cu_.arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
266 memset(code_item_, 0, sizeof(DexFile::CodeItem));
267 code_item_->insns_size_in_code_units_ = 2u * count;
Razvan A Lupusoru75035972014-09-11 15:24:59 -0700268 cu_.mir_graph->current_code_item_ = code_item_;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000269 }
270
271 template <size_t count>
272 void PrepareMIRs(const MIRDef (&defs)[count]) {
273 DoPrepareMIRs(defs, count);
274 }
275
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100276 MirOptimizationTest()
Vladimir Markobfea9c22014-01-17 17:49:33 +0000277 : pool_(),
278 cu_(&pool_),
279 mir_count_(0u),
280 mirs_(nullptr),
281 code_item_(nullptr) {
282 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100283 cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000284 }
285
286 ArenaPool pool_;
287 CompilationUnit cu_;
288 size_t mir_count_;
289 MIR* mirs_;
290 DexFile::CodeItem* code_item_;
291};
292
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100293class ClassInitCheckEliminationTest : public MirOptimizationTest {
294 protected:
295 struct SFieldDef {
296 uint16_t field_idx;
297 uintptr_t declaring_dex_file;
298 uint16_t declaring_class_idx;
299 uint16_t declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000300 DexMemAccessType type;
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100301 };
302
303 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
304 cu_.mir_graph->sfield_lowering_infos_.clear();
305 cu_.mir_graph->sfield_lowering_infos_.reserve(count);
306 for (size_t i = 0u; i != count; ++i) {
307 const SFieldDef* def = &defs[i];
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000308 MirSFieldLoweringInfo field_info(def->field_idx, def->type);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100309 if (def->declaring_dex_file != 0u) {
310 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
311 field_info.declaring_class_idx_ = def->declaring_class_idx;
312 field_info.declaring_field_idx_ = def->declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000313 // We don't care about the volatile flag in these tests.
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100314 }
315 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100316 ASSERT_FALSE(field_info.IsClassInitialized());
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100317 cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
318 }
319 }
320
321 template <size_t count>
322 void PrepareSFields(const SFieldDef (&defs)[count]) {
323 DoPrepareSFields(defs, count);
324 }
325
326 void PerformClassInitCheckElimination() {
327 cu_.mir_graph->ComputeDFSOrders();
328 bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
329 ASSERT_TRUE(gate_result);
330 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
331 bool change = false;
332 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
333 change = cu_.mir_graph->EliminateClassInitChecks(bb);
334 }
335 cu_.mir_graph->EliminateClassInitChecksEnd();
336 }
337
338 ClassInitCheckEliminationTest()
339 : MirOptimizationTest() {
340 }
341};
342
343class NullCheckEliminationTest : public MirOptimizationTest {
344 protected:
345 struct IFieldDef {
346 uint16_t field_idx;
347 uintptr_t declaring_dex_file;
348 uint16_t declaring_class_idx;
349 uint16_t declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000350 DexMemAccessType type;
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100351 };
352
353 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
354 cu_.mir_graph->ifield_lowering_infos_.clear();
355 cu_.mir_graph->ifield_lowering_infos_.reserve(count);
356 for (size_t i = 0u; i != count; ++i) {
357 const IFieldDef* def = &defs[i];
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000358 MirIFieldLoweringInfo field_info(def->field_idx, def->type);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100359 if (def->declaring_dex_file != 0u) {
360 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
361 field_info.declaring_class_idx_ = def->declaring_class_idx;
362 field_info.declaring_field_idx_ = def->declaring_field_idx;
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000363 // We don't care about the volatile flag in these tests.
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100364 }
365 ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
366 cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
367 }
368 }
369
370 template <size_t count>
371 void PrepareIFields(const IFieldDef (&defs)[count]) {
372 DoPrepareIFields(defs, count);
373 }
374
375 void PerformNullCheckElimination() {
376 // Make vregs in range [100, 1000) input registers, i.e. requiring a null check.
377 code_item_->registers_size_ = 1000;
378 code_item_->ins_size_ = 900;
379
380 cu_.mir_graph->ComputeDFSOrders();
381 bool gate_result = cu_.mir_graph->EliminateNullChecksGate();
382 ASSERT_TRUE(gate_result);
383 RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
384 bool change = false;
385 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
386 change = cu_.mir_graph->EliminateNullChecks(bb);
387 }
388 cu_.mir_graph->EliminateNullChecksEnd();
389 }
390
391 NullCheckEliminationTest()
392 : MirOptimizationTest() {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100393 static const MethodDef methods[] = {
394 { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false }, // Dummy.
395 };
396 PrepareMethods(methods);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100397 }
398};
399
Vladimir Markobfea9c22014-01-17 17:49:33 +0000400TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
401 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000402 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
403 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
404 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
405 { 3u, 1u, 3u, 3u, kDexMemAccessWord }, // Same declaring class as sfield[4].
406 { 4u, 1u, 3u, 4u, kDexMemAccessWord }, // Same declaring class as sfield[3].
407 { 5u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000408 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000409 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100410 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 5u), // Unresolved.
411 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
412 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
413 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
414 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
415 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
416 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
417 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
418 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u), // Unresolved.
419 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
420 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
Vladimir Markobfea9c22014-01-17 17:49:33 +0000421 };
422 static const bool expected_ignore_clinit_check[] = {
Vladimir Markof418f322014-07-09 14:45:36 +0100423 false, false, false, false, true, true, true, true, true, false, true
Vladimir Markobfea9c22014-01-17 17:49:33 +0000424 };
425
426 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100427 PrepareSingleBlock();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000428 PrepareMIRs(mirs);
429 PerformClassInitCheckElimination();
430 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
431 for (size_t i = 0u; i != arraysize(mirs); ++i) {
432 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100433 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
434 EXPECT_EQ(expected_ignore_clinit_check[i],
435 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
436 }
437}
438
439TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) {
440 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000441 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
442 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
443 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100444 };
445 static const MethodDef methods[] = {
446 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
447 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
448 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
449 };
450 static const MIRDef mirs[] = {
451 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
452 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
453 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
454 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
455 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
456 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
457 };
458 static const bool expected_class_initialized[] = {
459 false, true, false, true, false, true
460 };
461 static const bool expected_class_in_dex_cache[] = {
462 false, false, false, false, false, false
463 };
464
465 PrepareSFields(sfields);
466 PrepareMethods(methods);
467 PrepareSingleBlock();
468 PrepareMIRs(mirs);
469 PerformClassInitCheckElimination();
470 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
471 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
472 for (size_t i = 0u; i != arraysize(mirs); ++i) {
473 EXPECT_EQ(expected_class_initialized[i],
474 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
475 EXPECT_EQ(expected_class_in_dex_cache[i],
476 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000477 }
478}
479
480TEST_F(ClassInitCheckEliminationTest, Diamond) {
481 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000482 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
483 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
484 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
485 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
486 { 4u, 1u, 4u, 4u, kDexMemAccessWord },
487 { 5u, 1u, 5u, 5u, kDexMemAccessWord },
488 { 6u, 1u, 6u, 6u, kDexMemAccessWord },
489 { 7u, 1u, 7u, 7u, kDexMemAccessWord },
490 { 8u, 1u, 8u, 8u, kDexMemAccessWord }, // Same declaring class as sfield[9].
491 { 9u, 1u, 8u, 9u, kDexMemAccessWord }, // Same declaring class as sfield[8].
492 { 10u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000493 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000494 static const MIRDef mirs[] = {
495 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100496 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 10u), // Unresolved.
497 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 10u), // Unresolved.
498 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
499 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Eliminated (BB #3 dominates #6).
500 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 1u),
501 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Not eliminated (BB #4 doesn't dominate #6).
502 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
503 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // Eliminated (BB #3 dominates #4).
504 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
505 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 3u), // Eliminated (BB #3 dominates #5).
506 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
507 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 4u), // Eliminated (BB #3 dominates #6).
508 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 5u),
509 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 5u), // Not eliminated (BB #4 doesn't dominate #6).
510 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 6u),
511 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 6u), // Not eliminated (BB #5 doesn't dominate #6).
512 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 7u),
513 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 7u),
514 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 7u), // Eliminated (initialized in both #3 and #4).
515 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 8u),
516 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 9u),
517 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 8u), // Eliminated (with sfield[9] in BB #5).
518 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 9u), // Eliminated (with sfield[8] in BB #4).
Vladimir Markobfea9c22014-01-17 17:49:33 +0000519 };
520 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100521 false, true, // Unresolved: sfield[10]
Vladimir Markobfea9c22014-01-17 17:49:33 +0000522 false, true, // sfield[0]
523 false, false, // sfield[1]
524 false, true, // sfield[2]
525 false, true, // sfield[3]
526 false, true, // sfield[4]
527 false, false, // sfield[5]
528 false, false, // sfield[6]
529 false, false, true, // sfield[7]
530 false, false, true, true, // sfield[8], sfield[9]
531 };
532
533 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100534 PrepareDiamond();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000535 PrepareMIRs(mirs);
536 PerformClassInitCheckElimination();
537 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
538 for (size_t i = 0u; i != arraysize(mirs); ++i) {
539 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100540 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
541 EXPECT_EQ(expected_ignore_clinit_check[i],
542 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
543 }
544}
545
546TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) {
547 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000548 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
549 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
550 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
551 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
552 { 4u, 1u, 4u, 4u, kDexMemAccessWord },
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100553 };
554 static const MethodDef methods[] = {
555 { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
556 { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
557 { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
558 { 3u, 1u, 3u, 3u, kStatic, kStatic, false, false },
559 { 4u, 1u, 4u, 4u, kStatic, kStatic, false, false },
560 };
561 static const MIRDef mirs[] = {
562 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
563 DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
564 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
565 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
566 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 1u),
567 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
568 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
569 DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 2u),
570 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 3u),
571 DEF_SGET_SPUT(5u, Instruction::SPUT, 0u, 3u),
572 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u),
573 DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 4u),
574 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 4u),
575 DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 4u),
576 };
577 static const bool expected_class_initialized[] = {
578 false, true, // BB #3 SPUT, BB#6 INVOKE_STATIC
579 false, true, // BB #3 INVOKE_STATIC, BB#6 SPUT
580 false, false, true, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
581 false, false, true, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
582 false, false, true, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
583 };
584 static const bool expected_class_in_dex_cache[] = {
585 false, false, // BB #3 SPUT, BB#6 INVOKE_STATIC
586 false, false, // BB #3 INVOKE_STATIC, BB#6 SPUT
587 false, false, false, // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
588 false, false, false, // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
589 false, false, false, // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
590 };
591
592 PrepareSFields(sfields);
593 PrepareMethods(methods);
594 PrepareDiamond();
595 PrepareMIRs(mirs);
596 PerformClassInitCheckElimination();
597 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
598 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
599 for (size_t i = 0u; i != arraysize(mirs); ++i) {
600 EXPECT_EQ(expected_class_initialized[i],
601 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
602 EXPECT_EQ(expected_class_in_dex_cache[i],
603 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000604 }
605}
606
607TEST_F(ClassInitCheckEliminationTest, Loop) {
608 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000609 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
610 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
611 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000612 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000613 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100614 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
615 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 0u), // Eliminated.
616 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
617 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 1u), // Eliminated.
618 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
619 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // Eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000620 };
621 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100622 false, true, false, true, false, true,
Vladimir Markobfea9c22014-01-17 17:49:33 +0000623 };
624
625 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100626 PrepareLoop();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000627 PrepareMIRs(mirs);
628 PerformClassInitCheckElimination();
629 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
630 for (size_t i = 0u; i != arraysize(mirs); ++i) {
631 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100632 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
633 EXPECT_EQ(expected_ignore_clinit_check[i],
634 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
635 }
636}
637
638TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) {
639 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000640 { 0u, 1u, 0u, 0u, 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 };
647 static const MIRDef mirs[] = {
648 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
649 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
650 DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
651 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
652 DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
653 DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
654 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u),
655 };
656 static const bool expected_class_initialized[] = {
657 false, true, false, true, false, true, true,
658 };
659 static const bool expected_class_in_dex_cache[] = {
660 false, false, false, false, false, false, false,
661 };
662
663 PrepareSFields(sfields);
664 PrepareMethods(methods);
665 PrepareLoop();
666 PrepareMIRs(mirs);
667 PerformClassInitCheckElimination();
668 ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
669 ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
670 for (size_t i = 0u; i != arraysize(mirs); ++i) {
671 EXPECT_EQ(expected_class_initialized[i],
672 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
673 EXPECT_EQ(expected_class_in_dex_cache[i],
674 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000675 }
676}
677
678TEST_F(ClassInitCheckEliminationTest, Catch) {
679 static const SFieldDef sfields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000680 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
681 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
682 { 2u, 1u, 2u, 2u, kDexMemAccessWord },
683 { 3u, 1u, 3u, 3u, kDexMemAccessWord },
Vladimir Markobfea9c22014-01-17 17:49:33 +0000684 };
Vladimir Markobfea9c22014-01-17 17:49:33 +0000685 static const MIRDef mirs[] = {
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100686 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u), // Before the exception edge.
687 DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u), // Before the exception edge.
688 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u), // After the exception edge.
689 DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 3u), // After the exception edge.
690 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u), // In catch handler; eliminated.
691 DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u), // In catch handler; not eliminated.
692 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u), // Class init check eliminated.
693 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u), // Class init check eliminated.
694 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 2u), // Class init check eliminated.
695 DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u), // Class init check not eliminated.
Vladimir Markobfea9c22014-01-17 17:49:33 +0000696 };
697 static const bool expected_ignore_clinit_check[] = {
Vladimir Marko0a810d22014-07-11 14:44:36 +0100698 false, false, false, false, true, false, true, true, true, false
Vladimir Markobfea9c22014-01-17 17:49:33 +0000699 };
700
701 PrepareSFields(sfields);
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100702 PrepareCatch();
Vladimir Markobfea9c22014-01-17 17:49:33 +0000703 PrepareMIRs(mirs);
704 PerformClassInitCheckElimination();
705 ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
706 for (size_t i = 0u; i != arraysize(mirs); ++i) {
707 EXPECT_EQ(expected_ignore_clinit_check[i],
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100708 (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
709 EXPECT_EQ(expected_ignore_clinit_check[i],
710 (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
Vladimir Markobfea9c22014-01-17 17:49:33 +0000711 }
712}
713
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100714TEST_F(NullCheckEliminationTest, SingleBlock) {
715 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000716 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
717 { 1u, 1u, 0u, 1u, kDexMemAccessWord },
718 { 2u, 1u, 0u, 2u, kDexMemAccessObject },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100719 };
720 static const MIRDef mirs[] = {
721 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 0u, 100u, 2u),
722 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 0u, 1u),
723 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 2u, 100u, 2u), // Differs from 0u (no LVN here).
724 DEF_IGET_IPUT(3u, Instruction::IGET, 3u, 2u, 1u),
725 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 101u, 0u),
726 DEF_IGET_IPUT(3u, Instruction::IGET, 5u, 102u, 0u),
727 DEF_IGET_IPUT(3u, Instruction::IGET, 6u, 103u, 0u),
728 DEF_IGET_IPUT(3u, Instruction::IGET, 7u, 103u, 1u),
729 DEF_IGET_IPUT(3u, Instruction::IPUT, 8u, 104u, 0u),
730 DEF_IGET_IPUT(3u, Instruction::IPUT, 9u, 104u, 1u),
731 DEF_IGET_IPUT(3u, Instruction::IGET, 10u, 105u, 0u),
732 DEF_IGET_IPUT(3u, Instruction::IPUT, 11u, 105u, 1u),
733 DEF_IGET_IPUT(3u, Instruction::IPUT, 12u, 106u, 0u),
734 DEF_IGET_IPUT(3u, Instruction::IGET, 13u, 106u, 1u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100735 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 107, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100736 DEF_IGET_IPUT(3u, Instruction::IGET, 15u, 107u, 1u),
737 DEF_IGET_IPUT(3u, Instruction::IGET, 16u, 108u, 0u),
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100738 DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 108, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100739 DEF_AGET_APUT(3u, Instruction::AGET, 18u, 109u, 110u),
740 DEF_AGET_APUT(3u, Instruction::APUT, 19u, 109u, 111u),
741 DEF_OTHER2(3u, Instruction::ARRAY_LENGTH, 20u, 112u),
742 DEF_AGET_APUT(3u, Instruction::AGET, 21u, 112u, 113u),
743 DEF_OTHER1(3u, Instruction::MONITOR_ENTER, 114u),
744 DEF_OTHER1(3u, Instruction::MONITOR_EXIT, 114u),
745 };
746 static const bool expected_ignore_null_check[] = {
747 false, false, true, false /* Not doing LVN. */,
748 false, true /* Set before running NCE. */,
749 false, true, // IGET, IGET
750 false, true, // IPUT, IPUT
751 false, true, // IGET, IPUT
752 false, true, // IPUT, IGET
753 false, true, // INVOKE, IGET
754 false, true, // IGET, INVOKE
755 false, true, // AGET, APUT
756 false, true, // ARRAY_LENGTH, AGET
757 false, true, // MONITOR_ENTER, MONITOR_EXIT
758 };
759
760 PrepareIFields(ifields);
761 PrepareSingleBlock();
762 PrepareMIRs(mirs);
763
764 // Mark IGET 5u as null-checked to test that NCE doesn't clear this flag.
765 mirs_[5u].optimization_flags |= MIR_IGNORE_NULL_CHECK;
766
767 PerformNullCheckElimination();
768 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
769 for (size_t i = 0u; i != arraysize(mirs); ++i) {
770 EXPECT_EQ(expected_ignore_null_check[i],
771 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
772 }
773}
774
775TEST_F(NullCheckEliminationTest, Diamond) {
776 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000777 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
778 { 1u, 1u, 0u, 1u, kDexMemAccessWord },
779 { 2u, 1u, 0u, 2u, kDexMemAccessObject }, // int[].
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100780 };
781 static const MIRDef mirs[] = {
782 // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
783 DEF_IGET_IPUT(3u, Instruction::IPUT, 0u, 100u, 0u),
784 DEF_IGET_IPUT(6u, Instruction::IGET, 1u, 100u, 1u), // Eliminated (BB #3 dominates #6).
785 DEF_IGET_IPUT(3u, Instruction::IGET, 2u, 101u, 0u),
786 DEF_IGET_IPUT(4u, Instruction::IPUT, 3u, 101u, 0u), // Eliminated (BB #3 dominates #4).
787 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
788 DEF_IGET_IPUT(5u, Instruction::IPUT, 5u, 102u, 1u), // Eliminated (BB #3 dominates #5).
789 DEF_IGET_IPUT(4u, Instruction::IPUT, 6u, 103u, 0u),
790 DEF_IGET_IPUT(6u, Instruction::IPUT, 7u, 103u, 1u), // Not eliminated (going through BB #5).
791 DEF_IGET_IPUT(5u, Instruction::IGET, 8u, 104u, 1u),
792 DEF_IGET_IPUT(6u, Instruction::IGET, 9u, 104u, 0u), // Not eliminated (going through BB #4).
Vladimir Marko66c6d7b2014-10-16 15:41:48 +0100793 DEF_INVOKE(4u, Instruction::INVOKE_DIRECT, 105u, 0u /* dummy */),
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100794 DEF_IGET_IPUT(5u, Instruction::IGET, 11u, 105u, 1u),
795 DEF_IGET_IPUT(6u, Instruction::IPUT, 12u, 105u, 0u), // Eliminated.
796 DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 13u, 106u, 2u),
797 DEF_OTHER1(3u, Instruction::IF_EQZ, 13u), // Last insn in the BB #3.
798 DEF_OTHER2(5u, Instruction::NEW_ARRAY, 13u, 107u),
799 DEF_AGET_APUT(6u, Instruction::AGET, 16u, 13u, 108u), // Eliminated.
800 };
801 static const bool expected_ignore_null_check[] = {
802 false, true, // BB #3 IPUT, BB #6 IGET
803 false, true, // BB #3 IGET, BB #4 IPUT
804 false, true, // BB #3 IGET, BB #5 IPUT
805 false, false, // BB #4 IPUT, BB #6 IPUT
806 false, false, // BB #5 IGET, BB #6 IGET
807 false, false, true, // BB #4 INVOKE, BB #5 IGET, BB #6 IPUT
808 false, false, // BB #3 IGET_OBJECT & IF_EQZ
809 false, true, // BB #5 NEW_ARRAY, BB #6 AGET
810 };
811
812 PrepareIFields(ifields);
813 PrepareDiamond();
814 PrepareMIRs(mirs);
815 PerformNullCheckElimination();
816 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
817 for (size_t i = 0u; i != arraysize(mirs); ++i) {
818 EXPECT_EQ(expected_ignore_null_check[i],
819 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
820 }
821}
822
823TEST_F(NullCheckEliminationTest, Loop) {
824 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000825 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
826 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100827 };
828 static const MIRDef mirs[] = {
829 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u),
830 DEF_IGET_IPUT(4u, Instruction::IGET, 1u, 101u, 0u),
831 DEF_IGET_IPUT(5u, Instruction::IGET, 2u, 100u, 1u), // Eliminated.
832 DEF_IGET_IPUT(5u, Instruction::IGET, 3u, 101u, 1u), // Eliminated.
833 DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
834 DEF_IGET_IPUT(4u, Instruction::IGET, 5u, 102u, 1u), // Not eliminated (MOVE_OBJECT_16).
835 DEF_OTHER2(4u, Instruction::MOVE_OBJECT_16, 102u, 103u),
836 };
837 static const bool expected_ignore_null_check[] = {
838 false, false, true, true,
839 false, false, false,
840 };
841
842 PrepareIFields(ifields);
843 PrepareLoop();
844 PrepareMIRs(mirs);
845 PerformNullCheckElimination();
846 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
847 for (size_t i = 0u; i != arraysize(mirs); ++i) {
848 EXPECT_EQ(expected_ignore_null_check[i],
849 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
850 }
851}
852
853TEST_F(NullCheckEliminationTest, Catch) {
854 static const IFieldDef ifields[] = {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000855 { 0u, 1u, 0u, 0u, kDexMemAccessWord },
856 { 1u, 1u, 1u, 1u, kDexMemAccessWord },
Vladimir Marko7baa6f82014-10-09 18:01:24 +0100857 };
858 static const MIRDef mirs[] = {
859 DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u), // Before the exception edge.
860 DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 101u, 0u), // Before the exception edge.
861 DEF_IGET_IPUT(4u, Instruction::IGET, 2u, 102u, 0u), // After the exception edge.
862 DEF_IGET_IPUT(4u, Instruction::IGET, 3u, 103u, 0u), // After the exception edge.
863 DEF_IGET_IPUT(5u, Instruction::IGET, 4u, 100u, 1u), // In catch handler; eliminated.
864 DEF_IGET_IPUT(5u, Instruction::IGET, 5u, 102u, 1u), // In catch handler; not eliminated.
865 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 100u, 0u), // Null check eliminated.
866 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 101u, 1u), // Null check eliminated.
867 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 102u, 0u), // Null check eliminated.
868 DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 103u, 1u), // Null check not eliminated.
869 };
870 static const bool expected_ignore_null_check[] = {
871 false, false, false, false, true, false, true, true, true, false
872 };
873
874 PrepareIFields(ifields);
875 PrepareCatch();
876 PrepareMIRs(mirs);
877 PerformNullCheckElimination();
878 ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
879 for (size_t i = 0u; i != arraysize(mirs); ++i) {
880 EXPECT_EQ(expected_ignore_null_check[i],
881 (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
882 }
883}
884
885// Undefine MIR_DEF for null check elimination.
886#undef MIR_DEF
887
Vladimir Markobfea9c22014-01-17 17:49:33 +0000888} // namespace art