1 /* 2 * Copyright (C) 2015 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 "induction_var_range.h" 18 19 #include "base/arena_allocator.h" 20 #include "builder.h" 21 #include "induction_var_analysis.h" 22 #include "nodes.h" 23 #include "optimizing_unit_test.h" 24 25 namespace art { 26 27 using Value = InductionVarRange::Value; 28 29 /** 30 * Fixture class for the InductionVarRange tests. 31 */ 32 class InductionVarRangeTest : public OptimizingUnitTest { 33 public: 34 InductionVarRangeTest() 35 : graph_(CreateGraph()), 36 iva_(new (GetAllocator()) HInductionVarAnalysis(graph_)), 37 range_(iva_) { 38 BuildGraph(); 39 } 40 41 ~InductionVarRangeTest() { } 42 43 void ExpectEqual(Value v1, Value v2) { 44 EXPECT_EQ(v1.instruction, v2.instruction); 45 EXPECT_EQ(v1.a_constant, v2.a_constant); 46 EXPECT_EQ(v1.b_constant, v2.b_constant); 47 EXPECT_EQ(v1.is_known, v2.is_known); 48 } 49 50 void ExpectInt(int32_t value, HInstruction* i) { 51 ASSERT_TRUE(i->IsIntConstant()); 52 EXPECT_EQ(value, i->AsIntConstant()->GetValue()); 53 } 54 55 // 56 // Construction methods. 57 // 58 59 /** Constructs bare minimum graph. */ 60 void BuildGraph() { 61 graph_->SetNumberOfVRegs(1); 62 entry_block_ = new (GetAllocator()) HBasicBlock(graph_); 63 exit_block_ = new (GetAllocator()) HBasicBlock(graph_); 64 graph_->AddBlock(entry_block_); 65 graph_->AddBlock(exit_block_); 66 graph_->SetEntryBlock(entry_block_); 67 graph_->SetExitBlock(exit_block_); 68 // Two parameters. 69 x_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(), 70 dex::TypeIndex(0), 71 0, 72 DataType::Type::kInt32); 73 entry_block_->AddInstruction(x_); 74 y_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(), 75 dex::TypeIndex(0), 76 0, 77 DataType::Type::kInt32); 78 entry_block_->AddInstruction(y_); 79 // Set arbitrary range analysis hint while testing private methods. 80 SetHint(x_); 81 } 82 83 /** Constructs loop with given upper bound. */ 84 void BuildLoop(int32_t lower, HInstruction* upper, int32_t stride) { 85 // Control flow. 86 loop_preheader_ = new (GetAllocator()) HBasicBlock(graph_); 87 graph_->AddBlock(loop_preheader_); 88 loop_header_ = new (GetAllocator()) HBasicBlock(graph_); 89 graph_->AddBlock(loop_header_); 90 loop_body_ = new (GetAllocator()) HBasicBlock(graph_); 91 graph_->AddBlock(loop_body_); 92 HBasicBlock* return_block = new (GetAllocator()) HBasicBlock(graph_); 93 graph_->AddBlock(return_block); 94 entry_block_->AddSuccessor(loop_preheader_); 95 loop_preheader_->AddSuccessor(loop_header_); 96 loop_header_->AddSuccessor(loop_body_); 97 loop_header_->AddSuccessor(return_block); 98 loop_body_->AddSuccessor(loop_header_); 99 return_block->AddSuccessor(exit_block_); 100 // Instructions. 101 loop_preheader_->AddInstruction(new (GetAllocator()) HGoto()); 102 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32); 103 loop_header_->AddPhi(phi); 104 phi->AddInput(graph_->GetIntConstant(lower)); // i = l 105 if (stride > 0) { 106 condition_ = new (GetAllocator()) HLessThan(phi, upper); // i < u 107 } else { 108 condition_ = new (GetAllocator()) HGreaterThan(phi, upper); // i > u 109 } 110 loop_header_->AddInstruction(condition_); 111 loop_header_->AddInstruction(new (GetAllocator()) HIf(condition_)); 112 increment_ = 113 new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, graph_->GetIntConstant(stride)); 114 loop_body_->AddInstruction(increment_); // i += s 115 phi->AddInput(increment_); 116 loop_body_->AddInstruction(new (GetAllocator()) HGoto()); 117 return_block->AddInstruction(new (GetAllocator()) HReturnVoid()); 118 exit_block_->AddInstruction(new (GetAllocator()) HExit()); 119 } 120 121 /** Constructs SSA and performs induction variable analysis. */ 122 void PerformInductionVarAnalysis() { 123 graph_->BuildDominatorTree(); 124 iva_->Run(); 125 } 126 127 /** Sets hint. */ 128 void SetHint(HInstruction* hint) { 129 range_.chase_hint_ = hint; 130 } 131 132 /** Constructs an invariant. */ 133 HInductionVarAnalysis::InductionInfo* CreateInvariant(char opc, 134 HInductionVarAnalysis::InductionInfo* a, 135 HInductionVarAnalysis::InductionInfo* b) { 136 HInductionVarAnalysis::InductionOp op; 137 switch (opc) { 138 case '+': op = HInductionVarAnalysis::kAdd; break; 139 case '-': op = HInductionVarAnalysis::kSub; break; 140 case 'n': op = HInductionVarAnalysis::kNeg; break; 141 case '*': op = HInductionVarAnalysis::kMul; break; 142 case '/': op = HInductionVarAnalysis::kDiv; break; 143 case '%': op = HInductionVarAnalysis::kRem; break; 144 case '^': op = HInductionVarAnalysis::kXor; break; 145 case '<': op = HInductionVarAnalysis::kLT; break; 146 default: op = HInductionVarAnalysis::kNop; break; 147 } 148 return iva_->CreateInvariantOp(op, a, b); 149 } 150 151 /** Constructs a fetch. */ 152 HInductionVarAnalysis::InductionInfo* CreateFetch(HInstruction* fetch) { 153 return iva_->CreateInvariantFetch(fetch); 154 } 155 156 /** Constructs a constant. */ 157 HInductionVarAnalysis::InductionInfo* CreateConst(int32_t c) { 158 return CreateFetch(graph_->GetIntConstant(c)); 159 } 160 161 /** Constructs a constant trip-count. */ 162 HInductionVarAnalysis::InductionInfo* CreateTripCount(int32_t tc, bool in_loop, bool safe) { 163 HInductionVarAnalysis::InductionOp op = HInductionVarAnalysis::kTripCountInBodyUnsafe; 164 if (in_loop && safe) { 165 op = HInductionVarAnalysis::kTripCountInLoop; 166 } else if (in_loop) { 167 op = HInductionVarAnalysis::kTripCountInLoopUnsafe; 168 } else if (safe) { 169 op = HInductionVarAnalysis::kTripCountInBody; 170 } 171 // Return TC with taken-test 0 < TC. 172 return iva_->CreateTripCount(op, 173 CreateConst(tc), 174 CreateInvariant('<', CreateConst(0), CreateConst(tc)), 175 DataType::Type::kInt32); 176 } 177 178 /** Constructs a linear a * i + b induction. */ 179 HInductionVarAnalysis::InductionInfo* CreateLinear(int32_t a, int32_t b) { 180 return iva_->CreateInduction(HInductionVarAnalysis::kLinear, 181 HInductionVarAnalysis::kNop, 182 CreateConst(a), 183 CreateConst(b), 184 nullptr, 185 DataType::Type::kInt32); 186 } 187 188 /** Constructs a polynomial sum(a * i + b) + c induction. */ 189 HInductionVarAnalysis::InductionInfo* CreatePolynomial(int32_t a, int32_t b, int32_t c) { 190 return iva_->CreateInduction(HInductionVarAnalysis::kPolynomial, 191 HInductionVarAnalysis::kNop, 192 CreateLinear(a, b), 193 CreateConst(c), 194 nullptr, 195 DataType::Type::kInt32); 196 } 197 198 /** Constructs a geometric a * f^i + b induction. */ 199 HInductionVarAnalysis::InductionInfo* CreateGeometric(int32_t a, int32_t b, int32_t f, char op) { 200 return iva_->CreateInduction(HInductionVarAnalysis::kGeometric, 201 op == '*' ? HInductionVarAnalysis::kMul 202 : HInductionVarAnalysis::kDiv, 203 CreateConst(a), 204 CreateConst(b), 205 graph_->GetIntConstant(f), 206 DataType::Type::kInt32); 207 } 208 209 /** Constructs a range [lo, hi] using a periodic induction. */ 210 HInductionVarAnalysis::InductionInfo* CreateRange(int32_t lo, int32_t hi) { 211 return iva_->CreateInduction(HInductionVarAnalysis::kPeriodic, 212 HInductionVarAnalysis::kNop, 213 CreateConst(lo), 214 CreateConst(hi), 215 nullptr, 216 DataType::Type::kInt32); 217 } 218 219 /** Constructs a wrap-around induction consisting of a constant, followed by info. */ 220 HInductionVarAnalysis::InductionInfo* CreateWrapAround( 221 int32_t initial, 222 HInductionVarAnalysis::InductionInfo* info) { 223 return iva_->CreateInduction(HInductionVarAnalysis::kWrapAround, 224 HInductionVarAnalysis::kNop, 225 CreateConst(initial), 226 info, 227 nullptr, 228 DataType::Type::kInt32); 229 } 230 231 /** Constructs a wrap-around induction consisting of a constant, followed by a range. */ 232 HInductionVarAnalysis::InductionInfo* CreateWrapAround(int32_t initial, int32_t lo, int32_t hi) { 233 return CreateWrapAround(initial, CreateRange(lo, hi)); 234 } 235 236 // 237 // Relay methods. 238 // 239 240 bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) { 241 int64_t s = 0; 242 return range_.NeedsTripCount(info, &s); 243 } 244 245 bool IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) { 246 return range_.IsBodyTripCount(trip); 247 } 248 249 bool IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) { 250 return range_.IsUnsafeTripCount(trip); 251 } 252 253 Value GetMin(HInductionVarAnalysis::InductionInfo* info, 254 HInductionVarAnalysis::InductionInfo* trip) { 255 return range_.GetVal(info, trip, /* in_body */ true, /* is_min */ true); 256 } 257 258 Value GetMax(HInductionVarAnalysis::InductionInfo* info, 259 HInductionVarAnalysis::InductionInfo* trip) { 260 return range_.GetVal(info, trip, /* in_body */ true, /* is_min */ false); 261 } 262 263 Value GetMul(HInductionVarAnalysis::InductionInfo* info1, 264 HInductionVarAnalysis::InductionInfo* info2, 265 bool is_min) { 266 return range_.GetMul(info1, info2, nullptr, /* in_body */ true, is_min); 267 } 268 269 Value GetDiv(HInductionVarAnalysis::InductionInfo* info1, 270 HInductionVarAnalysis::InductionInfo* info2, 271 bool is_min) { 272 return range_.GetDiv(info1, info2, nullptr, /* in_body */ true, is_min); 273 } 274 275 Value GetRem(HInductionVarAnalysis::InductionInfo* info1, 276 HInductionVarAnalysis::InductionInfo* info2) { 277 return range_.GetRem(info1, info2); 278 } 279 280 Value GetXor(HInductionVarAnalysis::InductionInfo* info1, 281 HInductionVarAnalysis::InductionInfo* info2) { 282 return range_.GetXor(info1, info2); 283 } 284 285 bool IsExact(HInductionVarAnalysis::InductionInfo* info, int64_t* value) { 286 return range_.IsConstant(info, InductionVarRange::kExact, value); 287 } 288 289 bool IsAtMost(HInductionVarAnalysis::InductionInfo* info, int64_t* value) { 290 return range_.IsConstant(info, InductionVarRange::kAtMost, value); 291 } 292 293 bool IsAtLeast(HInductionVarAnalysis::InductionInfo* info, int64_t* value) { 294 return range_.IsConstant(info, InductionVarRange::kAtLeast, value); 295 } 296 297 Value AddValue(Value v1, Value v2) { return range_.AddValue(v1, v2); } 298 Value SubValue(Value v1, Value v2) { return range_.SubValue(v1, v2); } 299 Value MulValue(Value v1, Value v2) { return range_.MulValue(v1, v2); } 300 Value DivValue(Value v1, Value v2) { return range_.DivValue(v1, v2); } 301 Value MinValue(Value v1, Value v2) { return range_.MergeVal(v1, v2, true); } 302 Value MaxValue(Value v1, Value v2) { return range_.MergeVal(v1, v2, false); } 303 304 // General building fields. 305 HGraph* graph_; 306 HBasicBlock* entry_block_; 307 HBasicBlock* exit_block_; 308 HBasicBlock* loop_preheader_; 309 HBasicBlock* loop_header_; 310 HBasicBlock* loop_body_; 311 HInductionVarAnalysis* iva_; 312 InductionVarRange range_; 313 314 // Instructions. 315 HInstruction* condition_; 316 HInstruction* increment_; 317 HInstruction* x_; 318 HInstruction* y_; 319 }; 320 321 // 322 // Tests on private methods. 323 // 324 325 TEST_F(InductionVarRangeTest, IsConstant) { 326 int64_t value; 327 // Constant. 328 EXPECT_TRUE(IsExact(CreateConst(12345), &value)); 329 EXPECT_EQ(12345, value); 330 EXPECT_TRUE(IsAtMost(CreateConst(12345), &value)); 331 EXPECT_EQ(12345, value); 332 EXPECT_TRUE(IsAtLeast(CreateConst(12345), &value)); 333 EXPECT_EQ(12345, value); 334 // Constant trivial range. 335 EXPECT_TRUE(IsExact(CreateRange(111, 111), &value)); 336 EXPECT_EQ(111, value); 337 EXPECT_TRUE(IsAtMost(CreateRange(111, 111), &value)); 338 EXPECT_EQ(111, value); 339 EXPECT_TRUE(IsAtLeast(CreateRange(111, 111), &value)); 340 EXPECT_EQ(111, value); 341 // Constant non-trivial range. 342 EXPECT_FALSE(IsExact(CreateRange(11, 22), &value)); 343 EXPECT_TRUE(IsAtMost(CreateRange(11, 22), &value)); 344 EXPECT_EQ(22, value); 345 EXPECT_TRUE(IsAtLeast(CreateRange(11, 22), &value)); 346 EXPECT_EQ(11, value); 347 // Symbolic. 348 EXPECT_FALSE(IsExact(CreateFetch(x_), &value)); 349 EXPECT_FALSE(IsAtMost(CreateFetch(x_), &value)); 350 EXPECT_FALSE(IsAtLeast(CreateFetch(x_), &value)); 351 } 352 353 TEST_F(InductionVarRangeTest, TripCountProperties) { 354 EXPECT_FALSE(NeedsTripCount(nullptr)); 355 EXPECT_FALSE(NeedsTripCount(CreateConst(1))); 356 EXPECT_TRUE(NeedsTripCount(CreateLinear(1, 1))); 357 EXPECT_FALSE(NeedsTripCount(CreateWrapAround(1, 2, 3))); 358 EXPECT_TRUE(NeedsTripCount(CreateWrapAround(1, CreateLinear(1, 1)))); 359 360 EXPECT_FALSE(IsBodyTripCount(nullptr)); 361 EXPECT_FALSE(IsBodyTripCount(CreateTripCount(100, true, true))); 362 EXPECT_FALSE(IsBodyTripCount(CreateTripCount(100, true, false))); 363 EXPECT_TRUE(IsBodyTripCount(CreateTripCount(100, false, true))); 364 EXPECT_TRUE(IsBodyTripCount(CreateTripCount(100, false, false))); 365 366 EXPECT_FALSE(IsUnsafeTripCount(nullptr)); 367 EXPECT_FALSE(IsUnsafeTripCount(CreateTripCount(100, true, true))); 368 EXPECT_TRUE(IsUnsafeTripCount(CreateTripCount(100, true, false))); 369 EXPECT_FALSE(IsUnsafeTripCount(CreateTripCount(100, false, true))); 370 EXPECT_TRUE(IsUnsafeTripCount(CreateTripCount(100, false, false))); 371 } 372 373 TEST_F(InductionVarRangeTest, GetMinMaxNull) { 374 ExpectEqual(Value(), GetMin(nullptr, nullptr)); 375 ExpectEqual(Value(), GetMax(nullptr, nullptr)); 376 } 377 378 TEST_F(InductionVarRangeTest, GetMinMaxAdd) { 379 ExpectEqual(Value(12), 380 GetMin(CreateInvariant('+', CreateConst(2), CreateRange(10, 20)), nullptr)); 381 ExpectEqual(Value(22), 382 GetMax(CreateInvariant('+', CreateConst(2), CreateRange(10, 20)), nullptr)); 383 ExpectEqual(Value(x_, 1, -20), 384 GetMin(CreateInvariant('+', CreateFetch(x_), CreateRange(-20, -10)), nullptr)); 385 ExpectEqual(Value(x_, 1, -10), 386 GetMax(CreateInvariant('+', CreateFetch(x_), CreateRange(-20, -10)), nullptr)); 387 ExpectEqual(Value(x_, 1, 10), 388 GetMin(CreateInvariant('+', CreateRange(10, 20), CreateFetch(x_)), nullptr)); 389 ExpectEqual(Value(x_, 1, 20), 390 GetMax(CreateInvariant('+', CreateRange(10, 20), CreateFetch(x_)), nullptr)); 391 ExpectEqual(Value(5), 392 GetMin(CreateInvariant('+', CreateRange(-5, -1), CreateRange(10, 20)), nullptr)); 393 ExpectEqual(Value(19), 394 GetMax(CreateInvariant('+', CreateRange(-5, -1), CreateRange(10, 20)), nullptr)); 395 } 396 397 TEST_F(InductionVarRangeTest, GetMinMaxSub) { 398 ExpectEqual(Value(-18), 399 GetMin(CreateInvariant('-', CreateConst(2), CreateRange(10, 20)), nullptr)); 400 ExpectEqual(Value(-8), 401 GetMax(CreateInvariant('-', CreateConst(2), CreateRange(10, 20)), nullptr)); 402 ExpectEqual(Value(x_, 1, 10), 403 GetMin(CreateInvariant('-', CreateFetch(x_), CreateRange(-20, -10)), nullptr)); 404 ExpectEqual(Value(x_, 1, 20), 405 GetMax(CreateInvariant('-', CreateFetch(x_), CreateRange(-20, -10)), nullptr)); 406 ExpectEqual(Value(x_, -1, 10), 407 GetMin(CreateInvariant('-', CreateRange(10, 20), CreateFetch(x_)), nullptr)); 408 ExpectEqual(Value(x_, -1, 20), 409 GetMax(CreateInvariant('-', CreateRange(10, 20), CreateFetch(x_)), nullptr)); 410 ExpectEqual(Value(-25), 411 GetMin(CreateInvariant('-', CreateRange(-5, -1), CreateRange(10, 20)), nullptr)); 412 ExpectEqual(Value(-11), 413 GetMax(CreateInvariant('-', CreateRange(-5, -1), CreateRange(10, 20)), nullptr)); 414 } 415 416 TEST_F(InductionVarRangeTest, GetMinMaxNeg) { 417 ExpectEqual(Value(-20), GetMin(CreateInvariant('n', nullptr, CreateRange(10, 20)), nullptr)); 418 ExpectEqual(Value(-10), GetMax(CreateInvariant('n', nullptr, CreateRange(10, 20)), nullptr)); 419 ExpectEqual(Value(10), GetMin(CreateInvariant('n', nullptr, CreateRange(-20, -10)), nullptr)); 420 ExpectEqual(Value(20), GetMax(CreateInvariant('n', nullptr, CreateRange(-20, -10)), nullptr)); 421 ExpectEqual(Value(x_, -1, 0), GetMin(CreateInvariant('n', nullptr, CreateFetch(x_)), nullptr)); 422 ExpectEqual(Value(x_, -1, 0), GetMax(CreateInvariant('n', nullptr, CreateFetch(x_)), nullptr)); 423 } 424 425 TEST_F(InductionVarRangeTest, GetMinMaxMul) { 426 ExpectEqual(Value(20), 427 GetMin(CreateInvariant('*', CreateConst(2), CreateRange(10, 20)), nullptr)); 428 ExpectEqual(Value(40), 429 GetMax(CreateInvariant('*', CreateConst(2), CreateRange(10, 20)), nullptr)); 430 } 431 432 TEST_F(InductionVarRangeTest, GetMinMaxDiv) { 433 ExpectEqual(Value(3), 434 GetMin(CreateInvariant('/', CreateRange(12, 20), CreateConst(4)), nullptr)); 435 ExpectEqual(Value(5), 436 GetMax(CreateInvariant('/', CreateRange(12, 20), CreateConst(4)), nullptr)); 437 } 438 439 TEST_F(InductionVarRangeTest, GetMinMaxConstant) { 440 ExpectEqual(Value(12345), GetMin(CreateConst(12345), nullptr)); 441 ExpectEqual(Value(12345), GetMax(CreateConst(12345), nullptr)); 442 } 443 444 TEST_F(InductionVarRangeTest, GetMinMaxFetch) { 445 ExpectEqual(Value(x_, 1, 0), GetMin(CreateFetch(x_), nullptr)); 446 ExpectEqual(Value(x_, 1, 0), GetMax(CreateFetch(x_), nullptr)); 447 } 448 449 TEST_F(InductionVarRangeTest, GetMinMaxLinear) { 450 ExpectEqual(Value(20), GetMin(CreateLinear(10, 20), CreateTripCount(100, true, true))); 451 ExpectEqual(Value(1010), GetMax(CreateLinear(10, 20), CreateTripCount(100, true, true))); 452 ExpectEqual(Value(-970), GetMin(CreateLinear(-10, 20), CreateTripCount(100, true, true))); 453 ExpectEqual(Value(20), GetMax(CreateLinear(-10, 20), CreateTripCount(100, true, true))); 454 } 455 456 TEST_F(InductionVarRangeTest, GetMinMaxWrapAround) { 457 ExpectEqual(Value(-5), GetMin(CreateWrapAround(-5, -1, 10), nullptr)); 458 ExpectEqual(Value(10), GetMax(CreateWrapAround(-5, -1, 10), nullptr)); 459 ExpectEqual(Value(-1), GetMin(CreateWrapAround(2, -1, 10), nullptr)); 460 ExpectEqual(Value(10), GetMax(CreateWrapAround(2, -1, 10), nullptr)); 461 ExpectEqual(Value(-1), GetMin(CreateWrapAround(20, -1, 10), nullptr)); 462 ExpectEqual(Value(20), GetMax(CreateWrapAround(20, -1, 10), nullptr)); 463 } 464 465 TEST_F(InductionVarRangeTest, GetMinMaxPolynomial) { 466 ExpectEqual(Value(7), GetMin(CreatePolynomial(3, 5, 7), nullptr)); 467 ExpectEqual(Value(), GetMax(CreatePolynomial(3, 5, 7), nullptr)); 468 ExpectEqual(Value(7), GetMin(CreatePolynomial(3, 5, 7), CreateTripCount(5, true, true))); 469 ExpectEqual(Value(45), GetMax(CreatePolynomial(3, 5, 7), CreateTripCount(5, true, true))); 470 ExpectEqual(Value(7), GetMin(CreatePolynomial(3, 5, 7), CreateTripCount(10, true, true))); 471 ExpectEqual(Value(160), GetMax(CreatePolynomial(3, 5, 7), CreateTripCount(10, true, true))); 472 ExpectEqual(Value(-7), GetMin(CreatePolynomial(11, 13, -7), 473 CreateTripCount(5, true, true))); 474 ExpectEqual(Value(111), GetMax(CreatePolynomial(11, 13, -7), 475 CreateTripCount(5, true, true))); 476 ExpectEqual(Value(-7), GetMin(CreatePolynomial(11, 13, -7), 477 CreateTripCount(10, true, true))); 478 ExpectEqual(Value(506), GetMax(CreatePolynomial(11, 13, -7), 479 CreateTripCount(10, true, true))); 480 ExpectEqual(Value(), GetMin(CreatePolynomial(-3, 5, 7), CreateTripCount(10, true, true))); 481 ExpectEqual(Value(), GetMax(CreatePolynomial(-3, 5, 7), CreateTripCount(10, true, true))); 482 ExpectEqual(Value(), GetMin(CreatePolynomial(3, -5, 7), CreateTripCount(10, true, true))); 483 ExpectEqual(Value(), GetMax(CreatePolynomial(3, -5, 7), CreateTripCount(10, true, true))); 484 } 485 486 TEST_F(InductionVarRangeTest, GetMinMaxGeometricMul) { 487 ExpectEqual(Value(), GetMin(CreateGeometric(1, 1, 1, '*'), nullptr)); 488 ExpectEqual(Value(), GetMax(CreateGeometric(1, 1, 1, '*'), nullptr)); 489 } 490 491 TEST_F(InductionVarRangeTest, GetMinMaxGeometricDiv) { 492 ExpectEqual(Value(5), GetMin(CreateGeometric(11, 5, 3, '/'), nullptr)); 493 ExpectEqual(Value(16), GetMax(CreateGeometric(11, 5, 3, '/'), nullptr)); 494 ExpectEqual(Value(-5), GetMin(CreateGeometric(11, -5, 3, '/'), nullptr)); 495 ExpectEqual(Value(6), GetMax(CreateGeometric(11, -5, 3, '/'), nullptr)); 496 ExpectEqual(Value(-6), GetMin(CreateGeometric(-11, 5, 3, '/'), nullptr)); 497 ExpectEqual(Value(5), GetMax(CreateGeometric(-11, 5, 3, '/'), nullptr)); 498 ExpectEqual(Value(-16), GetMin(CreateGeometric(-11, -5, 3, '/'), nullptr)); 499 ExpectEqual(Value(-5), GetMax(CreateGeometric(-11, -5, 3, '/'), nullptr)); 500 } 501 502 TEST_F(InductionVarRangeTest, GetMinMaxPeriodic) { 503 ExpectEqual(Value(-2), GetMin(CreateRange(-2, 99), nullptr)); 504 ExpectEqual(Value(99), GetMax(CreateRange(-2, 99), nullptr)); 505 } 506 507 TEST_F(InductionVarRangeTest, GetMulMin) { 508 ExpectEqual(Value(-14), GetMul(CreateConst(2), CreateRange(-7, 8), true)); 509 ExpectEqual(Value(-16), GetMul(CreateConst(-2), CreateRange(-7, 8), true)); 510 ExpectEqual(Value(-14), GetMul(CreateRange(-7, 8), CreateConst(2), true)); 511 ExpectEqual(Value(-16), GetMul(CreateRange(-7, 8), CreateConst(-2), true)); 512 ExpectEqual(Value(6), GetMul(CreateRange(2, 10), CreateRange(3, 5), true)); 513 ExpectEqual(Value(-50), GetMul(CreateRange(2, 10), CreateRange(-5, -3), true)); 514 ExpectEqual(Value(), GetMul(CreateRange(2, 10), CreateRange(-1, 1), true)); 515 ExpectEqual(Value(-50), GetMul(CreateRange(-10, -2), CreateRange(3, 5), true)); 516 ExpectEqual(Value(6), GetMul(CreateRange(-10, -2), CreateRange(-5, -3), true)); 517 ExpectEqual(Value(), GetMul(CreateRange(-10, -2), CreateRange(-1, 1), true)); 518 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(2, 10), true)); 519 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(-10, -2), true)); 520 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(-1, 1), true)); 521 } 522 523 TEST_F(InductionVarRangeTest, GetMulMax) { 524 ExpectEqual(Value(16), GetMul(CreateConst(2), CreateRange(-7, 8), false)); 525 ExpectEqual(Value(14), GetMul(CreateConst(-2), CreateRange(-7, 8), false)); 526 ExpectEqual(Value(16), GetMul(CreateRange(-7, 8), CreateConst(2), false)); 527 ExpectEqual(Value(14), GetMul(CreateRange(-7, 8), CreateConst(-2), false)); 528 ExpectEqual(Value(50), GetMul(CreateRange(2, 10), CreateRange(3, 5), false)); 529 ExpectEqual(Value(-6), GetMul(CreateRange(2, 10), CreateRange(-5, -3), false)); 530 ExpectEqual(Value(), GetMul(CreateRange(2, 10), CreateRange(-1, 1), false)); 531 ExpectEqual(Value(-6), GetMul(CreateRange(-10, -2), CreateRange(3, 5), false)); 532 ExpectEqual(Value(50), GetMul(CreateRange(-10, -2), CreateRange(-5, -3), false)); 533 ExpectEqual(Value(), GetMul(CreateRange(-10, -2), CreateRange(-1, 1), false)); 534 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(2, 10), false)); 535 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(-10, -2), false)); 536 ExpectEqual(Value(), GetMul(CreateRange(-1, 1), CreateRange(-1, 1), false)); 537 } 538 539 TEST_F(InductionVarRangeTest, GetDivMin) { 540 ExpectEqual(Value(-5), GetDiv(CreateRange(-10, 20), CreateConst(2), true)); 541 ExpectEqual(Value(-10), GetDiv(CreateRange(-10, 20), CreateConst(-2), true)); 542 ExpectEqual(Value(10), GetDiv(CreateRange(40, 1000), CreateRange(2, 4), true)); 543 ExpectEqual(Value(-500), GetDiv(CreateRange(40, 1000), CreateRange(-4, -2), true)); 544 ExpectEqual(Value(), GetDiv(CreateRange(40, 1000), CreateRange(-1, 1), true)); 545 ExpectEqual(Value(-500), GetDiv(CreateRange(-1000, -40), CreateRange(2, 4), true)); 546 ExpectEqual(Value(10), GetDiv(CreateRange(-1000, -40), CreateRange(-4, -2), true)); 547 ExpectEqual(Value(), GetDiv(CreateRange(-1000, -40), CreateRange(-1, 1), true)); 548 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(40, 1000), true)); 549 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(-1000, -40), true)); 550 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(-1, 1), true)); 551 } 552 553 TEST_F(InductionVarRangeTest, GetDivMax) { 554 ExpectEqual(Value(10), GetDiv(CreateRange(-10, 20), CreateConst(2), false)); 555 ExpectEqual(Value(5), GetDiv(CreateRange(-10, 20), CreateConst(-2), false)); 556 ExpectEqual(Value(500), GetDiv(CreateRange(40, 1000), CreateRange(2, 4), false)); 557 ExpectEqual(Value(-10), GetDiv(CreateRange(40, 1000), CreateRange(-4, -2), false)); 558 ExpectEqual(Value(), GetDiv(CreateRange(40, 1000), CreateRange(-1, 1), false)); 559 ExpectEqual(Value(-10), GetDiv(CreateRange(-1000, -40), CreateRange(2, 4), false)); 560 ExpectEqual(Value(500), GetDiv(CreateRange(-1000, -40), CreateRange(-4, -2), false)); 561 ExpectEqual(Value(), GetDiv(CreateRange(-1000, -40), CreateRange(-1, 1), false)); 562 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(40, 1000), false)); 563 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(-1000, 40), false)); 564 ExpectEqual(Value(), GetDiv(CreateRange(-1, 1), CreateRange(-1, 1), false)); 565 } 566 567 TEST_F(InductionVarRangeTest, GetMinMaxRem) { 568 ExpectEqual(Value(), GetMin(CreateInvariant('%', CreateConst(2), CreateRange(10, 20)), nullptr)); 569 ExpectEqual(Value(), GetMax(CreateInvariant('%', CreateConst(2), CreateRange(10, 20)), nullptr)); 570 ExpectEqual(Value(), GetMin(CreateInvariant('%', CreateRange(10, 20), CreateConst(2)), nullptr)); 571 ExpectEqual(Value(), GetMax(CreateInvariant('%', CreateRange(10, 20), CreateConst(2)), nullptr)); 572 ExpectEqual(Value(2), GetMin(CreateInvariant('%', CreateConst(2), CreateConst(5)), nullptr)); 573 ExpectEqual(Value(2), GetMax(CreateInvariant('%', CreateConst(2), CreateConst(5)), nullptr)); 574 ExpectEqual(Value(1), GetMin(CreateInvariant('%', CreateConst(11), CreateConst(5)), nullptr)); 575 ExpectEqual(Value(1), GetMax(CreateInvariant('%', CreateConst(11), CreateConst(5)), nullptr)); 576 } 577 578 TEST_F(InductionVarRangeTest, GetRem) { 579 ExpectEqual(Value(0), GetRem(CreateConst(1), CreateConst(1))); 580 ExpectEqual(Value(2), GetRem(CreateConst(2), CreateConst(5))); 581 ExpectEqual(Value(1), GetRem(CreateConst(11), CreateConst(5))); 582 ExpectEqual(Value(-2), GetRem(CreateConst(-2), CreateConst(5))); 583 ExpectEqual(Value(-1), GetRem(CreateConst(-11), CreateConst(5))); 584 ExpectEqual(Value(2), GetRem(CreateConst(2), CreateConst(-5))); 585 ExpectEqual(Value(1), GetRem(CreateConst(11), CreateConst(-5))); 586 ExpectEqual(Value(-2), GetRem(CreateConst(-2), CreateConst(-5))); 587 ExpectEqual(Value(-1), GetRem(CreateConst(-11), CreateConst(-5))); 588 ExpectEqual(Value(), GetRem(CreateConst(1), CreateConst(0))); 589 } 590 591 TEST_F(InductionVarRangeTest, GetMinMaxXor) { 592 ExpectEqual(Value(), GetMin(CreateInvariant('^', CreateConst(2), CreateRange(10, 20)), nullptr)); 593 ExpectEqual(Value(), GetMax(CreateInvariant('^', CreateConst(2), CreateRange(10, 20)), nullptr)); 594 ExpectEqual(Value(), GetMin(CreateInvariant('^', CreateRange(10, 20), CreateConst(2)), nullptr)); 595 ExpectEqual(Value(), GetMax(CreateInvariant('^', CreateRange(10, 20), CreateConst(2)), nullptr)); 596 ExpectEqual(Value(3), GetMin(CreateInvariant('^', CreateConst(1), CreateConst(2)), nullptr)); 597 ExpectEqual(Value(3), GetMax(CreateInvariant('^', CreateConst(1), CreateConst(2)), nullptr)); 598 } 599 600 TEST_F(InductionVarRangeTest, GetXor) { 601 ExpectEqual(Value(0), GetXor(CreateConst(1), CreateConst(1))); 602 ExpectEqual(Value(3), GetXor(CreateConst(1), CreateConst(2))); 603 ExpectEqual(Value(-2), GetXor(CreateConst(1), CreateConst(-1))); 604 ExpectEqual(Value(0), GetXor(CreateConst(-1), CreateConst(-1))); 605 } 606 607 TEST_F(InductionVarRangeTest, AddValue) { 608 ExpectEqual(Value(110), AddValue(Value(10), Value(100))); 609 ExpectEqual(Value(-5), AddValue(Value(x_, 1, -4), Value(x_, -1, -1))); 610 ExpectEqual(Value(x_, 3, -5), AddValue(Value(x_, 2, -4), Value(x_, 1, -1))); 611 ExpectEqual(Value(), AddValue(Value(x_, 1, 5), Value(y_, 1, -7))); 612 ExpectEqual(Value(x_, 1, 23), AddValue(Value(x_, 1, 20), Value(3))); 613 ExpectEqual(Value(y_, 1, 5), AddValue(Value(55), Value(y_, 1, -50))); 614 const int32_t max_value = std::numeric_limits<int32_t>::max(); 615 ExpectEqual(Value(max_value), AddValue(Value(max_value - 5), Value(5))); 616 ExpectEqual(Value(), AddValue(Value(max_value - 5), Value(6))); // unsafe 617 } 618 619 TEST_F(InductionVarRangeTest, SubValue) { 620 ExpectEqual(Value(-90), SubValue(Value(10), Value(100))); 621 ExpectEqual(Value(-3), SubValue(Value(x_, 1, -4), Value(x_, 1, -1))); 622 ExpectEqual(Value(x_, 2, -3), SubValue(Value(x_, 3, -4), Value(x_, 1, -1))); 623 ExpectEqual(Value(), SubValue(Value(x_, 1, 5), Value(y_, 1, -7))); 624 ExpectEqual(Value(x_, 1, 17), SubValue(Value(x_, 1, 20), Value(3))); 625 ExpectEqual(Value(y_, -4, 105), SubValue(Value(55), Value(y_, 4, -50))); 626 const int32_t min_value = std::numeric_limits<int32_t>::min(); 627 ExpectEqual(Value(min_value), SubValue(Value(min_value + 5), Value(5))); 628 ExpectEqual(Value(), SubValue(Value(min_value + 5), Value(6))); // unsafe 629 } 630 631 TEST_F(InductionVarRangeTest, MulValue) { 632 ExpectEqual(Value(1000), MulValue(Value(10), Value(100))); 633 ExpectEqual(Value(), MulValue(Value(x_, 1, -4), Value(x_, 1, -1))); 634 ExpectEqual(Value(), MulValue(Value(x_, 1, 5), Value(y_, 1, -7))); 635 ExpectEqual(Value(x_, 9, 60), MulValue(Value(x_, 3, 20), Value(3))); 636 ExpectEqual(Value(y_, 55, -110), MulValue(Value(55), Value(y_, 1, -2))); 637 ExpectEqual(Value(), MulValue(Value(90000), Value(-90000))); // unsafe 638 } 639 640 TEST_F(InductionVarRangeTest, MulValueSpecial) { 641 const int32_t min_value = std::numeric_limits<int32_t>::min(); 642 const int32_t max_value = std::numeric_limits<int32_t>::max(); 643 644 // Unsafe. 645 ExpectEqual(Value(), MulValue(Value(min_value), Value(min_value))); 646 ExpectEqual(Value(), MulValue(Value(min_value), Value(-1))); 647 ExpectEqual(Value(), MulValue(Value(min_value), Value(max_value))); 648 ExpectEqual(Value(), MulValue(Value(max_value), Value(max_value))); 649 650 // Safe. 651 ExpectEqual(Value(min_value), MulValue(Value(min_value), Value(1))); 652 ExpectEqual(Value(max_value), MulValue(Value(max_value), Value(1))); 653 ExpectEqual(Value(-max_value), MulValue(Value(max_value), Value(-1))); 654 ExpectEqual(Value(-1), MulValue(Value(1), Value(-1))); 655 ExpectEqual(Value(1), MulValue(Value(-1), Value(-1))); 656 } 657 658 TEST_F(InductionVarRangeTest, DivValue) { 659 ExpectEqual(Value(25), DivValue(Value(100), Value(4))); 660 ExpectEqual(Value(), DivValue(Value(x_, 1, -4), Value(x_, 1, -1))); 661 ExpectEqual(Value(), DivValue(Value(x_, 1, 5), Value(y_, 1, -7))); 662 ExpectEqual(Value(), DivValue(Value(x_, 12, 24), Value(3))); 663 ExpectEqual(Value(), DivValue(Value(55), Value(y_, 1, -50))); 664 ExpectEqual(Value(), DivValue(Value(1), Value(0))); // unsafe 665 } 666 667 TEST_F(InductionVarRangeTest, DivValueSpecial) { 668 const int32_t min_value = std::numeric_limits<int32_t>::min(); 669 const int32_t max_value = std::numeric_limits<int32_t>::max(); 670 671 // Unsafe. 672 ExpectEqual(Value(), DivValue(Value(min_value), Value(-1))); 673 674 // Safe. 675 ExpectEqual(Value(1), DivValue(Value(min_value), Value(min_value))); 676 ExpectEqual(Value(1), DivValue(Value(max_value), Value(max_value))); 677 ExpectEqual(Value(min_value), DivValue(Value(min_value), Value(1))); 678 ExpectEqual(Value(max_value), DivValue(Value(max_value), Value(1))); 679 ExpectEqual(Value(-max_value), DivValue(Value(max_value), Value(-1))); 680 ExpectEqual(Value(-1), DivValue(Value(1), Value(-1))); 681 ExpectEqual(Value(1), DivValue(Value(-1), Value(-1))); 682 } 683 684 TEST_F(InductionVarRangeTest, MinValue) { 685 ExpectEqual(Value(10), MinValue(Value(10), Value(100))); 686 ExpectEqual(Value(x_, 1, -4), MinValue(Value(x_, 1, -4), Value(x_, 1, -1))); 687 ExpectEqual(Value(x_, 4, -4), MinValue(Value(x_, 4, -4), Value(x_, 4, -1))); 688 ExpectEqual(Value(), MinValue(Value(x_, 1, 5), Value(y_, 1, -7))); 689 ExpectEqual(Value(), MinValue(Value(x_, 1, 20), Value(3))); 690 ExpectEqual(Value(), MinValue(Value(55), Value(y_, 1, -50))); 691 } 692 693 TEST_F(InductionVarRangeTest, MaxValue) { 694 ExpectEqual(Value(100), MaxValue(Value(10), Value(100))); 695 ExpectEqual(Value(x_, 1, -1), MaxValue(Value(x_, 1, -4), Value(x_, 1, -1))); 696 ExpectEqual(Value(x_, 4, -1), MaxValue(Value(x_, 4, -4), Value(x_, 4, -1))); 697 ExpectEqual(Value(), MaxValue(Value(x_, 1, 5), Value(y_, 1, -7))); 698 ExpectEqual(Value(), MaxValue(Value(x_, 1, 20), Value(3))); 699 ExpectEqual(Value(), MaxValue(Value(55), Value(y_, 1, -50))); 700 } 701 702 TEST_F(InductionVarRangeTest, ArrayLengthAndHints) { 703 // We pass a bogus constant for the class to avoid mocking one. 704 HInstruction* new_array = new (GetAllocator()) HNewArray(x_, x_, 0); 705 entry_block_->AddInstruction(new_array); 706 HInstruction* array_length = new (GetAllocator()) HArrayLength(new_array, 0); 707 entry_block_->AddInstruction(array_length); 708 // With null hint: yields extreme constants. 709 const int32_t max_value = std::numeric_limits<int32_t>::max(); 710 SetHint(nullptr); 711 ExpectEqual(Value(0), GetMin(CreateFetch(array_length), nullptr)); 712 ExpectEqual(Value(max_value), GetMax(CreateFetch(array_length), nullptr)); 713 // With explicit hint: yields the length instruction. 714 SetHint(array_length); 715 ExpectEqual(Value(array_length, 1, 0), GetMin(CreateFetch(array_length), nullptr)); 716 ExpectEqual(Value(array_length, 1, 0), GetMax(CreateFetch(array_length), nullptr)); 717 // With any non-null hint: chases beyond the length instruction. 718 SetHint(x_); 719 ExpectEqual(Value(x_, 1, 0), GetMin(CreateFetch(array_length), nullptr)); 720 ExpectEqual(Value(x_, 1, 0), GetMax(CreateFetch(array_length), nullptr)); 721 } 722 723 TEST_F(InductionVarRangeTest, AddOrSubAndConstant) { 724 HInstruction* add = new (GetAllocator()) 725 HAdd(DataType::Type::kInt32, x_, graph_->GetIntConstant(-1)); 726 HInstruction* alt = new (GetAllocator()) 727 HAdd(DataType::Type::kInt32, graph_->GetIntConstant(-1), x_); 728 HInstruction* sub = new (GetAllocator()) 729 HSub(DataType::Type::kInt32, x_, graph_->GetIntConstant(1)); 730 HInstruction* rev = new (GetAllocator()) 731 HSub(DataType::Type::kInt32, graph_->GetIntConstant(1), x_); 732 entry_block_->AddInstruction(add); 733 entry_block_->AddInstruction(alt); 734 entry_block_->AddInstruction(sub); 735 entry_block_->AddInstruction(rev); 736 ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(add), nullptr)); 737 ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(add), nullptr)); 738 ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(alt), nullptr)); 739 ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(alt), nullptr)); 740 ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(sub), nullptr)); 741 ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(sub), nullptr)); 742 ExpectEqual(Value(x_, -1, 1), GetMin(CreateFetch(rev), nullptr)); 743 ExpectEqual(Value(x_, -1, 1), GetMax(CreateFetch(rev), nullptr)); 744 } 745 746 // 747 // Tests on public methods. 748 // 749 750 TEST_F(InductionVarRangeTest, ConstantTripCountUp) { 751 BuildLoop(0, graph_->GetIntConstant(1000), 1); 752 PerformInductionVarAnalysis(); 753 754 Value v1, v2; 755 bool needs_finite_test = true; 756 bool needs_taken_test = true; 757 758 HInstruction* phi = condition_->InputAt(0); 759 HInstruction* exit = exit_block_->GetLastInstruction(); 760 761 // In context of header: known. 762 range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test); 763 EXPECT_FALSE(needs_finite_test); 764 ExpectEqual(Value(0), v1); 765 ExpectEqual(Value(1000), v2); 766 767 // In context of loop-body: known. 768 range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test); 769 EXPECT_FALSE(needs_finite_test); 770 ExpectEqual(Value(0), v1); 771 ExpectEqual(Value(999), v2); 772 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 773 EXPECT_FALSE(needs_finite_test); 774 ExpectEqual(Value(1), v1); 775 ExpectEqual(Value(1000), v2); 776 777 // Induction vs. no-induction. 778 EXPECT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test)); 779 EXPECT_TRUE(range_.CanGenerateLastValue(phi)); 780 EXPECT_FALSE(range_.CanGenerateRange(exit, exit, &needs_finite_test, &needs_taken_test)); 781 EXPECT_FALSE(range_.CanGenerateLastValue(exit)); 782 783 // Last value (unsimplified). 784 HInstruction* last = range_.GenerateLastValue(phi, graph_, loop_preheader_); 785 ASSERT_TRUE(last->IsAdd()); 786 ExpectInt(1000, last->InputAt(0)); 787 ExpectInt(0, last->InputAt(1)); 788 789 // Loop logic. 790 int64_t tc = 0; 791 EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc)); 792 EXPECT_EQ(1000, tc); 793 HInstruction* offset = nullptr; 794 EXPECT_TRUE(range_.IsUnitStride(phi, phi, graph_, &offset)); 795 ExpectInt(0, offset); 796 HInstruction* tce = range_.GenerateTripCount( 797 loop_header_->GetLoopInformation(), graph_, loop_preheader_); 798 ASSERT_TRUE(tce != nullptr); 799 ExpectInt(1000, tce); 800 } 801 802 TEST_F(InductionVarRangeTest, ConstantTripCountDown) { 803 BuildLoop(1000, graph_->GetIntConstant(0), -1); 804 PerformInductionVarAnalysis(); 805 806 Value v1, v2; 807 bool needs_finite_test = true; 808 bool needs_taken_test = true; 809 810 HInstruction* phi = condition_->InputAt(0); 811 HInstruction* exit = exit_block_->GetLastInstruction(); 812 813 // In context of header: known. 814 range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test); 815 EXPECT_FALSE(needs_finite_test); 816 ExpectEqual(Value(0), v1); 817 ExpectEqual(Value(1000), v2); 818 819 // In context of loop-body: known. 820 range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test); 821 EXPECT_FALSE(needs_finite_test); 822 ExpectEqual(Value(1), v1); 823 ExpectEqual(Value(1000), v2); 824 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 825 EXPECT_FALSE(needs_finite_test); 826 ExpectEqual(Value(0), v1); 827 ExpectEqual(Value(999), v2); 828 829 // Induction vs. no-induction. 830 EXPECT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test)); 831 EXPECT_TRUE(range_.CanGenerateLastValue(phi)); 832 EXPECT_FALSE(range_.CanGenerateRange(exit, exit, &needs_finite_test, &needs_taken_test)); 833 EXPECT_FALSE(range_.CanGenerateLastValue(exit)); 834 835 // Last value (unsimplified). 836 HInstruction* last = range_.GenerateLastValue(phi, graph_, loop_preheader_); 837 ASSERT_TRUE(last->IsSub()); 838 ExpectInt(1000, last->InputAt(0)); 839 ASSERT_TRUE(last->InputAt(1)->IsNeg()); 840 last = last->InputAt(1)->InputAt(0); 841 ASSERT_TRUE(last->IsSub()); 842 ExpectInt(0, last->InputAt(0)); 843 ExpectInt(1000, last->InputAt(1)); 844 845 // Loop logic. 846 int64_t tc = 0; 847 EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc)); 848 EXPECT_EQ(1000, tc); 849 HInstruction* offset = nullptr; 850 EXPECT_FALSE(range_.IsUnitStride(phi, phi, graph_, &offset)); 851 HInstruction* tce = range_.GenerateTripCount( 852 loop_header_->GetLoopInformation(), graph_, loop_preheader_); 853 ASSERT_TRUE(tce != nullptr); 854 ASSERT_TRUE(tce->IsNeg()); 855 last = tce->InputAt(0); 856 EXPECT_TRUE(last->IsSub()); 857 ExpectInt(0, last->InputAt(0)); 858 ExpectInt(1000, last->InputAt(1)); 859 } 860 861 TEST_F(InductionVarRangeTest, SymbolicTripCountUp) { 862 BuildLoop(0, x_, 1); 863 PerformInductionVarAnalysis(); 864 865 Value v1, v2; 866 bool needs_finite_test = true; 867 bool needs_taken_test = true; 868 869 HInstruction* phi = condition_->InputAt(0); 870 871 // In context of header: upper unknown. 872 range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test); 873 EXPECT_FALSE(needs_finite_test); 874 ExpectEqual(Value(0), v1); 875 ExpectEqual(Value(), v2); 876 877 // In context of loop-body: known. 878 range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test); 879 EXPECT_FALSE(needs_finite_test); 880 ExpectEqual(Value(0), v1); 881 ExpectEqual(Value(x_, 1, -1), v2); 882 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 883 EXPECT_FALSE(needs_finite_test); 884 ExpectEqual(Value(1), v1); 885 ExpectEqual(Value(x_, 1, 0), v2); 886 887 HInstruction* lower = nullptr; 888 HInstruction* upper = nullptr; 889 890 // Can generate code in context of loop-body only. 891 EXPECT_FALSE(range_.CanGenerateRange(condition_, phi, &needs_finite_test, &needs_taken_test)); 892 ASSERT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test)); 893 EXPECT_FALSE(needs_finite_test); 894 EXPECT_TRUE(needs_taken_test); 895 896 // Generates code (unsimplified). 897 range_.GenerateRange(increment_, phi, graph_, loop_preheader_, &lower, &upper); 898 899 // Verify lower is 0+0. 900 ASSERT_TRUE(lower != nullptr); 901 ASSERT_TRUE(lower->IsAdd()); 902 ExpectInt(0, lower->InputAt(0)); 903 ExpectInt(0, lower->InputAt(1)); 904 905 // Verify upper is (V-1)+0. 906 ASSERT_TRUE(upper != nullptr); 907 ASSERT_TRUE(upper->IsAdd()); 908 ASSERT_TRUE(upper->InputAt(0)->IsSub()); 909 EXPECT_TRUE(upper->InputAt(0)->InputAt(0)->IsParameterValue()); 910 ExpectInt(1, upper->InputAt(0)->InputAt(1)); 911 ExpectInt(0, upper->InputAt(1)); 912 913 // Verify taken-test is 0<V. 914 HInstruction* taken = range_.GenerateTakenTest(increment_, graph_, loop_preheader_); 915 ASSERT_TRUE(taken != nullptr); 916 ASSERT_TRUE(taken->IsLessThan()); 917 ExpectInt(0, taken->InputAt(0)); 918 EXPECT_TRUE(taken->InputAt(1)->IsParameterValue()); 919 920 // Replacement. 921 range_.Replace(loop_header_->GetLastInstruction(), x_, y_); 922 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 923 EXPECT_FALSE(needs_finite_test); 924 ExpectEqual(Value(1), v1); 925 ExpectEqual(Value(y_, 1, 0), v2); 926 927 // Loop logic. 928 int64_t tc = 0; 929 EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc)); 930 EXPECT_EQ(0, tc); // unknown 931 HInstruction* offset = nullptr; 932 EXPECT_TRUE(range_.IsUnitStride(phi, phi, graph_, &offset)); 933 ExpectInt(0, offset); 934 HInstruction* tce = range_.GenerateTripCount( 935 loop_header_->GetLoopInformation(), graph_, loop_preheader_); 936 ASSERT_TRUE(tce != nullptr); 937 EXPECT_TRUE(tce->IsSelect()); // guarded by taken-test 938 ExpectInt(0, tce->InputAt(0)); 939 EXPECT_TRUE(tce->InputAt(1)->IsParameterValue()); 940 EXPECT_TRUE(tce->InputAt(2)->IsLessThan()); 941 } 942 943 TEST_F(InductionVarRangeTest, SymbolicTripCountDown) { 944 BuildLoop(1000, x_, -1); 945 PerformInductionVarAnalysis(); 946 947 Value v1, v2; 948 bool needs_finite_test = true; 949 bool needs_taken_test = true; 950 951 HInstruction* phi = condition_->InputAt(0); 952 953 // In context of header: lower unknown. 954 range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test); 955 EXPECT_FALSE(needs_finite_test); 956 ExpectEqual(Value(), v1); 957 ExpectEqual(Value(1000), v2); 958 959 // In context of loop-body: known. 960 range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test); 961 EXPECT_FALSE(needs_finite_test); 962 ExpectEqual(Value(x_, 1, 1), v1); 963 ExpectEqual(Value(1000), v2); 964 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 965 EXPECT_FALSE(needs_finite_test); 966 ExpectEqual(Value(x_, 1, 0), v1); 967 ExpectEqual(Value(999), v2); 968 969 HInstruction* lower = nullptr; 970 HInstruction* upper = nullptr; 971 972 // Can generate code in context of loop-body only. 973 EXPECT_FALSE(range_.CanGenerateRange(condition_, phi, &needs_finite_test, &needs_taken_test)); 974 ASSERT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test)); 975 EXPECT_FALSE(needs_finite_test); 976 EXPECT_TRUE(needs_taken_test); 977 978 // Generates code (unsimplified). 979 range_.GenerateRange(increment_, phi, graph_, loop_preheader_, &lower, &upper); 980 981 // Verify lower is 1000-((1000-V)-1). 982 ASSERT_TRUE(lower != nullptr); 983 ASSERT_TRUE(lower->IsSub()); 984 ExpectInt(1000, lower->InputAt(0)); 985 lower = lower->InputAt(1); 986 ASSERT_TRUE(lower->IsSub()); 987 ExpectInt(1, lower->InputAt(1)); 988 lower = lower->InputAt(0); 989 ASSERT_TRUE(lower->IsSub()); 990 ExpectInt(1000, lower->InputAt(0)); 991 EXPECT_TRUE(lower->InputAt(1)->IsParameterValue()); 992 993 // Verify upper is 1000-0. 994 ASSERT_TRUE(upper != nullptr); 995 ASSERT_TRUE(upper->IsSub()); 996 ExpectInt(1000, upper->InputAt(0)); 997 ExpectInt(0, upper->InputAt(1)); 998 999 // Verify taken-test is 1000>V. 1000 HInstruction* taken = range_.GenerateTakenTest(increment_, graph_, loop_preheader_); 1001 ASSERT_TRUE(taken != nullptr); 1002 ASSERT_TRUE(taken->IsGreaterThan()); 1003 ExpectInt(1000, taken->InputAt(0)); 1004 EXPECT_TRUE(taken->InputAt(1)->IsParameterValue()); 1005 1006 // Replacement. 1007 range_.Replace(loop_header_->GetLastInstruction(), x_, y_); 1008 range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test); 1009 EXPECT_FALSE(needs_finite_test); 1010 ExpectEqual(Value(y_, 1, 0), v1); 1011 ExpectEqual(Value(999), v2); 1012 1013 // Loop logic. 1014 int64_t tc = 0; 1015 EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc)); 1016 EXPECT_EQ(0, tc); // unknown 1017 HInstruction* offset = nullptr; 1018 EXPECT_FALSE(range_.IsUnitStride(phi, phi, graph_, &offset)); 1019 HInstruction* tce = range_.GenerateTripCount( 1020 loop_header_->GetLoopInformation(), graph_, loop_preheader_); 1021 ASSERT_TRUE(tce != nullptr); 1022 EXPECT_TRUE(tce->IsSelect()); // guarded by taken-test 1023 ExpectInt(0, tce->InputAt(0)); 1024 EXPECT_TRUE(tce->InputAt(1)->IsSub()); 1025 EXPECT_TRUE(tce->InputAt(2)->IsGreaterThan()); 1026 tce = tce->InputAt(1); 1027 ExpectInt(1000, taken->InputAt(0)); 1028 EXPECT_TRUE(taken->InputAt(1)->IsParameterValue()); 1029 } 1030 1031 } // namespace art 1032