blob: 230c0125737aed05cc356b4c837b6685faa0188a [file] [log] [blame]
Vladimir Markof59f18b2014-02-17 15:53:57 +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 "local_value_numbering.h"
20#include "compiler_internals.h"
21#include "gtest/gtest.h"
22
23namespace art {
24
25class LocalValueNumberingTest : public testing::Test {
26 protected:
27 struct IFieldDef {
28 uint16_t field_idx;
29 uintptr_t declaring_dex_file;
30 uint16_t declaring_field_idx;
31 bool is_volatile;
32 };
33
34 struct SFieldDef {
35 uint16_t field_idx;
36 uintptr_t declaring_dex_file;
37 uint16_t declaring_field_idx;
38 bool is_volatile;
39 };
40
41 struct MIRDef {
42 static constexpr size_t kMaxSsaDefs = 2;
43 static constexpr size_t kMaxSsaUses = 3;
44
45 Instruction::Code opcode;
46 int64_t value;
47 uint32_t field_annotation;
48 size_t num_uses;
49 int32_t uses[kMaxSsaUses];
50 size_t num_defs;
51 int32_t defs[kMaxSsaDefs];
52 };
53
54#define DEF_CONST(opcode, reg, value) \
55 { opcode, value, 0u, 0, { }, 1, { reg } }
56#define DEF_CONST_WIDE(opcode, reg, value) \
57 { opcode, value, 0u, 0, { }, 2, { reg, reg + 1 } }
58#define DEF_IGET(opcode, reg, obj, field_annotation) \
59 { opcode, 0u, field_annotation, 1, { obj }, 1, { reg } }
60#define DEF_IGET_WIDE(opcode, reg, obj, field_annotation) \
61 { opcode, 0u, field_annotation, 1, { obj }, 2, { reg, reg + 1 } }
62#define DEF_IPUT(opcode, reg, obj, field_annotation) \
63 { opcode, 0u, field_annotation, 2, { reg, obj }, 0, { } }
64#define DEF_IPUT_WIDE(opcode, reg, obj, field_annotation) \
65 { opcode, 0u, field_annotation, 3, { reg, reg + 1, obj }, 0, { } }
66#define DEF_SGET(opcode, reg, field_annotation) \
67 { opcode, 0u, field_annotation, 0, { }, 1, { reg } }
68#define DEF_SGET_WIDE(opcode, reg, field_annotation) \
69 { opcode, 0u, field_annotation, 0, { }, 2, { reg, reg + 1 } }
70#define DEF_SPUT(opcode, reg, field_annotation) \
71 { opcode, 0u, field_annotation, 1, { reg }, 0, { } }
72#define DEF_SPUT_WIDE(opcode, reg, field_annotation) \
73 { opcode, 0u, field_annotation, 2, { reg, reg + 1 }, 0, { } }
74#define DEF_INVOKE1(opcode, reg) \
75 { opcode, 0u, 0u, 1, { reg }, 0, { } }
76#define DEF_UNIQUE_REF(opcode, reg) \
77 { opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
78
79 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
80 cu_.mir_graph->ifield_annotations_.Reset();
81 cu_.mir_graph->ifield_annotations_.Resize(count);
82 for (size_t i = 0u; i != count; ++i) {
83 const IFieldDef* def = &defs[i];
84 IFieldAnnotation annotation(def->field_idx);
85 if (def->declaring_dex_file != 0u) {
86 annotation.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
87 annotation.declaring_field_idx_ = def->declaring_field_idx;
88 annotation.is_volatile_ = def->is_volatile ? 1u : 0u;
89 }
90 cu_.mir_graph->ifield_annotations_.Insert(annotation);
91 }
92 }
93
94 template <size_t count>
95 void PrepareIFields(const IFieldDef (&defs)[count]) {
96 DoPrepareIFields(defs, count);
97 }
98
99 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
100 cu_.mir_graph->sfield_annotations_.Reset();
101 cu_.mir_graph->sfield_annotations_.Resize(count);
102 for (size_t i = 0u; i != count; ++i) {
103 const SFieldDef* def = &defs[i];
104 SFieldAnnotation annotation(def->field_idx);
105 if (def->declaring_dex_file != 0u) {
106 annotation.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
107 annotation.declaring_field_idx_ = def->declaring_field_idx;
108 annotation.is_volatile_ = def->is_volatile ? 1u : 0u;
109 }
110 cu_.mir_graph->sfield_annotations_.Insert(annotation);
111 }
112 }
113
114 template <size_t count>
115 void PrepareSFields(const SFieldDef (&defs)[count]) {
116 DoPrepareSFields(defs, count);
117 }
118
119 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
120 mir_count_ = count;
121 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, ArenaAllocator::kAllocMIR));
122 ssa_reps_.resize(count);
123 for (size_t i = 0u; i != count; ++i) {
124 const MIRDef* def = &defs[i];
125 MIR* mir = &mirs_[i];
126 mir->dalvikInsn.opcode = def->opcode;
127 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
128 mir->dalvikInsn.vB_wide = def->value;
129 if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
130 ASSERT_LT(def->field_annotation, cu_.mir_graph->ifield_annotations_.Size());
131 mir->meta.ifield_annotation = def->field_annotation;
132 } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
133 ASSERT_LT(def->field_annotation, cu_.mir_graph->sfield_annotations_.Size());
134 mir->meta.sfield_annotation = def->field_annotation;
135 }
136 mir->ssa_rep = &ssa_reps_[i];
137 mir->ssa_rep->num_uses = def->num_uses;
138 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
139 mir->ssa_rep->fp_use = nullptr; // Not used by LVN.
140 mir->ssa_rep->num_defs = def->num_defs;
141 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN.
142 mir->ssa_rep->fp_def = nullptr; // Not used by LVN.
143 mir->dalvikInsn.opcode = def->opcode;
144 mir->offset = i; // LVN uses offset only for debug output
145 mir->width = 1u; // Not used by LVN.
146 mir->optimization_flags = 0u;
147
148 if (i != 0u) {
149 mirs_[i - 1u].next = mir;
150 }
151 }
152 mirs_[count - 1u].next = nullptr;
153 }
154
155 template <size_t count>
156 void PrepareMIRs(const MIRDef (&defs)[count]) {
157 DoPrepareMIRs(defs, count);
158 }
159
160 void PerformLVN() {
161 value_names_.resize(mir_count_);
162 for (size_t i = 0; i != mir_count_; ++i) {
163 value_names_[i] = lvn_.GetValueNumber(&mirs_[i]);
164 }
165 }
166
167 LocalValueNumberingTest() : pool_(), cu_(&pool_), mir_count_(0u), mirs_(nullptr), lvn_(&cu_) {
168 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
169 }
170
171 ArenaPool pool_;
172 CompilationUnit cu_;
173 size_t mir_count_;
174 MIR* mirs_;
175 std::vector<SSARepresentation> ssa_reps_;
176 std::vector<uint16_t> value_names_;
177 LocalValueNumbering lvn_;
178};
179
180TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) {
181 static const IFieldDef ifields[] = {
182 { 1u, 1u, 1u, false }
183 };
184 static const MIRDef mirs[] = {
185 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
186 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
187 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u),
188 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
189 };
190
191 PrepareIFields(ifields);
192 PrepareMIRs(mirs);
193 PerformLVN();
194 ASSERT_EQ(value_names_.size(), 4u);
195 EXPECT_EQ(value_names_[0], value_names_[1]);
196 EXPECT_NE(value_names_[0], value_names_[3]);
197 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
198 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
199 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
200 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
201}
202
203TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) {
204 static const IFieldDef ifields[] = {
205 { 1u, 1u, 1u, false },
206 { 2u, 1u, 2u, false },
207 };
208 static const MIRDef mirs[] = {
209 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
210 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // May alias.
211 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
212 DEF_IGET(Instruction::IGET, 3u, 0u, 1u),
213 DEF_IGET(Instruction::IGET, 4u, 2u, 1u),
214 };
215
216 PrepareIFields(ifields);
217 PrepareMIRs(mirs);
218 PerformLVN();
219 ASSERT_EQ(value_names_.size(), 5u);
220 EXPECT_NE(value_names_[0], value_names_[2]);
221 EXPECT_NE(value_names_[3], value_names_[4]);
222 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
223 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
224 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
225 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
226 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
227}
228
229TEST_F(LocalValueNumberingTest, TestUniquePreserve1) {
230 static const IFieldDef ifields[] = {
231 { 1u, 1u, 1u, false },
232 };
233 static const MIRDef mirs[] = {
234 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
235 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
236 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique.
237 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
238 };
239
240 PrepareIFields(ifields);
241 PrepareMIRs(mirs);
242 PerformLVN();
243 ASSERT_EQ(value_names_.size(), 4u);
244 EXPECT_EQ(value_names_[1], value_names_[3]);
245 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
246 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
247 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
248}
249
250TEST_F(LocalValueNumberingTest, TestUniquePreserve2) {
251 static const IFieldDef ifields[] = {
252 { 1u, 1u, 1u, false },
253 };
254 static const MIRDef mirs[] = {
255 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
256 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
257 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique.
258 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
259 };
260
261 PrepareIFields(ifields);
262 PrepareMIRs(mirs);
263 PerformLVN();
264 ASSERT_EQ(value_names_.size(), 4u);
265 EXPECT_EQ(value_names_[1], value_names_[3]);
266 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
267 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
268 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
269}
270
271TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) {
272 static const IFieldDef ifields[] = {
273 { 1u, 1u, 1u, false },
274 };
275 static const MIRDef mirs[] = {
276 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
277 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
278 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique.
279 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
280 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore.
281 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
282 };
283
284 PrepareIFields(ifields);
285 PrepareMIRs(mirs);
286 PerformLVN();
287 ASSERT_EQ(value_names_.size(), 6u);
288 EXPECT_EQ(value_names_[1], value_names_[3]);
289 EXPECT_NE(value_names_[1], value_names_[5]);
290 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
291 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
292 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
293}
294
295TEST_F(LocalValueNumberingTest, TestVolatile) {
296 static const IFieldDef ifields[] = {
297 { 1u, 1u, 1u, false },
298 { 2u, 1u, 2u, true },
299 };
300 static const MIRDef mirs[] = {
301 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile.
302 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
303 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
304 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
305 };
306
307 PrepareIFields(ifields);
308 PrepareMIRs(mirs);
309 PerformLVN();
310 ASSERT_EQ(value_names_.size(), 4u);
311 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
312 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
313 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
314 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
315 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
316 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
317}
318
319} // namespace art