local_value_numbering_test.cc revision ef562fdef7e0071cae11e07a9e53fb152d0934b8
1/* 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_info; 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_info) \ 59 { opcode, 0u, field_info, 1, { obj }, 1, { reg } } 60#define DEF_IGET_WIDE(opcode, reg, obj, field_info) \ 61 { opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } } 62#define DEF_IPUT(opcode, reg, obj, field_info) \ 63 { opcode, 0u, field_info, 2, { reg, obj }, 0, { } } 64#define DEF_IPUT_WIDE(opcode, reg, obj, field_info) \ 65 { opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } } 66#define DEF_SGET(opcode, reg, field_info) \ 67 { opcode, 0u, field_info, 0, { }, 1, { reg } } 68#define DEF_SGET_WIDE(opcode, reg, field_info) \ 69 { opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } } 70#define DEF_SPUT(opcode, reg, field_info) \ 71 { opcode, 0u, field_info, 1, { reg }, 0, { } } 72#define DEF_SPUT_WIDE(opcode, reg, field_info) \ 73 { opcode, 0u, field_info, 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_lowering_infos_.Reset(); 81 cu_.mir_graph->ifield_lowering_infos_.Resize(count); 82 for (size_t i = 0u; i != count; ++i) { 83 const IFieldDef* def = &defs[i]; 84 MirIFieldLoweringInfo field_info(def->field_idx); 85 if (def->declaring_dex_file != 0u) { 86 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); 87 field_info.declaring_field_idx_ = def->declaring_field_idx; 88 field_info.flags_ = 0u | // Without kFlagIsStatic. 89 (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u); 90 } 91 cu_.mir_graph->ifield_lowering_infos_.Insert(field_info); 92 } 93 } 94 95 template <size_t count> 96 void PrepareIFields(const IFieldDef (&defs)[count]) { 97 DoPrepareIFields(defs, count); 98 } 99 100 void DoPrepareSFields(const SFieldDef* defs, size_t count) { 101 cu_.mir_graph->sfield_lowering_infos_.Reset(); 102 cu_.mir_graph->sfield_lowering_infos_.Resize(count); 103 for (size_t i = 0u; i != count; ++i) { 104 const SFieldDef* def = &defs[i]; 105 MirSFieldLoweringInfo field_info(def->field_idx); 106 if (def->declaring_dex_file != 0u) { 107 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); 108 field_info.declaring_field_idx_ = def->declaring_field_idx; 109 field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic | 110 (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u); 111 } 112 cu_.mir_graph->sfield_lowering_infos_.Insert(field_info); 113 } 114 } 115 116 template <size_t count> 117 void PrepareSFields(const SFieldDef (&defs)[count]) { 118 DoPrepareSFields(defs, count); 119 } 120 121 void DoPrepareMIRs(const MIRDef* defs, size_t count) { 122 mir_count_ = count; 123 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR)); 124 ssa_reps_.resize(count); 125 for (size_t i = 0u; i != count; ++i) { 126 const MIRDef* def = &defs[i]; 127 MIR* mir = &mirs_[i]; 128 mir->dalvikInsn.opcode = def->opcode; 129 mir->dalvikInsn.vB = static_cast<int32_t>(def->value); 130 mir->dalvikInsn.vB_wide = def->value; 131 if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) { 132 ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.Size()); 133 mir->meta.ifield_lowering_info = def->field_info; 134 } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) { 135 ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.Size()); 136 mir->meta.sfield_lowering_info = def->field_info; 137 } 138 mir->ssa_rep = &ssa_reps_[i]; 139 mir->ssa_rep->num_uses = def->num_uses; 140 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN. 141 mir->ssa_rep->fp_use = nullptr; // Not used by LVN. 142 mir->ssa_rep->num_defs = def->num_defs; 143 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN. 144 mir->ssa_rep->fp_def = nullptr; // Not used by LVN. 145 mir->dalvikInsn.opcode = def->opcode; 146 mir->offset = i; // LVN uses offset only for debug output 147 mir->optimization_flags = 0u; 148 149 if (i != 0u) { 150 mirs_[i - 1u].next = mir; 151 } 152 } 153 mirs_[count - 1u].next = nullptr; 154 } 155 156 template <size_t count> 157 void PrepareMIRs(const MIRDef (&defs)[count]) { 158 DoPrepareMIRs(defs, count); 159 } 160 161 void PerformLVN() { 162 value_names_.resize(mir_count_); 163 for (size_t i = 0; i != mir_count_; ++i) { 164 value_names_[i] = lvn_->GetValueNumber(&mirs_[i]); 165 } 166 } 167 168 LocalValueNumberingTest() 169 : pool_(), 170 cu_(&pool_), 171 mir_count_(0u), 172 mirs_(nullptr), 173 lvn_(LocalValueNumbering::Create(&cu_)) { 174 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena)); 175 } 176 177 ArenaPool pool_; 178 CompilationUnit cu_; 179 size_t mir_count_; 180 MIR* mirs_; 181 std::vector<SSARepresentation> ssa_reps_; 182 std::vector<uint16_t> value_names_; 183 std::unique_ptr<LocalValueNumbering> lvn_; 184}; 185 186TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) { 187 static const IFieldDef ifields[] = { 188 { 1u, 1u, 1u, false } 189 }; 190 static const MIRDef mirs[] = { 191 DEF_IGET(Instruction::IGET, 0u, 10u, 0u), 192 DEF_IGET(Instruction::IGET, 1u, 10u, 0u), 193 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), 194 DEF_IGET(Instruction::IGET, 2u, 10u, 0u), 195 }; 196 197 PrepareIFields(ifields); 198 PrepareMIRs(mirs); 199 PerformLVN(); 200 ASSERT_EQ(value_names_.size(), 4u); 201 EXPECT_EQ(value_names_[0], value_names_[1]); 202 EXPECT_NE(value_names_[0], value_names_[3]); 203 EXPECT_EQ(mirs_[0].optimization_flags, 0u); 204 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK); 205 EXPECT_EQ(mirs_[2].optimization_flags, 0u); 206 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK); 207} 208 209TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) { 210 static const IFieldDef ifields[] = { 211 { 1u, 1u, 1u, false }, 212 { 2u, 1u, 2u, false }, 213 }; 214 static const MIRDef mirs[] = { 215 DEF_IGET(Instruction::IGET, 0u, 10u, 0u), 216 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // May alias. 217 DEF_IGET(Instruction::IGET, 2u, 10u, 0u), 218 DEF_IGET(Instruction::IGET, 3u, 0u, 1u), 219 DEF_IGET(Instruction::IGET, 4u, 2u, 1u), 220 }; 221 222 PrepareIFields(ifields); 223 PrepareMIRs(mirs); 224 PerformLVN(); 225 ASSERT_EQ(value_names_.size(), 5u); 226 EXPECT_NE(value_names_[0], value_names_[2]); 227 EXPECT_NE(value_names_[3], value_names_[4]); 228 EXPECT_EQ(mirs_[0].optimization_flags, 0u); 229 EXPECT_EQ(mirs_[1].optimization_flags, 0u); 230 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK); 231 EXPECT_EQ(mirs_[3].optimization_flags, 0u); 232 EXPECT_EQ(mirs_[4].optimization_flags, 0u); 233} 234 235TEST_F(LocalValueNumberingTest, TestUniquePreserve1) { 236 static const IFieldDef ifields[] = { 237 { 1u, 1u, 1u, false }, 238 }; 239 static const MIRDef mirs[] = { 240 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u), 241 DEF_IGET(Instruction::IGET, 0u, 10u, 0u), 242 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique. 243 DEF_IGET(Instruction::IGET, 2u, 10u, 0u), 244 }; 245 246 PrepareIFields(ifields); 247 PrepareMIRs(mirs); 248 PerformLVN(); 249 ASSERT_EQ(value_names_.size(), 4u); 250 EXPECT_EQ(value_names_[1], value_names_[3]); 251 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK); 252 EXPECT_EQ(mirs_[2].optimization_flags, 0u); 253 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK); 254} 255 256TEST_F(LocalValueNumberingTest, TestUniquePreserve2) { 257 static const IFieldDef ifields[] = { 258 { 1u, 1u, 1u, false }, 259 }; 260 static const MIRDef mirs[] = { 261 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u), 262 DEF_IGET(Instruction::IGET, 0u, 10u, 0u), 263 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique. 264 DEF_IGET(Instruction::IGET, 2u, 10u, 0u), 265 }; 266 267 PrepareIFields(ifields); 268 PrepareMIRs(mirs); 269 PerformLVN(); 270 ASSERT_EQ(value_names_.size(), 4u); 271 EXPECT_EQ(value_names_[1], value_names_[3]); 272 EXPECT_EQ(mirs_[1].optimization_flags, 0u); 273 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK); 274 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK); 275} 276 277TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) { 278 static const IFieldDef ifields[] = { 279 { 1u, 1u, 1u, false }, 280 }; 281 static const MIRDef mirs[] = { 282 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u), 283 DEF_IGET(Instruction::IGET, 0u, 10u, 0u), 284 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique. 285 DEF_IGET(Instruction::IGET, 2u, 10u, 0u), 286 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore. 287 DEF_IGET(Instruction::IGET, 3u, 10u, 0u), 288 }; 289 290 PrepareIFields(ifields); 291 PrepareMIRs(mirs); 292 PerformLVN(); 293 ASSERT_EQ(value_names_.size(), 6u); 294 EXPECT_EQ(value_names_[1], value_names_[3]); 295 EXPECT_NE(value_names_[1], value_names_[5]); 296 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK); 297 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK); 298 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK); 299} 300 301TEST_F(LocalValueNumberingTest, TestVolatile) { 302 static const IFieldDef ifields[] = { 303 { 1u, 1u, 1u, false }, 304 { 2u, 1u, 2u, true }, 305 }; 306 static const MIRDef mirs[] = { 307 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile. 308 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile. 309 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile. 310 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile. 311 }; 312 313 PrepareIFields(ifields); 314 PrepareMIRs(mirs); 315 PerformLVN(); 316 ASSERT_EQ(value_names_.size(), 4u); 317 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name. 318 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile. 319 EXPECT_EQ(mirs_[0].optimization_flags, 0u); 320 EXPECT_EQ(mirs_[1].optimization_flags, 0u); 321 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK); 322 EXPECT_EQ(mirs_[3].optimization_flags, 0u); 323} 324 325} // namespace art 326