54 static std::unique_ptr<Context>
57 return std::make_unique<Context>();
60 std::unique_ptr<SCEVChainRecurrence>
67 return SCEV::CloneAs<SCEVChainRecurrence>(*it->second);
73 const auto it =
SCEVMap_.find(&output);
74 if (it ==
SCEVMap_.end() || !it->second)
77 return it->second->Clone();
83 ChrecMap_.insert_or_assign(&output, SCEV::CloneAs<SCEVChainRecurrence>(*chrec));
86 const std::unordered_map<rvsdg::Output *, std::unique_ptr<SCEVChainRecurrence>> &
92 const std::unordered_map<rvsdg::Output *, std::unique_ptr<SCEV>> &
105 if (rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*out)
108 if (chrec->GetOperands().size() == n + 1 && !
IsUnknown(*chrec))
121 if (rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*out)
135 SCEVMap_.insert_or_assign(&output, scev->Clone());
162 const std::unordered_map<const rvsdg::ThetaNode *, size_t> &
169 std::unordered_map<rvsdg::Output *, std::unique_ptr<SCEVChainRecurrence>>
ChrecMap_;
170 std::unordered_map<rvsdg::Output *, std::unique_ptr<SCEV>>
SCEVMap_;
200 context.GetNumInductionVariablesWithOrder(0));
203 context.GetNumInductionVariablesWithOrder(1));
206 context.GetNumInductionVariablesWithOrder(2));
217 for (
auto & [thetaNode, tripCount] : tripCountMap)
223 s +=
"ID(" + std::to_string(thetaNode->subregion()->getRegionId())
224 +
")=" + std::to_string(tripCount);
229 static std::unique_ptr<Statistics>
232 return std::make_unique<Statistics>(sourceFile);
237 : rvsdg::Transformation(
"ScalarEvolution")
245 std::unordered_map<const rvsdg::Output *, std::unique_ptr<SCEVChainRecurrence>> mapCopy{};
246 for (
auto & [output, chrec] : Context_->GetChrecMap())
248 mapCopy.emplace(output, SCEV::CloneAs<SCEVChainRecurrence>(*chrec));
253 std::unordered_map<const rvsdg::Output *, std::unique_ptr<SCEV>>
256 std::unordered_map<const rvsdg::Output *, std::unique_ptr<SCEV>> mapCopy{};
257 for (
auto & [output, scev] :
Context_->GetSCEVMap())
259 mapCopy.emplace(output, scev->Clone());
264 std::unordered_map<const rvsdg::ThetaNode *, size_t>
290 for (
auto & node : region.
Nodes())
294 for (
auto & subregion : structuralNode->Subregions())
302 for (
const auto loopVar : thetaNode->GetLoopVars())
315 if (tripCount.has_value())
316 Context_->SetTripCount(*thetaNode, *tripCount);
325 if (
auto constantStep =
dynamic_cast<const SCEVConstant *
>(&stepSCEV))
327 return constantStep->GetValue() < 0;
333 const auto start =
dynamic_cast<const SCEVConstant *
>(recurrenceStep->GetStartValue());
334 auto stepPtr = recurrenceStep->GetStep();
335 const auto step =
dynamic_cast<const SCEVConstant *
>(stepPtr->get());
338 throw std::logic_error(
"Step can only contain constant SCEVs!");
340 const auto a = start->GetValue();
341 const auto b = step->GetValue();
343 return a <= 0 && b <= 0 && !(a == 0 && b == 0);
345 throw std::logic_error(
"Wrong type for step!");
351 if (
auto constantStep =
dynamic_cast<const SCEVConstant *
>(&stepSCEV))
353 return constantStep->GetValue() > 0;
359 const auto start =
dynamic_cast<const SCEVConstant *
>(recurrenceStep->GetStartValue());
360 auto stepPtr = recurrenceStep->GetStep();
361 const auto step =
dynamic_cast<const SCEVConstant *
>(stepPtr->get());
364 throw std::logic_error(
"Step can only contain constant SCEVs!");
366 const auto a = start->GetValue();
367 const auto b = step->GetValue();
369 return a >= 0 && b >= 0 && !(a == 0 && b == 0);
371 throw std::logic_error(
"Wrong type for step!");
377 if (
auto constantStep =
dynamic_cast<const SCEVConstant *
>(&stepSCEV))
379 return constantStep->GetValue() == 0;
385 const auto start =
dynamic_cast<const SCEVConstant *
>(recurrenceStep->GetStartValue());
386 auto stepPtr = recurrenceStep->GetStep();
387 const auto step =
dynamic_cast<const SCEVConstant *
>(stepPtr->get());
390 throw std::logic_error(
"Step can only contain constant SCEVs!");
392 const auto a = start->GetValue();
393 const auto b = step->GetValue();
395 return a == 0 && b == 0;
397 throw std::logic_error(
"Wrong type for step!");
400 std::optional<size_t>
404 const auto & [node, matchOperation] =
405 rvsdg::TryGetSimpleNodeAndOptionalOp<rvsdg::MatchOperation>(*pred->origin());
411 const auto origin = node->input(0)->origin();
412 const auto comparisonNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*origin);
416 const auto * comparisonOperation = &comparisonNode->GetOperation();
417 if (!(rvsdg::is<IntegerSltOperation>(*comparisonOperation)
418 || rvsdg::is<IntegerSleOperation>(*comparisonOperation)
419 || rvsdg::is<IntegerUltOperation>(*comparisonOperation)
420 || rvsdg::is<IntegerUleOperation>(*comparisonOperation)
421 || rvsdg::is<IntegerSgtOperation>(*comparisonOperation)
422 || rvsdg::is<IntegerSgeOperation>(*comparisonOperation)
423 || rvsdg::is<IntegerUgtOperation>(*comparisonOperation)
424 || rvsdg::is<IntegerUgeOperation>(*comparisonOperation)
425 || rvsdg::is<IntegerNeOperation>(*comparisonOperation)
426 || rvsdg::is<IntegerEqOperation>(*comparisonOperation)))
429 auto & lhs = *comparisonNode->input(0)->origin();
430 auto & rhs = *comparisonNode->input(1)->origin();
431 auto lhsChrec =
Context_->TryGetChrecForOutput(lhs);
432 auto rhsChrec =
Context_->TryGetChrecForOutput(rhs);
441 std::unique_ptr<SCEVChainRecurrence> chrec{};
445 const auto constantSCEV =
dynamic_cast<SCEVConstant *
>(lhsChrec->GetOperand(0));
450 chrec = SCEV::CloneAs<SCEVChainRecurrence>(*rhsChrec);
454 const auto constantSCEV =
dynamic_cast<SCEVConstant *
>(rhsChrec->GetOperand(0));
459 chrec = SCEV::CloneAs<SCEVChainRecurrence>(*lhsChrec);
474 for (
const auto op : chrec->GetOperands())
484 const auto start =
dynamic_cast<const SCEVConstant *
>(chrec->GetStartValue())->GetValue();
485 const auto stepOpt = chrec->GetStep();
489 const auto & stepSCEV = **stepOpt;
491 if (rvsdg::is<IntegerSltOperation>(*comparisonOperation)
492 || rvsdg::is<IntegerUltOperation>(*comparisonOperation))
499 const auto backedgeTakenCount =
501 if (backedgeTakenCount.has_value())
504 return *backedgeTakenCount + 1;
508 if (rvsdg::is<IntegerSleOperation>(*comparisonOperation)
509 || rvsdg::is<IntegerUleOperation>(*comparisonOperation))
515 const auto backedgeTakenCount =
517 if (backedgeTakenCount.has_value())
519 return *backedgeTakenCount + 1;
523 if (rvsdg::is<IntegerSgtOperation>(*comparisonOperation)
524 || rvsdg::is<IntegerUgtOperation>(*comparisonOperation))
530 const auto backedgeTakenCount =
532 if (backedgeTakenCount.has_value())
534 return *backedgeTakenCount + 1;
538 if (rvsdg::is<IntegerSgeOperation>(*comparisonOperation)
539 || rvsdg::is<IntegerUgeOperation>(*comparisonOperation))
545 const auto backedgeTakenCount =
547 if (backedgeTakenCount.has_value())
549 return *backedgeTakenCount + 1;
554 if (rvsdg::is<IntegerNeOperation>(*comparisonOperation))
560 const auto step =
dynamic_cast<const SCEVConstant *
>(&stepSCEV)->GetValue();
563 const auto backedgeTakenCount =
566 if (start <= bound && (bound - start) % step == 0)
567 return *backedgeTakenCount + 1;
571 const auto backedgeTakenCount =
573 if (start >= bound && (bound - start) % step == 0)
574 return *backedgeTakenCount + 1;
581 if (rvsdg::is<IntegerEqOperation>(*comparisonOperation))
606 std::optional<size_t>
613 const auto stepOpt = chrec.
GetStep();
617 const auto & stepSCEV = *stepOpt;
619 bool isEqualsComparison = rvsdg::is<IntegerSleOperation>(*comparisonOperation)
620 || rvsdg::is<IntegerUleOperation>(*comparisonOperation)
621 || rvsdg::is<IntegerSgeOperation>(*comparisonOperation)
622 || rvsdg::is<IntegerUgeOperation>(*comparisonOperation);
628 const auto stepConstant =
dynamic_cast<const SCEVConstant *
>(stepSCEV.get());
629 const auto step = stepConstant->
GetValue();
633 size_t result = std::ceil(
static_cast<double>(bound - start) / step);
635 if (isEqualsComparison)
639 if ((bound - start) % step == 0)
652 const int64_t stepFirst =
653 dynamic_cast<const SCEVConstant *
>(stepRecurrence->GetStartValue())->GetValue();
655 const int64_t stepSecond =
656 dynamic_cast<const SCEVConstant *
>(stepRecurrence->GetStep()->get())->GetValue();
671 const int64_t a = stepSecond;
672 const int64_t b = 2 * stepFirst - stepSecond;
673 const int64_t c = 2 * (start - bound);
676 if (!quadraticResult.has_value())
679 size_t result = *quadraticResult;
681 if (isEqualsComparison)
685 const int64_t valueAtResult =
686 start + result * stepFirst + result * (result - 1) / 2 * stepSecond;
687 if (valueAtResult == bound)
695 std::optional<size_t>
706 const auto d = b * b - 4 * a * c;
712 int64_t sq = std::floor(std::sqrt(d));
715 const bool inexactSq = (sq * sq != d);
733 x = (-b - (sq + (inexactSq ? 1 : 0))) / (2 * a);
734 rem = (-b - sq) % (2 * a);
738 x = (-b + sq) / (2 * a);
739 rem = (-b + sq) % (2 * a);
747 if (!inexactSq && rem == 0)
754 const int64_t valueAtX = (a * x + b) * x + c;
755 const int64_t valueAtXPlusOne = (a * (x + 1) + b) * (x + 1) + c;
757 const bool signChange =
758 ((valueAtX < 0) != (valueAtXPlusOne < 0)) || ((valueAtX == 0) != (valueAtXPlusOne == 0));
775 std::vector<std::pair<rvsdg::Output *, std::unique_ptr<SCEV>>> pending;
776 for (
auto & [output, chrec] :
Context_->GetChrecMap())
780 pending.emplace_back(output, std::move(*newSCEV));
785 for (
auto & [output, scev] : pending)
790 Context_->InsertChrec(*output, SCEV::CloneAs<SCEVChainRecurrence>(*chrec));
796 Context_->InsertSCEV(*output, std::move(scev));
802 std::optional<std::unique_ptr<SCEV>>
805 if (
const auto initSCEV =
dynamic_cast<const SCEVInit *
>(&scev))
809 const auto & initPrePointer = initSCEV->GetPrePointer();
810 if (
const auto innerTheta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(initPrePointer))
812 const auto correspondingInput = innerTheta->MapPreLoopVar(initPrePointer).input;
814 if (
const auto originSCEV =
Context_->TryGetSCEVForOutput(inputOrigin))
818 const auto thetaParent = rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(inputOrigin);
819 const auto outerTheta =
820 thetaParent ? thetaParent
821 : util::assertedCast<rvsdg::ThetaNode>(inputOrigin.region()->node());
826 return chrec->Clone();
830 if (
const auto nArySCEV =
dynamic_cast<const SCEVNAryExpr *
>(&scev))
834 auto clone = SCEV::CloneAs<SCEVNAryExpr>(*nArySCEV);
835 const auto operands = nArySCEV->GetOperands();
836 bool changed =
false;
837 for (
size_t i = 0; i <
operands.size(); ++i)
845 clone->ReplaceOperand(i, std::move(*result));
879 const auto post = loopVar.post;
883 Context_->InsertSCEV(*loopVar.output, scev);
889 for (
const auto & [output, deps] : dependencyGraph)
892 validOutputs.
insert(output);
897 auto filteredDependencyGraph = dependencyGraph;
898 for (
auto it = filteredDependencyGraph.begin(); it != filteredDependencyGraph.end();)
900 if (!validOutputs.Contains(it->first))
902 for (
auto & [node, deps] : filteredDependencyGraph)
903 deps.erase(it->first);
904 it = filteredDependencyGraph.erase(it);
912 for (
auto output : order)
914 std::unique_ptr<SCEV> scev{};
915 if (
const auto theta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*output);
921 scev =
Context_->TryGetSCEVForOutput(newOutput);
924 scev =
Context_->TryGetSCEVForOutput(*output);
929 Context_->InsertChrec(*output, chrec);
932 for (
auto & [output, scev] :
Context_->GetSCEVMap())
934 if (std::find(order.begin(), order.end(), output) == order.end())
936 auto unknownChainRecurrence =
938 Context_->InsertChrec(*output, unknownChainRecurrence);
943 std::unique_ptr<SCEV>
946 if (
const auto existing =
Context_->TryGetSCEVForOutput(output))
947 return existing->Clone();
949 std::unique_ptr<SCEV> result{};
950 if (rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(output))
957 const auto & [simpleNode, simpleOperation] =
958 rvsdg::TryGetSimpleNodeAndOptionalOp<rvsdg::SimpleOperation>(output);
962 if (rvsdg::is<IOBarrierOperation>(*simpleOperation))
968 rvsdg::is<SExtOperation>(*simpleOperation) || rvsdg::is<ZExtOperation>(*simpleOperation))
976 const auto baseIndex = simpleNode->input(0)->origin();
977 JLM_ASSERT(is<PointerType>(baseIndex->Type()));
979 const auto & pointeeType = gepOp->getPointeeType();
986 std::unique_ptr<SCEV> offset =
995 const auto value = constOp->Representation().to_int();
998 else if (rvsdg::is<IntegerBinaryOperation>(*simpleOperation))
1001 const auto lhs = simpleNode->input(0)->origin();
1002 const auto rhs = simpleNode->input(1)->origin();
1006 if (rvsdg::is<IntegerAddOperation>(*simpleOperation))
1010 else if (rvsdg::is<IntegerSubOperation>(*simpleOperation))
1016 else if (rvsdg::is<IntegerMulOperation>(*simpleOperation))
1020 else if (rvsdg::is<IntegerShlOperation>(*simpleOperation))
1022 if (
const auto * rhsConst =
dynamic_cast<SCEVConstant *
>(rhsScev.get()))
1024 const auto shiftAmount = rhsConst->GetValue();
1033 for (
auto & input : simpleNode->Inputs())
1045 Context_->InsertSCEV(output, result);
1050 std::unique_ptr<SCEV>
1053 const size_t inputIndex,
1058 if (inputIndex >= gepNode.
ninputs())
1063 const auto gepInput = gepNode.
input(inputIndex);
1064 if (
const auto arrayType =
dynamic_cast<const ArrayType *
>(&type))
1066 const auto & elementType = *arrayType->GetElementType();
1078 if (
const auto structType =
dynamic_cast<const StructType *
>(&type))
1082 if (!indexingValue.has_value())
1085 const auto & fieldType = structType->getElementType(*indexingValue);
1096 throw std::logic_error(
"Unknown GEP type!");
1105 if (
const auto placeholderSCEV =
dynamic_cast<const SCEVPlaceholder *
>(&scev))
1107 auto & dependency = placeholderSCEV->GetPrePointer();
1111 auto & depInfo = dependencies[&dependency];
1112 depInfo.operation = op;
1116 if (
const auto addSCEV =
dynamic_cast<const SCEVAddExpr *
>(&scev))
1122 if (
const auto mulSCEV =
dynamic_cast<const SCEVMulExpr *
>(&scev))
1134 for (
const auto & [output, scev] :
Context_->GetSCEVMap())
1137 if (
const auto theta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(*output);
1138 theta == &thetaNode)
1142 const auto loopVar = theta->MapPreLoopVar(*output);
1143 auto newScev =
Context_->TryGetSCEVForOutput(*loopVar.post->origin());
1150 graph[output] = dependencies;
1156 std::vector<rvsdg::Output *>
1159 const size_t numVertices = dependencyGraph.size();
1160 std::unordered_map<const rvsdg::Output *, int> indegree(numVertices);
1161 std::queue<rvsdg::Output *> q{};
1162 for (
auto & [node, deps] : dependencyGraph)
1164 for (
auto & dep : deps)
1166 if (
const auto ptr = dep.first; ptr == node)
1169 indegree[node] += 1;
1171 if (indegree[node] == 0)
1178 std::vector<rvsdg::Output *> result{};
1183 result.push_back(currentNode);
1185 for (
const auto & [node, deps] : dependencyGraph)
1187 if (node == currentNode)
1190 for (
const auto & dep : deps)
1192 const auto ptr = dep.first;
1195 if (ptr == currentNode)
1198 indegree[node] -= 1;
1199 if (indegree[node] == 0)
1209 std::unique_ptr<SCEVChainRecurrence>
1215 if (
const auto existing =
Context_->TryGetChrecForOutput(output))
1217 return SCEV::CloneAs<SCEVChainRecurrence>(*existing);
1222 if (
const auto theta = rvsdg::TryGetRegionParentNode<rvsdg::ThetaNode>(output);
1223 theta == &thetaNode)
1239 return stepRecurrence;
1242 std::unique_ptr<SCEVChainRecurrence>
1245 const SCEV & scevTree,
1248 if (
const auto scevConstant =
dynamic_cast<const SCEVConstant *
>(&scevTree))
1253 if (
const auto scevPlaceholder =
dynamic_cast<const SCEVPlaceholder *
>(&scevTree))
1255 if (&scevPlaceholder->GetPrePointer() == &output)
1262 if (
auto storedRec =
Context_->TryGetChrecForOutput(scevPlaceholder->GetPrePointer()))
1270 if (
const auto scevAddExpr =
dynamic_cast<const SCEVAddExpr *
>(&scevTree))
1275 return SCEV::CloneAs<SCEVChainRecurrence>(
1278 if (
const auto scevMulExpr =
dynamic_cast<const SCEVMulExpr *
>(&scevTree))
1283 return SCEV::CloneAs<SCEVChainRecurrence>(
1289 std::unique_ptr<SCEV>
1298 for (
size_t i = 0; i < expression.
NumOperands(); ++i)
1300 std::vector<SCEV *> ops = expression.
GetOperands();
1301 if (
dynamic_cast<const SCEVInit *
>(ops[i]))
1303 for (
size_t j = i + 1; j < expression.
NumOperands(); ++j)
1305 if (
dynamic_cast<const SCEVInit *
>(ops[j]))
1309 std::unique_ptr<SCEV> foldedOperand{};
1320 throw std::logic_error(
"Invalid n-ary SCEV expression type in FoldNAryExpression!");
1338 return expression.
Clone();
1341 std::unique_ptr<SCEV>
1364 if (
const auto *lhsUnknown =
dynamic_cast<const SCEVUnknown *
>(lhsOperand),
1365 *rhsUnknown =
dynamic_cast<const SCEVUnknown *
>(rhsOperand);
1366 lhsUnknown || rhsUnknown)
1374 if (lhsChrec && rhsChrec)
1376 if (&lhsChrec->GetLoop() != &rhsChrec->GetLoop())
1379 lhsChrec->GetLoop(),
1385 const auto lhsSize = lhsChrec->NumOperands();
1386 const auto rhsSize = rhsChrec->NumOperands();
1387 for (
size_t i = 0; i < std::max(lhsSize, rhsSize); ++i)
1392 lhs = lhsChrec->GetOperand(i);
1395 rhs = rhsChrec->GetOperand(i);
1403 if (lhsChrec || rhsChrec)
1405 auto * chrec = lhsChrec ? lhsChrec : rhsChrec;
1406 auto * otherOperand = lhsChrec ? rhsOperand : lhsOperand;
1409 if (
const auto constant =
dynamic_cast<const SCEVConstant *
>(otherOperand))
1413 return chrec->
Clone();
1417 const auto chrecOperands = chrec->GetOperands();
1419 bool isFirst =
true;
1420 for (
const auto operand : chrecOperands)
1430 newChrec->AddOperand(operand->Clone());
1436 const auto lhsNAryMulExpr =
dynamic_cast<const SCEVNAryMulExpr *
>(lhsOperand);
1437 const auto rhsNAryMulExpr =
dynamic_cast<const SCEVNAryMulExpr *
>(rhsOperand);
1439 if (lhsNAryMulExpr && rhsNAryMulExpr)
1445 const auto lhsNAryAddExpr =
dynamic_cast<const SCEVNAryAddExpr *
>(lhsOperand);
1446 const auto rhsNAryAddExpr =
dynamic_cast<const SCEVNAryAddExpr *
>(rhsOperand);
1447 if ((lhsNAryMulExpr && rhsNAryAddExpr) || (rhsNAryMulExpr && lhsNAryAddExpr))
1451 const auto * mulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1452 auto * addExpr = lhsNAryAddExpr ? lhsNAryAddExpr : rhsNAryAddExpr;
1453 auto newAddExpr = SCEV::CloneAs<SCEVNAryExpr>(*addExpr);
1454 newAddExpr->AddOperand(mulExpr->Clone());
1455 return newAddExpr->Clone();
1458 const auto lhsInit =
dynamic_cast<const SCEVInit *
>(lhsOperand);
1459 const auto rhsInit =
dynamic_cast<const SCEVInit *
>(rhsOperand);
1460 if ((lhsNAryMulExpr && rhsInit) || (rhsNAryMulExpr && lhsInit))
1463 const auto * mulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1464 const auto * init = lhsInit ? lhsInit : rhsInit;
1468 const auto lhsConstant =
dynamic_cast<SCEVConstant *
>(lhsOperand);
1469 const auto rhsConstant =
dynamic_cast<SCEVConstant *
>(rhsOperand);
1474 const auto * mulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1475 const auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1479 if (lhsNAryMulExpr || rhsNAryMulExpr)
1482 const auto * mulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1483 return mulExpr->Clone();
1486 if (lhsInit && rhsInit)
1492 if ((lhsInit && rhsNAryAddExpr) || (rhsInit && lhsNAryAddExpr))
1495 const auto * init = lhsInit ? lhsInit : rhsInit;
1496 auto * nAryAddExpr = lhsNAryAddExpr ? lhsNAryAddExpr : rhsNAryAddExpr;
1497 auto newAddExpr = SCEV::CloneAs<SCEVNAryAddExpr>(*nAryAddExpr);
1498 newAddExpr->AddOperand(init->Clone());
1499 return newAddExpr->Clone();
1506 const auto * init = lhsInit ? lhsInit : rhsInit;
1507 const auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1511 if (lhsInit || rhsInit)
1514 const auto * init = lhsInit ? lhsInit : rhsInit;
1515 return init->Clone();
1518 if (lhsNAryAddExpr && rhsNAryAddExpr)
1521 auto lhsNewNAryAddExpr = SCEV::CloneAs<SCEVNAryAddExpr>(*lhsNAryAddExpr);
1522 for (
auto op : rhsNAryAddExpr->GetOperands())
1524 lhsNewNAryAddExpr->AddOperand(op->Clone());
1526 return lhsNewNAryAddExpr;
1533 auto * nAryAddExpr = lhsNAryAddExpr ? lhsNAryAddExpr : rhsNAryAddExpr;
1534 auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1535 auto newNAryAddExpr = SCEV::CloneAs<SCEVNAryAddExpr>(*nAryAddExpr);
1539 bool folded =
false;
1540 for (
size_t i = 0; i < newNAryAddExpr->NumOperands(); ++i)
1542 if (
auto existingConstant =
dynamic_cast<SCEVConstant *
>(newNAryAddExpr->GetOperands()[i]))
1545 auto foldedConstant =
ApplyAddFolding(existingConstant, constant, output);
1546 newNAryAddExpr->ReplaceOperand(i, foldedConstant);
1555 newNAryAddExpr->AddOperand(constant->Clone());
1558 return newNAryAddExpr;
1561 if (lhsNAryAddExpr || rhsNAryAddExpr)
1563 const auto * nAryAddExpr = lhsNAryAddExpr ? lhsNAryAddExpr : rhsNAryAddExpr;
1564 return nAryAddExpr->Clone();
1566 if (lhsConstant && rhsConstant)
1569 const auto lhsValue = lhsConstant->GetValue();
1570 const auto rhsValue = rhsConstant->GetValue();
1575 if (lhsConstant || rhsConstant)
1577 const auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1578 return constant->Clone();
1584 std::unique_ptr<SCEVChainRecurrence>
1594 return SCEV::CloneAs<SCEVChainRecurrence>(*lhsChrec);
1596 return SCEV::CloneAs<SCEVChainRecurrence>(*rhsChrec);
1655 if (rhsSize > lhsSize)
1656 std::swap(lhsChrec, rhsChrec);
1658 std::unique_ptr<SCEVChainRecurrence> lhsStepRecurrence, rhsStepRecurrence;
1660 const auto lhsStep = *lhsChrec->
GetStep();
1664 throw std::logic_error(
"Could not get step for LHS in ComputeProductOfChrecs!");
1667 const auto rhsStep = *rhsChrec->
GetStep();
1670 throw std::logic_error(
"Could not get step for RHS in ComputeProductOfChrecs!");
1674 lhsStepRecurrence = SCEV::CloneAs<SCEVChainRecurrence>(*lhsStep);
1679 rhsStepRecurrence = SCEV::CloneAs<SCEVChainRecurrence>(*rhsStep);
1683 const auto rhsMarked = SCEV::CloneAs<SCEVChainRecurrence>(
1690 SCEV::CloneAs<SCEVChainRecurrence>(*
ApplyAddFolding(res1.get(), res2.get(), output));
1693 resFolded->AddOperandToFront(first);
1698 std::unique_ptr<SCEV>
1708 if (
const auto *lhsUnknown =
dynamic_cast<const SCEVUnknown *
>(lhsOperand),
1709 *rhsUnknown =
dynamic_cast<const SCEVUnknown *
>(rhsOperand);
1710 lhsUnknown || rhsUnknown)
1717 if (lhsChrec && rhsChrec)
1719 if (&lhsChrec->GetLoop() != &rhsChrec->GetLoop())
1722 lhsChrec->GetLoop(),
1732 if (lhsChrec || rhsChrec)
1734 auto * chrec = lhsChrec ? lhsChrec : rhsChrec;
1735 auto * otherOperand = lhsChrec ? rhsOperand : lhsOperand;
1737 if (
auto constant =
dynamic_cast<const SCEVConstant *
>(otherOperand))
1739 if (constant->GetValue() == 1)
1742 return chrec->
Clone();
1745 if (constant->GetValue() == 0)
1752 const auto chrecOperands = chrec->GetOperands();
1754 for (
auto & operand : chrecOperands)
1762 const auto lhsNAryAddExpr =
dynamic_cast<const SCEVNAryAddExpr *
>(lhsOperand);
1763 const auto rhsNAryAddExpr =
dynamic_cast<const SCEVNAryAddExpr *
>(rhsOperand);
1764 if (lhsNAryAddExpr || rhsNAryAddExpr)
1768 const auto nAryAddExpr = lhsNAryAddExpr ? lhsNAryAddExpr : rhsNAryAddExpr;
1769 const auto other = lhsNAryAddExpr ? rhsOperand : lhsOperand;
1772 for (
auto operand : nAryAddExpr->GetOperands())
1775 resultAddExpr->AddOperand(std::move(product));
1777 return resultAddExpr;
1780 const auto lhsInit =
dynamic_cast<const SCEVInit *
>(lhsOperand);
1781 const auto rhsInit =
dynamic_cast<const SCEVInit *
>(rhsOperand);
1782 if (lhsInit && rhsInit)
1788 const auto lhsNAryMulExpr =
dynamic_cast<const SCEVNAryMulExpr *
>(lhsOperand);
1789 const auto rhsNAryMulExpr =
dynamic_cast<const SCEVNAryMulExpr *
>(rhsOperand);
1790 if ((lhsInit && rhsNAryMulExpr) || (rhsInit && lhsNAryMulExpr))
1793 const auto * init = lhsInit ? lhsInit : rhsInit;
1794 auto * nAryMulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1795 auto newNAryMulExpr = SCEV::CloneAs<SCEVNAryMulExpr>(*nAryMulExpr);
1796 newNAryMulExpr->AddOperand(init->Clone());
1797 return newNAryMulExpr->Clone();
1800 auto lhsConstant =
dynamic_cast<SCEVConstant *
>(lhsOperand);
1801 auto rhsConstant =
dynamic_cast<SCEVConstant *
>(rhsOperand);
1802 if ((lhsInit && rhsConstant && rhsConstant->GetValue() != 1)
1803 || (rhsInit && lhsConstant && lhsConstant->GetValue() != 1))
1806 const auto * init = lhsInit ? lhsInit : rhsInit;
1807 const auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1811 if (lhsInit || rhsInit)
1814 const auto * init = lhsInit ? lhsInit : rhsInit;
1815 return init->Clone();
1818 if (lhsNAryMulExpr && rhsNAryMulExpr)
1821 auto lhsNewNAryMulExpr = SCEV::CloneAs<SCEVNAryMulExpr>(*lhsNAryMulExpr);
1822 for (
auto op : rhsNAryMulExpr->GetOperands())
1824 lhsNewNAryMulExpr->AddOperand(op->Clone());
1826 return lhsNewNAryMulExpr;
1829 if ((lhsNAryMulExpr && rhsConstant && rhsConstant->GetValue() != 1)
1830 || (rhsNAryMulExpr && lhsConstant && lhsConstant->GetValue() != 1))
1833 auto * nAryMulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1834 auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1836 auto newNAryMulExpr = SCEV::CloneAs<SCEVNAryMulExpr>(*nAryMulExpr);
1838 bool folded =
false;
1839 for (
size_t i = 0; i < newNAryMulExpr->NumOperands(); ++i)
1841 if (
auto existingConstant =
dynamic_cast<SCEVConstant *
>(newNAryMulExpr->GetOperands()[i]))
1844 auto foldedConstant =
ApplyMulFolding(existingConstant, constant, output);
1845 newNAryMulExpr->ReplaceOperand(i, foldedConstant);
1854 newNAryMulExpr->AddOperand(constant->Clone());
1857 return newNAryMulExpr;
1860 if (lhsNAryMulExpr || rhsNAryMulExpr)
1862 const auto * nAryMulExpr = lhsNAryMulExpr ? lhsNAryMulExpr : rhsNAryMulExpr;
1863 return nAryMulExpr->Clone();
1866 if (lhsConstant && rhsConstant)
1869 const auto lhsValue = lhsConstant->GetValue();
1870 const auto rhsValue = rhsConstant->GetValue();
1874 if (lhsConstant || rhsConstant)
1876 const auto * constant = lhsConstant ? lhsConstant : rhsConstant;
1877 return constant->Clone();
1883 std::unique_ptr<SCEV>
1887 if (
const auto c =
dynamic_cast<const SCEVConstant *
>(&scev))
1889 const auto value = c->GetValue();
1895 if (
const auto c =
dynamic_cast<const SCEVConstant *
>(
mul->GetLeftOperand());
1898 return mul->GetRightOperand()->Clone();
1900 if (
const auto c =
dynamic_cast<const SCEVConstant *
>(
mul->GetRightOperand());
1903 return mul->GetLeftOperand()->Clone();
1919 auto deps = dependencyGraph[&output];
1920 if (deps.find(&output) != deps.end())
1922 if (deps[&output].count != 1)
1936 std::unordered_set<const rvsdg::Output *> visited{};
1937 std::unordered_set<const rvsdg::Output *> recursionStack{};
1946 std::unordered_set<const rvsdg::Output *> & visited,
1947 std::unordered_set<const rvsdg::Output *> & recursionStack)
1949 visited.insert(¤tOutput);
1950 recursionStack.insert(¤tOutput);
1952 for (
const auto & [depPtr, depCount] : dependencyGraph[¤tOutput])
1955 if (depPtr == ¤tOutput)
1960 if (depPtr == &originalOutput)
1964 if (visited.find(depPtr) != visited.end())
1972 recursionStack.erase(¤tOutput);
1988 if (
auto * binaryExpr =
dynamic_cast<const SCEVBinaryExpr *
>(&scev))
1990 return IsUnknown(*binaryExpr->GetLeftOperand()) ||
IsUnknown(*binaryExpr->GetLeftOperand());
1993 if (
auto * nAryExpr =
dynamic_cast<const SCEVNAryExpr *
>(&scev))
1995 for (
const auto operand : nAryExpr->GetOperands())
2003 throw std::logic_error(
"Invalid SCEV type in IsUnknown!\n");
2009 if (
typeid(a) !=
typeid(b))
2015 if (
auto * constantA =
dynamic_cast<const SCEVConstant *
>(&a))
2017 auto * constantB =
dynamic_cast<const SCEVConstant *
>(&b);
2018 return constantA->
GetValue() == constantB->GetValue();
2021 if (
auto * initA =
dynamic_cast<const SCEVInit *
>(&a))
2023 auto * initB =
dynamic_cast<const SCEVInit *
>(&b);
2027 if (
auto * binaryExprA =
dynamic_cast<const SCEVBinaryExpr *
>(&a))
2030 return StructurallyEqual(*binaryExprA->GetLeftOperand(), *binaryExprB->GetLeftOperand())
2031 &&
StructurallyEqual(*binaryExprA->GetRightOperand(), *binaryExprB->GetRightOperand());
2037 if (&chrecA->GetLoop() != &chrecB->GetLoop())
2039 if (&chrecA->GetOutput() != &chrecB->GetOutput())
2041 if (chrecA->NumOperands() != chrecB->NumOperands())
2043 for (
size_t i = 0; i < chrecA->NumOperands(); ++i)
2051 if (
auto * nAryExprA =
dynamic_cast<const SCEVNAryExpr *
>(&a))
2053 auto * nAryExprB =
dynamic_cast<const SCEVNAryExpr *
>(&b);
2054 if (nAryExprA->NumOperands() != nAryExprB->NumOperands())
2056 for (
size_t i = 0; i < nAryExprA->NumOperands(); ++i)
2058 if (!
StructurallyEqual(*nAryExprA->GetOperands()[i], *nAryExprB->GetOperands()[i]))
static jlm::util::StatisticsCollector statisticsCollector
static rvsdg::Input & BarredInput(const rvsdg::SimpleNode &node) noexcept
static std::unique_ptr< SCEVAddExpr > Create(std::unique_ptr< SCEV > left, std::unique_ptr< SCEV > right)
rvsdg::ThetaNode & GetLoop() const noexcept
SCEV * GetStartValue() const
static bool IsQuadratic(const SCEVChainRecurrence &chrec)
static bool IsConstant(const SCEVChainRecurrence &chrec)
std::optional< std::unique_ptr< SCEV > > GetStep() const
static std::unique_ptr< SCEVChainRecurrence > Create(rvsdg::ThetaNode &loop, rvsdg::Output &output)
static bool IsAffine(const SCEVChainRecurrence &chrec)
static bool IsNonZero(const SCEVConstant *c)
static std::unique_ptr< SCEVConstant > Create(const int64_t value)
rvsdg::Output & GetPrePointer() const noexcept
static std::unique_ptr< SCEVInit > Create(rvsdg::Output &prePointer)
static std::unique_ptr< SCEVMulExpr > Create(std::unique_ptr< SCEV > left, std::unique_ptr< SCEV > right)
static std::unique_ptr< SCEVNAryAddExpr > Create(Args &&... operands)
SCEV * GetOperand(const size_t index) const
size_t NumOperands() const
void RemoveOperand(const size_t index)
std::vector< SCEV * > GetOperands() const
void ReplaceOperand(const size_t index, const std::unique_ptr< SCEV > &operand)
static std::unique_ptr< SCEVNAryMulExpr > Create(Args &&... operands)
static std::unique_ptr< SCEVPlaceholder > Create(rvsdg::Output &PrePointer_)
static std::unique_ptr< SCEVUnknown > Create()
virtual std::unique_ptr< SCEV > Clone() const =0
size_t GetTripCount(const rvsdg::ThetaNode &thetaNode) const
std::unordered_map< const rvsdg::ThetaNode *, size_t > TripCountMap_
const std::unordered_map< rvsdg::Output *, std::unique_ptr< SCEVChainRecurrence > > & GetChrecMap() const noexcept
size_t GetNumLoops() const
size_t GetNumTotalLoopVars() const
const std::unordered_map< rvsdg::Output *, std::unique_ptr< SCEV > > & GetSCEVMap() const noexcept
std::unique_ptr< SCEVChainRecurrence > TryGetChrecForOutput(rvsdg::Output &output) const
std::unordered_set< const rvsdg::Output * > LoopVars_
Context & operator=(const Context &)=delete
const std::unordered_map< const rvsdg::ThetaNode *, size_t > & GetTripCountMap() const noexcept
void SetTripCount(const rvsdg::ThetaNode &thetaNode, const size_t tripCount)
void InsertSCEV(rvsdg::Output &output, const std::unique_ptr< SCEV > &scev)
std::unordered_map< rvsdg::Output *, std::unique_ptr< SCEVChainRecurrence > > ChrecMap_
Context(const Context &)=delete
void AddLoopVar(const rvsdg::Output &var)
std::unordered_map< rvsdg::Output *, std::unique_ptr< SCEV > > SCEVMap_
size_t GetNumTotalInductionVariables() const
Context(Context &&)=delete
Context & operator=(Context &&)=delete
std::unique_ptr< SCEV > TryGetSCEVForOutput(rvsdg::Output &output) const
static std::unique_ptr< Context > Create()
void InsertChrec(rvsdg::Output &output, const std::unique_ptr< SCEVChainRecurrence > &chrec)
int GetNumInductionVariablesWithOrder(const size_t n) const
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
~Statistics() noexcept override=default
static std::string GetTripCountString(const std::unordered_map< const rvsdg::ThetaNode *, size_t > &tripCountMap)
void Stop(const Context &context) noexcept
std::unordered_map< rvsdg::Output *, DependencyInfo > DependencyMap
std::unordered_map< rvsdg::Output *, DependencyMap > DependencyGraph
static std::unique_ptr< SCEVChainRecurrence > ComputeProductOfChrecs(SCEVChainRecurrence *lhsChrec, SCEVChainRecurrence *rhsChrec, rvsdg::Output &output)
std::optional< std::unique_ptr< SCEV > > TryReplaceInitForSCEV(const SCEV &scev, rvsdg::Output &output)
std::unique_ptr< SCEVChainRecurrence > GetOrCreateStepForSCEV(rvsdg::Output &output, const SCEV &scevTree, rvsdg::ThetaNode &thetaNode)
void PerformSCEVAnalysis(rvsdg::ThetaNode &thetaNode)
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static void FindDependenciesForSCEV(const SCEV &scev, DependencyMap &dependencies, DependencyOp op)
static bool IsStepZero(const SCEV &stepSCEV)
static std::unique_ptr< SCEV > ApplyMulFolding(SCEV *lhsOperand, SCEV *rhsOperand, rvsdg::Output &output)
Apply folding rules for multiplication to combine two SCEV operands into one.
static std::unique_ptr< SCEV > FoldNAryExpression(SCEVNAryExpr &expression, rvsdg::Output &output)
Try to combine the constants in an n-ary expression (Add or Mul) into themselves.
static std::optional< size_t > SolveQuadraticEquation(int64_t a, int64_t b, int64_t c)
Tries to find a solution to the quadratic equation a^2 x + b x + c = 0 using integer arithmetic.
DependencyGraph CreateDependencyGraph(const rvsdg::ThetaNode &thetaNode) const
static std::unique_ptr< SCEV > ApplyAddFolding(SCEV *lhsOperand, SCEV *rhsOperand, rvsdg::Output &output)
Apply folding rules for addition to combine two SCEV operands into one.
static bool HasCycleThroughOthers(rvsdg::Output ¤tOutput, const rvsdg::Output &originalOutput, DependencyGraph &dependencyGraph, std::unordered_set< const rvsdg::Output * > &visited, std::unordered_set< const rvsdg::Output * > &recursionStack)
~ScalarEvolution() noexcept override
std::unique_ptr< Context > Context_
static bool IsStepPositive(const SCEV &stepSCEV)
void CombineChrecsAcrossLoops()
static bool CanCreateChainRecurrence(rvsdg::Output &output, DependencyGraph &dependencyGraph)
std::unique_ptr< SCEV > ComputeSCEVForGepInnerOffset(const rvsdg::SimpleNode &gepNode, size_t inputIndex, const rvsdg::Type &type)
std::optional< size_t > GetPredictedTripCount(rvsdg::ThetaNode &thetaNode)
static bool StructurallyEqual(const SCEV &a, const SCEV &b)
static bool IsUnknown(const SCEV &scev)
std::unordered_map< const rvsdg::Output *, std::unique_ptr< SCEV > > GetSCEVMap() const
static bool IsStepNegative(const SCEV &stepSCEV)
static std::vector< rvsdg::Output * > TopologicalSort(DependencyGraph &dependencyGraph)
std::unique_ptr< SCEV > GetOrCreateSCEVForOutput(rvsdg::Output &output)
std::unique_ptr< SCEVChainRecurrence > GetOrCreateChainRecurrence(rvsdg::Output &output, const SCEV &scev, rvsdg::ThetaNode &thetaNode)
std::unordered_map< const rvsdg::ThetaNode *, size_t > GetTripCountMap() const noexcept
static std::unique_ptr< SCEV > GetNegativeSCEV(const SCEV &scev)
void AnalyzeRegion(rvsdg::Region ®ion)
static std::optional< size_t > ComputeBackedgeTakenCountForChrec(const SCEVChainRecurrence &chrec, int64_t bound, const rvsdg::SimpleOperation *comparisonOperation)
Region & GetRootRegion() const noexcept
size_t ninputs() const noexcept
Represent acyclic RVSDG subgraphs.
NodeRange Nodes() noexcept
const std::optional< util::FilePath > & SourceFilePath() const noexcept
NodeInput * input(size_t index) const noexcept
RegionResult * predicate() const noexcept
LoopVar MapPreLoopVar(const rvsdg::Output &argument) const
Maps variable at start of loop iteration to full varibale description.
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
bool insert(ItemType item)
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
util::Timer & GetTimer(const std::string &name)
util::Timer & AddTimer(std::string name)
void AddMeasurement(std::string name, T value)
Global memory state passed between functions.
size_t GetTypeAllocSize(const rvsdg::Type &type)
std::optional< int64_t > tryGetConstantSignedInteger(const rvsdg::Output &output)
static bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
Output & traceOutput(Output &output, const rvsdg::Region *withinRegion)
@ State
Designate a state type.
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
rvsdg::Input * input
Variable at loop entry (input to theta).
rvsdg::Input * post
Variable after iteration (output result from subregion).
static const char * TripCounts
static const char * NumFirstOrderInductionVariables
static const char * NumConstantInductionVariables
static const char * NumTotalInductionVariables
static const char * Timer
static const char * NumSecondOrderInductionVariables
static const char * NumLoopVariablesTotal
static const char * NumLoops