1 2 #include "polly/Support/SCEVValidator.h" 3 #include "polly/ScopInfo.h" 4 #include "llvm/Analysis/RegionInfo.h" 5 #include "llvm/Analysis/ScalarEvolution.h" 6 #include "llvm/Analysis/ScalarEvolutionExpressions.h" 7 #include "llvm/Support/Debug.h" 8 9 using namespace llvm; 10 using namespace polly; 11 12 #define DEBUG_TYPE "polly-scev-validator" 13 14 namespace SCEVType { 15 /// @brief The type of a SCEV 16 /// 17 /// To check for the validity of a SCEV we assign to each SCEV a type. The 18 /// possible types are INT, PARAM, IV and INVALID. The order of the types is 19 /// important. The subexpressions of SCEV with a type X can only have a type 20 /// that is smaller or equal than X. 21 enum TYPE { 22 // An integer value. 23 INT, 24 25 // An expression that is constant during the execution of the Scop, 26 // but that may depend on parameters unknown at compile time. 27 PARAM, 28 29 // An expression that may change during the execution of the SCoP. 30 IV, 31 32 // An invalid expression. 33 INVALID 34 }; 35 } 36 37 /// @brief The result the validator returns for a SCEV expression. 38 class ValidatorResult { 39 /// @brief The type of the expression 40 SCEVType::TYPE Type; 41 42 /// @brief The set of Parameters in the expression. 43 ParameterSetTy Parameters; 44 45 public: 46 /// @brief The copy constructor 47 ValidatorResult(const ValidatorResult &Source) { 48 Type = Source.Type; 49 Parameters = Source.Parameters; 50 } 51 52 /// @brief Construct a result with a certain type and no parameters. 53 ValidatorResult(SCEVType::TYPE Type) : Type(Type) { 54 assert(Type != SCEVType::PARAM && "Did you forget to pass the parameter"); 55 } 56 57 /// @brief Construct a result with a certain type and a single parameter. 58 ValidatorResult(SCEVType::TYPE Type, const SCEV *Expr) : Type(Type) { 59 Parameters.insert(Expr); 60 } 61 62 /// @brief Get the type of the ValidatorResult. 63 SCEVType::TYPE getType() { return Type; } 64 65 /// @brief Is the analyzed SCEV constant during the execution of the SCoP. 66 bool isConstant() { return Type == SCEVType::INT || Type == SCEVType::PARAM; } 67 68 /// @brief Is the analyzed SCEV valid. 69 bool isValid() { return Type != SCEVType::INVALID; } 70 71 /// @brief Is the analyzed SCEV of Type IV. 72 bool isIV() { return Type == SCEVType::IV; } 73 74 /// @brief Is the analyzed SCEV of Type INT. 75 bool isINT() { return Type == SCEVType::INT; } 76 77 /// @brief Is the analyzed SCEV of Type PARAM. 78 bool isPARAM() { return Type == SCEVType::PARAM; } 79 80 /// @brief Get the parameters of this validator result. 81 const ParameterSetTy &getParameters() { return Parameters; } 82 83 /// @brief Add the parameters of Source to this result. 84 void addParamsFrom(const ValidatorResult &Source) { 85 Parameters.insert(Source.Parameters.begin(), Source.Parameters.end()); 86 } 87 88 /// @brief Merge a result. 89 /// 90 /// This means to merge the parameters and to set the Type to the most 91 /// specific Type that matches both. 92 void merge(const ValidatorResult &ToMerge) { 93 Type = std::max(Type, ToMerge.Type); 94 addParamsFrom(ToMerge); 95 } 96 97 void print(raw_ostream &OS) { 98 switch (Type) { 99 case SCEVType::INT: 100 OS << "SCEVType::INT"; 101 break; 102 case SCEVType::PARAM: 103 OS << "SCEVType::PARAM"; 104 break; 105 case SCEVType::IV: 106 OS << "SCEVType::IV"; 107 break; 108 case SCEVType::INVALID: 109 OS << "SCEVType::INVALID"; 110 break; 111 } 112 } 113 }; 114 115 raw_ostream &operator<<(raw_ostream &OS, class ValidatorResult &VR) { 116 VR.print(OS); 117 return OS; 118 } 119 120 /// Check if a SCEV is valid in a SCoP. 121 struct SCEVValidator 122 : public SCEVVisitor<SCEVValidator, class ValidatorResult> { 123 private: 124 const Region *R; 125 Loop *Scope; 126 ScalarEvolution &SE; 127 InvariantLoadsSetTy *ILS; 128 129 public: 130 SCEVValidator(const Region *R, Loop *Scope, ScalarEvolution &SE, 131 InvariantLoadsSetTy *ILS) 132 : R(R), Scope(Scope), SE(SE), ILS(ILS) {} 133 134 class ValidatorResult visitConstant(const SCEVConstant *Constant) { 135 return ValidatorResult(SCEVType::INT); 136 } 137 138 class ValidatorResult visitTruncateExpr(const SCEVTruncateExpr *Expr) { 139 ValidatorResult Op = visit(Expr->getOperand()); 140 141 switch (Op.getType()) { 142 case SCEVType::INT: 143 case SCEVType::PARAM: 144 // We currently do not represent a truncate expression as an affine 145 // expression. If it is constant during Scop execution, we treat it as a 146 // parameter. 147 return ValidatorResult(SCEVType::PARAM, Expr); 148 case SCEVType::IV: 149 DEBUG(dbgs() << "INVALID: Truncation of SCEVType::IV expression"); 150 return ValidatorResult(SCEVType::INVALID); 151 case SCEVType::INVALID: 152 return Op; 153 } 154 155 llvm_unreachable("Unknown SCEVType"); 156 } 157 158 class ValidatorResult visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) { 159 return visit(Expr->getOperand()); 160 } 161 162 class ValidatorResult visitSignExtendExpr(const SCEVSignExtendExpr *Expr) { 163 // We currently allow only signed SCEV expressions. In the case of a 164 // signed value, a sign extend is a noop. 165 // 166 // TODO: Reconsider this when we add support for unsigned values. 167 return visit(Expr->getOperand()); 168 } 169 170 class ValidatorResult visitAddExpr(const SCEVAddExpr *Expr) { 171 ValidatorResult Return(SCEVType::INT); 172 173 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) { 174 ValidatorResult Op = visit(Expr->getOperand(i)); 175 Return.merge(Op); 176 177 // Early exit. 178 if (!Return.isValid()) 179 break; 180 } 181 182 // TODO: Check for NSW and NUW. 183 return Return; 184 } 185 186 class ValidatorResult visitMulExpr(const SCEVMulExpr *Expr) { 187 ValidatorResult Return(SCEVType::INT); 188 189 bool HasMultipleParams = false; 190 191 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) { 192 ValidatorResult Op = visit(Expr->getOperand(i)); 193 194 if (Op.isINT()) 195 continue; 196 197 if (Op.isPARAM() && Return.isPARAM()) { 198 HasMultipleParams = true; 199 continue; 200 } 201 202 if ((Op.isIV() || Op.isPARAM()) && !Return.isINT()) { 203 DEBUG(dbgs() << "INVALID: More than one non-int operand in MulExpr\n" 204 << "\tExpr: " << *Expr << "\n" 205 << "\tPrevious expression type: " << Return << "\n" 206 << "\tNext operand (" << Op 207 << "): " << *Expr->getOperand(i) << "\n"); 208 209 return ValidatorResult(SCEVType::INVALID); 210 } 211 212 Return.merge(Op); 213 } 214 215 if (HasMultipleParams && Return.isValid()) 216 return ValidatorResult(SCEVType::PARAM, Expr); 217 218 // TODO: Check for NSW and NUW. 219 return Return; 220 } 221 222 class ValidatorResult visitAddRecExpr(const SCEVAddRecExpr *Expr) { 223 if (!Expr->isAffine()) { 224 DEBUG(dbgs() << "INVALID: AddRec is not affine"); 225 return ValidatorResult(SCEVType::INVALID); 226 } 227 228 ValidatorResult Start = visit(Expr->getStart()); 229 ValidatorResult Recurrence = visit(Expr->getStepRecurrence(SE)); 230 231 if (!Start.isValid()) 232 return Start; 233 234 if (!Recurrence.isValid()) 235 return Recurrence; 236 237 auto *L = Expr->getLoop(); 238 if (R->contains(L) && (!Scope || !L->contains(Scope))) { 239 DEBUG(dbgs() << "INVALID: AddRec out of a loop whose exit value is not " 240 "synthesizable"); 241 return ValidatorResult(SCEVType::INVALID); 242 } 243 244 if (R->contains(L)) { 245 if (Recurrence.isINT()) { 246 ValidatorResult Result(SCEVType::IV); 247 Result.addParamsFrom(Start); 248 return Result; 249 } 250 251 DEBUG(dbgs() << "INVALID: AddRec within scop has non-int" 252 "recurrence part"); 253 return ValidatorResult(SCEVType::INVALID); 254 } 255 256 assert(Start.isConstant() && Recurrence.isConstant() && 257 "Expected 'Start' and 'Recurrence' to be constant"); 258 259 // Directly generate ValidatorResult for Expr if 'start' is zero. 260 if (Expr->getStart()->isZero()) 261 return ValidatorResult(SCEVType::PARAM, Expr); 262 263 // Translate AddRecExpr from '{start, +, inc}' into 'start + {0, +, inc}' 264 // if 'start' is not zero. 265 const SCEV *ZeroStartExpr = SE.getAddRecExpr( 266 SE.getConstant(Expr->getStart()->getType(), 0), 267 Expr->getStepRecurrence(SE), Expr->getLoop(), Expr->getNoWrapFlags()); 268 269 ValidatorResult ZeroStartResult = 270 ValidatorResult(SCEVType::PARAM, ZeroStartExpr); 271 ZeroStartResult.addParamsFrom(Start); 272 273 return ZeroStartResult; 274 } 275 276 class ValidatorResult visitSMaxExpr(const SCEVSMaxExpr *Expr) { 277 ValidatorResult Return(SCEVType::INT); 278 279 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) { 280 ValidatorResult Op = visit(Expr->getOperand(i)); 281 282 if (!Op.isValid()) 283 return Op; 284 285 Return.merge(Op); 286 } 287 288 return Return; 289 } 290 291 class ValidatorResult visitUMaxExpr(const SCEVUMaxExpr *Expr) { 292 // We do not support unsigned operations. If 'Expr' is constant during Scop 293 // execution we treat this as a parameter, otherwise we bail out. 294 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) { 295 ValidatorResult Op = visit(Expr->getOperand(i)); 296 297 if (!Op.isConstant()) { 298 DEBUG(dbgs() << "INVALID: UMaxExpr has a non-constant operand"); 299 return ValidatorResult(SCEVType::INVALID); 300 } 301 } 302 303 return ValidatorResult(SCEVType::PARAM, Expr); 304 } 305 306 ValidatorResult visitGenericInst(Instruction *I, const SCEV *S) { 307 if (R->contains(I)) { 308 DEBUG(dbgs() << "INVALID: UnknownExpr references an instruction " 309 "within the region\n"); 310 return ValidatorResult(SCEVType::INVALID); 311 } 312 313 return ValidatorResult(SCEVType::PARAM, S); 314 } 315 316 ValidatorResult visitLoadInstruction(Instruction *I, const SCEV *S) { 317 if (R->contains(I) && ILS) { 318 ILS->insert(cast<LoadInst>(I)); 319 return ValidatorResult(SCEVType::PARAM, S); 320 } 321 322 return visitGenericInst(I, S); 323 } 324 325 ValidatorResult visitDivision(const SCEV *Dividend, const SCEV *Divisor, 326 const SCEV *DivExpr, 327 Instruction *SDiv = nullptr) { 328 329 // First check if we might be able to model the division, thus if the 330 // divisor is constant. If so, check the dividend, otherwise check if 331 // the whole division can be seen as a parameter. 332 if (isa<SCEVConstant>(Divisor)) 333 return visit(Dividend); 334 335 // For signed divisions use the SDiv instruction to check for a parameter 336 // division, for unsigned divisions check the operands. 337 if (SDiv) 338 return visitGenericInst(SDiv, DivExpr); 339 340 ValidatorResult LHS = visit(Dividend); 341 ValidatorResult RHS = visit(Divisor); 342 if (LHS.isConstant() && RHS.isConstant()) 343 return ValidatorResult(SCEVType::PARAM, DivExpr); 344 345 DEBUG(dbgs() << "INVALID: unsigned division of non-constant expressions"); 346 return ValidatorResult(SCEVType::INVALID); 347 } 348 349 ValidatorResult visitUDivExpr(const SCEVUDivExpr *Expr) { 350 auto *Dividend = Expr->getLHS(); 351 auto *Divisor = Expr->getRHS(); 352 return visitDivision(Dividend, Divisor, Expr); 353 } 354 355 ValidatorResult visitSDivInstruction(Instruction *SDiv, const SCEV *Expr) { 356 assert(SDiv->getOpcode() == Instruction::SDiv && 357 "Assumed SDiv instruction!"); 358 359 auto *Dividend = SE.getSCEV(SDiv->getOperand(0)); 360 auto *Divisor = SE.getSCEV(SDiv->getOperand(1)); 361 return visitDivision(Dividend, Divisor, Expr, SDiv); 362 } 363 364 ValidatorResult visitSRemInstruction(Instruction *SRem, const SCEV *S) { 365 assert(SRem->getOpcode() == Instruction::SRem && 366 "Assumed SRem instruction!"); 367 368 auto *Divisor = SRem->getOperand(1); 369 auto *CI = dyn_cast<ConstantInt>(Divisor); 370 if (!CI) 371 return visitGenericInst(SRem, S); 372 373 auto *Dividend = SRem->getOperand(0); 374 auto *DividendSCEV = SE.getSCEV(Dividend); 375 return visit(DividendSCEV); 376 } 377 378 ValidatorResult visitUnknown(const SCEVUnknown *Expr) { 379 Value *V = Expr->getValue(); 380 381 if (!Expr->getType()->isIntegerTy() && !Expr->getType()->isPointerTy()) { 382 DEBUG(dbgs() << "INVALID: UnknownExpr is not an integer or pointer"); 383 return ValidatorResult(SCEVType::INVALID); 384 } 385 386 if (isa<UndefValue>(V)) { 387 DEBUG(dbgs() << "INVALID: UnknownExpr references an undef value"); 388 return ValidatorResult(SCEVType::INVALID); 389 } 390 391 if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) { 392 switch (I->getOpcode()) { 393 case Instruction::Load: 394 return visitLoadInstruction(I, Expr); 395 case Instruction::SDiv: 396 return visitSDivInstruction(I, Expr); 397 case Instruction::SRem: 398 return visitSRemInstruction(I, Expr); 399 default: 400 return visitGenericInst(I, Expr); 401 } 402 } 403 404 return ValidatorResult(SCEVType::PARAM, Expr); 405 } 406 }; 407 408 /// @brief Check whether a SCEV refers to an SSA name defined inside a region. 409 class SCEVInRegionDependences { 410 const Region *R; 411 Loop *Scope; 412 bool AllowLoops; 413 bool HasInRegionDeps = false; 414 415 public: 416 SCEVInRegionDependences(const Region *R, Loop *Scope, bool AllowLoops) 417 : R(R), Scope(Scope), AllowLoops(AllowLoops) {} 418 419 bool follow(const SCEV *S) { 420 if (auto Unknown = dyn_cast<SCEVUnknown>(S)) { 421 Instruction *Inst = dyn_cast<Instruction>(Unknown->getValue()); 422 423 // Return true when Inst is defined inside the region R. 424 if (Inst && R->contains(Inst)) { 425 HasInRegionDeps = true; 426 return false; 427 } 428 } else if (auto AddRec = dyn_cast<SCEVAddRecExpr>(S)) { 429 if (!AllowLoops) { 430 if (!Scope) { 431 HasInRegionDeps = true; 432 return false; 433 } 434 auto *L = AddRec->getLoop(); 435 if (R->contains(L) && !L->contains(Scope)) { 436 HasInRegionDeps = true; 437 return false; 438 } 439 } 440 } 441 return true; 442 } 443 bool isDone() { return false; } 444 bool hasDependences() { return HasInRegionDeps; } 445 }; 446 447 namespace polly { 448 /// Find all loops referenced in SCEVAddRecExprs. 449 class SCEVFindLoops { 450 SetVector<const Loop *> &Loops; 451 452 public: 453 SCEVFindLoops(SetVector<const Loop *> &Loops) : Loops(Loops) {} 454 455 bool follow(const SCEV *S) { 456 if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) 457 Loops.insert(AddRec->getLoop()); 458 return true; 459 } 460 bool isDone() { return false; } 461 }; 462 463 void findLoops(const SCEV *Expr, SetVector<const Loop *> &Loops) { 464 SCEVFindLoops FindLoops(Loops); 465 SCEVTraversal<SCEVFindLoops> ST(FindLoops); 466 ST.visitAll(Expr); 467 } 468 469 /// Find all values referenced in SCEVUnknowns. 470 class SCEVFindValues { 471 ScalarEvolution &SE; 472 SetVector<Value *> &Values; 473 474 public: 475 SCEVFindValues(ScalarEvolution &SE, SetVector<Value *> &Values) 476 : SE(SE), Values(Values) {} 477 478 bool follow(const SCEV *S) { 479 const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(S); 480 if (!Unknown) 481 return true; 482 483 Values.insert(Unknown->getValue()); 484 Instruction *Inst = dyn_cast<Instruction>(Unknown->getValue()); 485 if (!Inst || (Inst->getOpcode() != Instruction::SRem && 486 Inst->getOpcode() != Instruction::SDiv)) 487 return false; 488 489 auto *Dividend = SE.getSCEV(Inst->getOperand(1)); 490 if (!isa<SCEVConstant>(Dividend)) 491 return false; 492 493 auto *Divisor = SE.getSCEV(Inst->getOperand(0)); 494 SCEVFindValues FindValues(SE, Values); 495 SCEVTraversal<SCEVFindValues> ST(FindValues); 496 ST.visitAll(Dividend); 497 ST.visitAll(Divisor); 498 499 return false; 500 } 501 bool isDone() { return false; } 502 }; 503 504 void findValues(const SCEV *Expr, ScalarEvolution &SE, 505 SetVector<Value *> &Values) { 506 SCEVFindValues FindValues(SE, Values); 507 SCEVTraversal<SCEVFindValues> ST(FindValues); 508 ST.visitAll(Expr); 509 } 510 511 bool hasScalarDepsInsideRegion(const SCEV *Expr, const Region *R, 512 llvm::Loop *Scope, bool AllowLoops) { 513 SCEVInRegionDependences InRegionDeps(R, Scope, AllowLoops); 514 SCEVTraversal<SCEVInRegionDependences> ST(InRegionDeps); 515 ST.visitAll(Expr); 516 return InRegionDeps.hasDependences(); 517 } 518 519 bool isAffineExpr(const Region *R, llvm::Loop *Scope, const SCEV *Expr, 520 ScalarEvolution &SE, InvariantLoadsSetTy *ILS) { 521 if (isa<SCEVCouldNotCompute>(Expr)) 522 return false; 523 524 SCEVValidator Validator(R, Scope, SE, ILS); 525 DEBUG({ 526 dbgs() << "\n"; 527 dbgs() << "Expr: " << *Expr << "\n"; 528 dbgs() << "Region: " << R->getNameStr() << "\n"; 529 dbgs() << " -> "; 530 }); 531 532 ValidatorResult Result = Validator.visit(Expr); 533 534 DEBUG({ 535 if (Result.isValid()) 536 dbgs() << "VALID\n"; 537 dbgs() << "\n"; 538 }); 539 540 return Result.isValid(); 541 } 542 543 static bool isAffineParamExpr(Value *V, const Region *R, Loop *Scope, 544 ScalarEvolution &SE, ParameterSetTy &Params) { 545 auto *E = SE.getSCEV(V); 546 if (isa<SCEVCouldNotCompute>(E)) 547 return false; 548 549 SCEVValidator Validator(R, Scope, SE, nullptr); 550 ValidatorResult Result = Validator.visit(E); 551 if (!Result.isConstant()) 552 return false; 553 554 auto ResultParams = Result.getParameters(); 555 Params.insert(ResultParams.begin(), ResultParams.end()); 556 557 return true; 558 } 559 560 bool isAffineParamConstraint(Value *V, const Region *R, llvm::Loop *Scope, 561 ScalarEvolution &SE, ParameterSetTy &Params, 562 bool OrExpr) { 563 if (auto *ICmp = dyn_cast<ICmpInst>(V)) { 564 return isAffineParamConstraint(ICmp->getOperand(0), R, Scope, SE, Params, 565 true) && 566 isAffineParamConstraint(ICmp->getOperand(1), R, Scope, SE, Params, 567 true); 568 } else if (auto *BinOp = dyn_cast<BinaryOperator>(V)) { 569 auto Opcode = BinOp->getOpcode(); 570 if (Opcode == Instruction::And || Opcode == Instruction::Or) 571 return isAffineParamConstraint(BinOp->getOperand(0), R, Scope, SE, Params, 572 false) && 573 isAffineParamConstraint(BinOp->getOperand(1), R, Scope, SE, Params, 574 false); 575 /* Fall through */ 576 } 577 578 if (!OrExpr) 579 return false; 580 581 return isAffineParamExpr(V, R, Scope, SE, Params); 582 } 583 584 ParameterSetTy getParamsInAffineExpr(const Region *R, Loop *Scope, 585 const SCEV *Expr, ScalarEvolution &SE) { 586 if (isa<SCEVCouldNotCompute>(Expr)) 587 return ParameterSetTy(); 588 589 InvariantLoadsSetTy ILS; 590 SCEVValidator Validator(R, Scope, SE, &ILS); 591 ValidatorResult Result = Validator.visit(Expr); 592 assert(Result.isValid() && "Requested parameters for an invalid SCEV!"); 593 594 return Result.getParameters(); 595 } 596 597 std::pair<const SCEVConstant *, const SCEV *> 598 extractConstantFactor(const SCEV *S, ScalarEvolution &SE) { 599 600 auto *LeftOver = SE.getConstant(S->getType(), 1); 601 auto *ConstPart = cast<SCEVConstant>(SE.getConstant(S->getType(), 1)); 602 603 if (auto *Constant = dyn_cast<SCEVConstant>(S)) 604 return std::make_pair(Constant, LeftOver); 605 606 auto *AddRec = dyn_cast<SCEVAddRecExpr>(S); 607 if (AddRec) { 608 auto *StartExpr = AddRec->getStart(); 609 if (StartExpr->isZero()) { 610 auto StepPair = extractConstantFactor(AddRec->getStepRecurrence(SE), SE); 611 auto *LeftOverAddRec = 612 SE.getAddRecExpr(StartExpr, StepPair.second, AddRec->getLoop(), 613 AddRec->getNoWrapFlags()); 614 return std::make_pair(StepPair.first, LeftOverAddRec); 615 } 616 return std::make_pair(ConstPart, S); 617 } 618 619 if (auto *Add = dyn_cast<SCEVAddExpr>(S)) { 620 SmallVector<const SCEV *, 4> LeftOvers; 621 auto Op0Pair = extractConstantFactor(Add->getOperand(0), SE); 622 auto *Factor = Op0Pair.first; 623 if (SE.isKnownNegative(Factor)) { 624 Factor = cast<SCEVConstant>(SE.getNegativeSCEV(Factor)); 625 LeftOvers.push_back(SE.getNegativeSCEV(Op0Pair.second)); 626 } else { 627 LeftOvers.push_back(Op0Pair.second); 628 } 629 630 for (unsigned u = 1, e = Add->getNumOperands(); u < e; u++) { 631 auto OpUPair = extractConstantFactor(Add->getOperand(u), SE); 632 // TODO: Use something smarter than equality here, e.g., gcd. 633 if (Factor == OpUPair.first) 634 LeftOvers.push_back(OpUPair.second); 635 else if (Factor == SE.getNegativeSCEV(OpUPair.first)) 636 LeftOvers.push_back(SE.getNegativeSCEV(OpUPair.second)); 637 else 638 return std::make_pair(ConstPart, S); 639 } 640 641 auto *NewAdd = SE.getAddExpr(LeftOvers, Add->getNoWrapFlags()); 642 return std::make_pair(Factor, NewAdd); 643 } 644 645 auto *Mul = dyn_cast<SCEVMulExpr>(S); 646 if (!Mul) 647 return std::make_pair(ConstPart, S); 648 649 for (auto *Op : Mul->operands()) 650 if (isa<SCEVConstant>(Op)) 651 ConstPart = cast<SCEVConstant>(SE.getMulExpr(ConstPart, Op)); 652 else 653 LeftOver = SE.getMulExpr(LeftOver, Op); 654 655 return std::make_pair(ConstPart, LeftOver); 656 } 657 } 658