blob: 6ab6c51a1fa546c99aed4c9c4599b7f08e8be6e3 [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) {
Vladimir Markof59f18b2014-02-17 15:53:57 +000080 }
81
82 template <size_t count>
83 void PrepareIFields(const IFieldDef (&defs)[count]) {
84 DoPrepareIFields(defs, count);
85 }
86
87 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
Vladimir Markof59f18b2014-02-17 15:53:57 +000088 }
89
90 template <size_t count>
91 void PrepareSFields(const SFieldDef (&defs)[count]) {
92 DoPrepareSFields(defs, count);
93 }
94
95 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
96 mir_count_ = count;
97 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, ArenaAllocator::kAllocMIR));
98 ssa_reps_.resize(count);
99 for (size_t i = 0u; i != count; ++i) {
100 const MIRDef* def = &defs[i];
101 MIR* mir = &mirs_[i];
102 mir->dalvikInsn.opcode = def->opcode;
103 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
104 mir->dalvikInsn.vB_wide = def->value;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000105 mir->ssa_rep = &ssa_reps_[i];
106 mir->ssa_rep->num_uses = def->num_uses;
107 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
108 mir->ssa_rep->fp_use = nullptr; // Not used by LVN.
109 mir->ssa_rep->num_defs = def->num_defs;
110 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN.
111 mir->ssa_rep->fp_def = nullptr; // Not used by LVN.
112 mir->dalvikInsn.opcode = def->opcode;
113 mir->offset = i; // LVN uses offset only for debug output
114 mir->width = 1u; // Not used by LVN.
115 mir->optimization_flags = 0u;
116
117 if (i != 0u) {
118 mirs_[i - 1u].next = mir;
119 }
120 }
121 mirs_[count - 1u].next = nullptr;
122 }
123
124 template <size_t count>
125 void PrepareMIRs(const MIRDef (&defs)[count]) {
126 DoPrepareMIRs(defs, count);
127 }
128
129 void PerformLVN() {
130 value_names_.resize(mir_count_);
131 for (size_t i = 0; i != mir_count_; ++i) {
132 value_names_[i] = lvn_.GetValueNumber(&mirs_[i]);
133 }
134 }
135
136 LocalValueNumberingTest() : pool_(), cu_(&pool_), mir_count_(0u), mirs_(nullptr), lvn_(&cu_) {
137 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
138 }
139
140 ArenaPool pool_;
141 CompilationUnit cu_;
142 size_t mir_count_;
143 MIR* mirs_;
144 std::vector<SSARepresentation> ssa_reps_;
145 std::vector<uint16_t> value_names_;
146 LocalValueNumbering lvn_;
147};
148
Ian Rogers9c86a022014-02-21 16:40:21 +0000149#if 0 // TODO: re-enable when LVN is handling memory igets.
Vladimir Markof59f18b2014-02-17 15:53:57 +0000150TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) {
151 static const IFieldDef ifields[] = {
152 { 1u, 1u, 1u, false }
153 };
154 static const MIRDef mirs[] = {
155 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
156 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
157 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u),
158 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
159 };
160
161 PrepareIFields(ifields);
162 PrepareMIRs(mirs);
163 PerformLVN();
164 ASSERT_EQ(value_names_.size(), 4u);
165 EXPECT_EQ(value_names_[0], value_names_[1]);
166 EXPECT_NE(value_names_[0], value_names_[3]);
167 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
168 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
169 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
170 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
171}
Ian Rogers9c86a022014-02-21 16:40:21 +0000172#endif
Vladimir Markof59f18b2014-02-17 15:53:57 +0000173
174TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) {
175 static const IFieldDef ifields[] = {
176 { 1u, 1u, 1u, false },
177 { 2u, 1u, 2u, false },
178 };
179 static const MIRDef mirs[] = {
180 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
181 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // May alias.
182 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
183 DEF_IGET(Instruction::IGET, 3u, 0u, 1u),
184 DEF_IGET(Instruction::IGET, 4u, 2u, 1u),
185 };
186
187 PrepareIFields(ifields);
188 PrepareMIRs(mirs);
189 PerformLVN();
190 ASSERT_EQ(value_names_.size(), 5u);
191 EXPECT_NE(value_names_[0], value_names_[2]);
192 EXPECT_NE(value_names_[3], value_names_[4]);
193 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
194 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
195 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
196 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
197 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
198}
199
Ian Rogers9c86a022014-02-21 16:40:21 +0000200#if 0 // TODO: re-enable when LVN is handling memory igets.
Vladimir Markof59f18b2014-02-17 15:53:57 +0000201TEST_F(LocalValueNumberingTest, TestUniquePreserve1) {
202 static const IFieldDef ifields[] = {
203 { 1u, 1u, 1u, false },
204 };
205 static const MIRDef mirs[] = {
206 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
207 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
208 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique.
209 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
210 };
211
212 PrepareIFields(ifields);
213 PrepareMIRs(mirs);
214 PerformLVN();
215 ASSERT_EQ(value_names_.size(), 4u);
216 EXPECT_EQ(value_names_[1], value_names_[3]);
217 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
218 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
219 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
220}
Ian Rogers9c86a022014-02-21 16:40:21 +0000221#endif
Vladimir Markof59f18b2014-02-17 15:53:57 +0000222
Ian Rogers9c86a022014-02-21 16:40:21 +0000223#if 0 // TODO: re-enable when LVN is handling memory igets.
Vladimir Markof59f18b2014-02-17 15:53:57 +0000224TEST_F(LocalValueNumberingTest, TestUniquePreserve2) {
225 static const IFieldDef ifields[] = {
226 { 1u, 1u, 1u, false },
227 };
228 static const MIRDef mirs[] = {
229 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
230 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
231 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique.
232 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
233 };
234
235 PrepareIFields(ifields);
236 PrepareMIRs(mirs);
237 PerformLVN();
238 ASSERT_EQ(value_names_.size(), 4u);
239 EXPECT_EQ(value_names_[1], value_names_[3]);
240 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
241 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
242 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
243}
Ian Rogers9c86a022014-02-21 16:40:21 +0000244#endif
Vladimir Markof59f18b2014-02-17 15:53:57 +0000245
Ian Rogers9c86a022014-02-21 16:40:21 +0000246#if 0 // TODO: re-enable when LVN is handling memory igets.
Vladimir Markof59f18b2014-02-17 15:53:57 +0000247TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) {
248 static const IFieldDef ifields[] = {
249 { 1u, 1u, 1u, false },
250 };
251 static const MIRDef mirs[] = {
252 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
253 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
254 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique.
255 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
256 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore.
257 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
258 };
259
260 PrepareIFields(ifields);
261 PrepareMIRs(mirs);
262 PerformLVN();
263 ASSERT_EQ(value_names_.size(), 6u);
264 EXPECT_EQ(value_names_[1], value_names_[3]);
265 EXPECT_NE(value_names_[1], value_names_[5]);
266 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
267 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
268 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
269}
Ian Rogers9c86a022014-02-21 16:40:21 +0000270#endif
Vladimir Markof59f18b2014-02-17 15:53:57 +0000271
272TEST_F(LocalValueNumberingTest, TestVolatile) {
273 static const IFieldDef ifields[] = {
274 { 1u, 1u, 1u, false },
275 { 2u, 1u, 2u, true },
276 };
277 static const MIRDef mirs[] = {
278 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile.
279 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
280 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
281 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
282 };
283
284 PrepareIFields(ifields);
285 PrepareMIRs(mirs);
286 PerformLVN();
287 ASSERT_EQ(value_names_.size(), 4u);
288 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
289 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
290 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
291 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
292 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
293 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
294}
295
296} // namespace art