[llvm] Introduce PrecomputLoopExpressionsPass. (PR #90263)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 26 13:08:13 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Huihui Zhang (huihzhang)
<details>
<summary>Changes</summary>
This patch is not for review, but to share the optimization to community.
---
Patch is 35.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/90263.diff
4 Files Affected:
- (added) llvm/include/llvm/Transforms/Scalar/PrecomputeLoopExpressions.h (+27)
- (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+7)
- (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
- (added) llvm/lib/Transforms/Scalar/PrecomputeLoop.cpp (+1107)
``````````diff
diff --git a/llvm/include/llvm/Transforms/Scalar/PrecomputeLoopExpressions.h b/llvm/include/llvm/Transforms/Scalar/PrecomputeLoopExpressions.h
new file mode 100644
index 00000000000000..42eea0a8d53e59
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/PrecomputeLoopExpressions.h
@@ -0,0 +1,27 @@
+//===-------------------- PrecomputeLoopExpressions.h ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_PRECOMPUTE_LOOP_EXPRESSIONS_H
+#define LLVM_TRANSFORMS_SCALAR_PRECOMPUTE_LOOP_EXPRESSIONS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class PrecomputeLoopExpressionsPass
+ : public PassInfoMixin<PrecomputeLoopExpressionsPass> {
+ unsigned TotalInitSize;
+
+public:
+ PrecomputeLoopExpressionsPass(unsigned TotalInitSize = 0)
+ : TotalInitSize(TotalInitSize) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_PRECOMPUTE_LOOP_EXPRESSIONS_H
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 90ba3b541553e2..36351e0f510220 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -115,6 +115,7 @@
#include "llvm/Transforms/Scalar/MemCpyOptimizer.h"
#include "llvm/Transforms/Scalar/MergedLoadStoreMotion.h"
#include "llvm/Transforms/Scalar/NewGVN.h"
+#include "llvm/Transforms/Scalar/PrecomputeLoopExpressions.h"
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/SCCP.h"
#include "llvm/Transforms/Scalar/SROA.h"
@@ -302,6 +303,8 @@ namespace llvm {
extern cl::opt<bool> EnableMemProfContextDisambiguation;
extern cl::opt<bool> EnableInferAlignmentPass;
+
+extern cl::opt<bool> DisablePCLE;
} // namespace llvm
PipelineTuningOptions::PipelineTuningOptions() {
@@ -681,6 +684,10 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM1),
/*UseMemorySSA=*/true,
/*UseBlockFrequencyInfo=*/true));
+
+ if (!DisablePCLE)
+ FPM.addPass(PrecomputeLoopExpressionsPass());
+
FPM.addPass(
SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true)));
FPM.addPass(InstCombinePass());
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index ba09ebf8b04c4c..8b5bd39d1242d0 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -61,6 +61,7 @@ add_llvm_component_library(LLVMScalarOpts
NewGVN.cpp
PartiallyInlineLibCalls.cpp
PlaceSafepoints.cpp
+ PrecomputeLoop.cpp
Reassociate.cpp
Reg2Mem.cpp
RewriteStatepointsForGC.cpp
diff --git a/llvm/lib/Transforms/Scalar/PrecomputeLoop.cpp b/llvm/lib/Transforms/Scalar/PrecomputeLoop.cpp
new file mode 100644
index 00000000000000..3af149db11b28c
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/PrecomputeLoop.cpp
@@ -0,0 +1,1107 @@
+//===-------- PrecomputeLoop.cpp - Precompute expressions in a loop -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass detects and evaluates expressions based on loop induction
+// variables. Loops and induction variables will need to have compile-time known
+// trip count and increments. Then this pass will determine if the detected
+// expressions can benefit from being replaced with loads to precomputed table.
+// The precomputed table is initialized with values computed based on
+// expressions and iteration space.
+//
+// For example:
+// int N = 36, sum;
+// for (int p=0; p<N; p++){
+// sum = 0;
+// for (int m=0; m < N/2; m++)
+// sum += cos_table[((2*p+1+N/2)*(2*m+1))%144];
+// out[p] = sum;
+// }
+//
+// Expression "(...*(2*m+1))%144" is detected and to be replaced with a single
+// load to precomputed table.
+// The precomputed table is created as a ConstantArray of size
+// [36 x [18 x i32]], and use the expression and iteration space to initialize.
+// E.g., array element at (p=0,m=2) is 95.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/PrecomputeLoopExpressions.h"
+
+#include <atomic>
+#include <deque>
+#include <map>
+#include <set>
+#include <vector>
+
+#define DEBUG_TYPE "pcle"
+
+using namespace llvm;
+
+static cl::opt<unsigned> MinCostThreshold("pcle-min-cost", cl::Hidden,
+ cl::init(8));
+
+static const int kByte = 1024;
+static const int MByte = 1024 * 1024;
+
+static cl::opt<unsigned> MaxSizeThreshold("pcle-max-size", cl::Hidden,
+ cl::init(512 * kByte));
+
+static cl::opt<unsigned> MaxTotalSizeThreshold("pcle-max-total-size",
+ cl::Hidden, cl::init(2 * MByte));
+
+namespace llvm {
+cl::opt<bool> DisablePCLE("disable-pcle", cl::Hidden, cl::init(false),
+ cl::desc("Disable Precomputing Loop Expressions"));
+}
+
+namespace {
+typedef int32_t Integer;
+#define BitSize(T) (8 * sizeof(T))
+
+struct IVInfo {
+ IVInfo() : L(0) {}
+ IVInfo(Loop *Lp) : L(Lp) {}
+ Integer Start, End, Bump;
+ Loop *L;
+
+ bool EqualIterSpace(const IVInfo &I) const {
+ return Start == I.Start && End == I.End && Bump == I.Bump;
+ }
+};
+#ifndef NDEBUG
+raw_ostream &operator<<(raw_ostream &OS, const IVInfo &II) {
+ if (II.L)
+ OS << "Loop header: " << II.L->getHeader()->getName();
+ else
+ OS << "No loop";
+ OS << " Start:" << II.Start << " End:" << II.End << " Bump:" << II.Bump;
+ return OS;
+}
+#endif
+
+typedef std::vector<Value *> ValueVect;
+typedef std::map<Value *, IVInfo> IVInfoMap;
+
+#ifndef NDEBUG
+raw_ostream &operator<<(raw_ostream &OS, const IVInfoMap &M) {
+ for (auto &I : M)
+ OS << I.first->getName() << " -> " << I.second << '\n';
+ return OS;
+}
+#endif
+
+class InitDescKey {
+public:
+ ArrayType *ATy;
+ ValueVect IVs;
+
+ InitDescKey() : ATy(0), IVs(), IVInfos(0) {}
+ InitDescKey(ArrayType *T, ValueVect &Vs, IVInfoMap &IVM)
+ : ATy(T), IVs(Vs), IVInfos(&IVM) {}
+
+ bool operator==(const InitDescKey &K) const {
+ if (ATy != K.ATy)
+ return false;
+
+ unsigned Dims = IVs.size();
+ if (Dims != K.IVs.size())
+ return false;
+
+ for (unsigned i = 0; i < Dims; ++i) {
+ IVInfo &I = (*IVInfos)[IVs[i]];
+ IVInfo &KI = (*K.IVInfos)[K.IVs[i]];
+ if (!I.EqualIterSpace(KI))
+ return false;
+ }
+ return true;
+ }
+ bool operator<(const InitDescKey &K) const {
+ unsigned Dims = IVs.size();
+ if (Dims != K.IVs.size())
+ return Dims < K.IVs.size();
+ // Dims are equal here.
+ if (ATy != K.ATy)
+ return uintptr_t(ATy) < uintptr_t(K.ATy);
+ // Types are the same.
+ for (unsigned i = 0; i < Dims; ++i) {
+ IVInfo &I = (*IVInfos)[IVs[i]];
+ IVInfo &KI = (*K.IVInfos)[K.IVs[i]];
+ if (I.Start != KI.Start)
+ return I.Start < KI.Start;
+ if (I.End != KI.End)
+ return I.End < KI.End;
+ if (I.Bump != KI.Bump)
+ return I.Bump < KI.Bump;
+ }
+ return false;
+ }
+
+private:
+ IVInfoMap *IVInfos;
+};
+
+class InitDescVal {
+public:
+ Value *Ex;
+ GlobalVariable *GV;
+ Constant *Init;
+ unsigned Seq;
+
+ InitDescVal() : Ex(0), GV(0), Init(0), Seq(0) {}
+ InitDescVal(Value *E, GlobalVariable *G, Constant *I)
+ : Ex(E), GV(G), Init(I), Seq(std::atomic_fetch_add(&SeqCounter, 1U)) {}
+
+ static std::atomic<unsigned> SeqCounter;
+};
+
+typedef std::vector<Integer> IntVect;
+typedef std::deque<Value *> ValueQueue;
+typedef std::set<Value *> ValueSet;
+typedef std::pair<GlobalVariable *, Value *> AdjustedInit;
+typedef std::multimap<InitDescKey, InitDescVal> InitializerCache;
+
+struct OrderMap {
+ OrderMap() {}
+ typedef std::map<Instruction *, unsigned> MapType;
+ MapType::mapped_type operator[](Instruction *In) {
+ if (Map.find(In) == Map.end())
+ recalculate(*In->getParent()->getParent());
+ assert(Map.find(In) != Map.end());
+ return Map[In];
+ }
+
+ void recalculate(Function &F);
+ MapType Map;
+};
+
+void OrderMap::recalculate(Function &F) {
+ Map.clear();
+ unsigned Ord = 0;
+ for (auto &B : F)
+ for (auto &I : B)
+ Map.insert(std::make_pair(&I, ++Ord));
+}
+
+#ifndef NDEBUG
+raw_ostream &operator<<(raw_ostream &OS, const ValueSet &S) {
+ OS << '{';
+ for (auto &I : S)
+ OS << ' ' << *I;
+ OS << " }";
+ return OS;
+}
+#endif
+
+class PrecomputeLoopExpressions {
+public:
+ PrecomputeLoopExpressions(DominatorTree *DT, LoopInfo *LI,
+ ScalarEvolution *SE, TargetLibraryInfo *TLI,
+ unsigned TotalInitSize)
+ : DT(DT), LI(LI), SE(SE), TLI(TLI), TotalInitSize(TotalInitSize) {};
+
+ bool run(Function &Fn);
+
+private:
+ bool isLoopValid(Loop *L);
+ bool processLatchForIV(Instruction *TrIn, Value *&IV, IVInfo &IVI);
+ bool processPHIForIV(Instruction *PIn, Value *IV, IVInfo &IVI);
+ void collectInductionVariables();
+
+ bool isAllowedOpcode(unsigned Opc);
+ bool verifyExpressionNode(Value *Ex, ValueSet &Valid);
+ bool verifyExpression(Value *Ex, ValueSet &Valid);
+ void extendExpression(Value *Ex, ValueSet &Valid, ValueSet &New);
+ unsigned computeInitializerSize(Value *V);
+ unsigned computeExpressionCost(Value *V, ValueSet &Vs);
+ void collectCandidateExpressions();
+
+ void extractInductionVariables(Value *Ex, ValueVect &IVs);
+ ArrayType *createTypeForArray(Type *ETy, ValueVect &IVs);
+ Integer evaluateExpression(Value *Ex, ValueVect &IVs, IntVect &C);
+ Constant *createInitializerForSlice(Value *Ex, unsigned Dim, ArrayType *ATy,
+ ValueVect &IVs, bool Zero, IntVect &C,
+ IntVect &Starts, IntVect &Ends,
+ IntVect &Bumps);
+ Constant *createInitializerForArray(Value *Ex, ArrayType *ATy,
+ ValueVect &IVs);
+ AdjustedInit getInitializerForArray(Value *Ex, ArrayType *ATy,
+ ValueVect &IVs);
+ Value *computeDifference(Value *A, Value *B);
+ bool rewriteExpression(Value *Ex, Value *Adj, ArrayType *ATy, ValueVect &IVs,
+ GlobalVariable *GV);
+ bool processCandidateExpressions();
+
+ Function *F;
+ DominatorTree *DT;
+ LoopInfo *LI;
+ ScalarEvolution *SE;
+ TargetLibraryInfo *TLI;
+ OrderMap Order;
+
+ IVInfoMap IVInfos;
+ ValueSet IVEs;
+ InitializerCache InitCache;
+ unsigned TotalInitSize;
+
+ static std::atomic<unsigned> Counter;
+};
+} // namespace
+
+std::atomic<unsigned> InitDescVal::SeqCounter(0);
+std::atomic<unsigned> PrecomputeLoopExpressions::Counter(0);
+
+static unsigned Log2p(unsigned A) {
+ if (A == 0)
+ return 1;
+
+ unsigned L = 1;
+ while (A >>= 1)
+ L++;
+
+ return L;
+}
+
+bool PrecomputeLoopExpressions::isLoopValid(Loop *L) {
+ BasicBlock *H = L->getHeader();
+ if (!H)
+ return false;
+ BasicBlock *PH = L->getLoopPreheader();
+ if (!PH)
+ return false;
+ BasicBlock *EB = L->getExitingBlock();
+ if (!EB)
+ return false;
+
+ if (std::distance(pred_begin(H), pred_end(H)) != 2)
+ return false;
+
+ unsigned TC = SE->getSmallConstantTripCount(L, EB);
+ if (TC == 0)
+ return false;
+
+ return true;
+}
+
+bool PrecomputeLoopExpressions::processLatchForIV(Instruction *TrIn, Value *&IV,
+ IVInfo &IVI) {
+ // Need a conditional branch.
+ BranchInst *Br = dyn_cast<BranchInst>(TrIn);
+ if (!Br || !Br->isConditional())
+ return false;
+
+ // The branch condition needs to be an integer compare.
+ Value *CV = Br->getCondition();
+ Instruction *CIn = dyn_cast<Instruction>(CV);
+ if (!CIn || CIn->getOpcode() != Instruction::ICmp)
+ return false;
+
+ // The comparison has to be less-than.
+ ICmpInst *ICIn = cast<ICmpInst>(CIn);
+ CmpInst::Predicate P = ICIn->getPredicate();
+ if (P != CmpInst::ICMP_ULT && P != CmpInst::ICMP_SLT)
+ return false;
+
+ // Less-than a constant int to be exact.
+ Value *CR = ICIn->getOperand(1);
+ if (!isa<ConstantInt>(CR))
+ return false;
+
+ // The int has to fit in 32 bits.
+ const APInt &U = cast<ConstantInt>(CR)->getValue();
+ if (!U.isSignedIntN(BitSize(Integer)))
+ return false;
+
+ // The value that is less-than the int needs to be an add.
+ Value *VC = ICIn->getOperand(0);
+ Instruction *VCIn = dyn_cast<Instruction>(VC);
+ if (!VCIn || VCIn->getOpcode() != Instruction::Add)
+ return false;
+
+ // An add of a constant int.
+ Value *ValA, *ValI;
+ if (isa<ConstantInt>(VCIn->getOperand(1))) {
+ ValA = VCIn->getOperand(0);
+ ValI = VCIn->getOperand(1);
+ } else {
+ ValA = VCIn->getOperand(1);
+ ValI = VCIn->getOperand(0);
+ }
+ if (!isa<ConstantInt>(ValI))
+ return false;
+
+ // The added int has to fit in 32 bits.
+ const APInt &B = cast<ConstantInt>(ValI)->getValue();
+ if (!B.isSignedIntN(BitSize(Integer)))
+ return false;
+
+ // Done...
+ IV = ValA;
+ IVI.End = (Integer)U.getSExtValue();
+ IVI.Bump = (Integer)B.getSExtValue();
+ return true;
+}
+
+bool PrecomputeLoopExpressions::processPHIForIV(Instruction *PIn, Value *IV,
+ IVInfo &IVI) {
+ if (IV != PIn)
+ return false;
+
+ // The PHI must only have two incoming blocks.
+ PHINode *P = cast<PHINode>(PIn);
+ if (P->getNumIncomingValues() != 2)
+ return false;
+
+ // The blocks have to be preheader and loop latch.
+ BasicBlock *PH = IVI.L->getLoopPreheader();
+ BasicBlock *LT = IVI.L->getLoopLatch();
+
+ if (P->getIncomingBlock(0) == PH) {
+ if (P->getIncomingBlock(1) != LT)
+ return false;
+ } else if (P->getIncomingBlock(1) == PH) {
+ if (P->getIncomingBlock(0) != LT)
+ return false;
+ } else {
+ return false;
+ }
+
+ // The value coming from the preheader needs to be a constant int.
+ Value *VPH = P->getIncomingValueForBlock(PH);
+ if (!isa<ConstantInt>(VPH))
+ return false;
+
+ // That int has to fit in 32 bits.
+ const APInt &S = cast<ConstantInt>(VPH)->getValue();
+ if (!S.isSignedIntN(BitSize(Integer)))
+ return false;
+
+ // All checks passed.
+ IVI.Start = static_cast<Integer>(S.getSExtValue());
+ return true;
+}
+
+void PrecomputeLoopExpressions::collectInductionVariables() {
+ IVInfos.clear();
+
+ typedef std::deque<Loop *> LoopQueue;
+ LoopQueue Work;
+
+ for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I) {
+ Work.push_back(*I);
+ }
+
+ while (!Work.empty()) {
+ Loop *L = Work.front();
+ Work.pop_front();
+
+ for (Loop::iterator I = L->begin(), E = L->end(); I != E; ++I) {
+ Work.push_back(*I);
+ }
+ if (!isLoopValid(L))
+ continue;
+
+ Value *IV;
+ IVInfo IVI(L);
+ Instruction *TrIn = L->getLoopLatch()->getTerminator();
+
+ bool LatchOk = processLatchForIV(TrIn, IV, IVI);
+ if (!LatchOk)
+ continue;
+
+ BasicBlock *H = L->getHeader();
+ for (BasicBlock::iterator PI = H->begin(); isa<PHINode>(PI); ++PI) {
+ Instruction *I = &*PI;
+ if (I == IV) {
+ bool PHIOk = processPHIForIV(I, IV, IVI);
+ if (PHIOk) {
+ IVInfos.insert(std::make_pair(IV, IVI));
+ }
+ break;
+ }
+ }
+ }
+}
+
+bool PrecomputeLoopExpressions::isAllowedOpcode(unsigned Opc) {
+ switch (Opc) {
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::Shl:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ return true;
+ }
+ return false;
+}
+
+bool PrecomputeLoopExpressions::verifyExpressionNode(Value *Ex,
+ ValueSet &Valid) {
+ Type *T = Ex->getType();
+ if (!T->isIntegerTy())
+ return false;
+ if (cast<IntegerType>(T)->getBitWidth() > BitSize(Integer))
+ return false;
+
+ Instruction *In = dyn_cast<Instruction>(Ex);
+ if (!In)
+ return false;
+ if (!isAllowedOpcode(In->getOpcode()))
+ return false;
+
+ return true;
+}
+
+bool PrecomputeLoopExpressions::verifyExpression(Value *Ex, ValueSet &Valid) {
+ if (Valid.count(Ex))
+ return true;
+ if (isa<ConstantInt>(Ex))
+ return true;
+
+ if (!verifyExpressionNode(Ex, Valid))
+ return false;
+
+ assert(isa<Instruction>(Ex) && "Should have checked for instruction");
+ Instruction *In = cast<Instruction>(Ex);
+ for (unsigned i = 0, n = In->getNumOperands(); i < n; ++i) {
+ bool ValidOp = verifyExpression(In->getOperand(i), Valid);
+ if (!ValidOp)
+ return false;
+ }
+ return true;
+}
+
+void PrecomputeLoopExpressions::extendExpression(Value *Ex, ValueSet &Valid,
+ ValueSet &New) {
+ for (Value::user_iterator I = Ex->user_begin(), E = Ex->user_end(); I != E;
+ ++I) {
+ Value *U = *I;
+ if (Valid.count(U))
+ continue;
+ if (U->getType()->isVoidTy())
+ continue;
+
+ bool BadUser = false;
+
+ if (Instruction *In = dyn_cast<Instruction>(U)) {
+ if (In->getOpcode() == Instruction::PHI)
+ continue;
+ if (!verifyExpressionNode(U, Valid))
+ continue;
+
+ for (unsigned i = 0, n = In->getNumOperands(); i < n; ++i) {
+ Value *Op = In->getOperand(i);
+ if (Op != Ex && !verifyExpression(Op, Valid)) {
+ BadUser = true;
+ break;
+ }
+ }
+ } else {
+ BadUser = true;
+ }
+ if (BadUser)
+ continue;
+
+ New.insert(U);
+ }
+}
+
+unsigned PrecomputeLoopExpressions::computeExpressionCost(Value *V,
+ ValueSet &Vs) {
+ if (Vs.count(V))
+ return 0;
+ Vs.insert(V);
+
+ unsigned C = 0;
+ if (Instruction *In = dyn_cast<Instruction>(V)) {
+ switch (In->getOpcode()) {
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Shl:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ C = 1;
+ break;
+ case Instruction::Mul:
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ C = 3;
+ break;
+ case Instruction::PHI:
+ return 0;
+ }
+
+ for (unsigned i = 0, n = In->getNumOperands(); i < n; ++i) {
+ C += computeExpressionCost(In->getOperand(i), Vs);
+ }
+ }
+
+ return C;
+}
+
+unsigned PrecomputeLoopExpressions::computeInitializerSize(Value *V) {
+ ValueVect IVs;
+
+ extractInductionVariables(V, IVs);
+
+ Type *T = V->getType();
+ assert(T->isIntegerTy());
+ unsigned Total = (cast<IntegerType>(T)->getBitWidth()) / 8;
+
+ for (unsigned i = 0, Dims = IVs.size(); i < Dims; ++i) {
+ IVInfo &IVI = IVInfos[IVs[i]];
+ unsigned D = std::abs(IVI.End - IVI.Start);
+ if (Log2p(D) + Log2p(Total) > 8 * sizeof(Integer))
+ return UINT_MAX;
+ Total *= D;
+ }
+
+ return Total;
+}
+
+void PrecomputeLoopExpressions::collectCandidateExpressions() {
+ ValueQueue Work;
+
+ IVEs.clear();
+
+ for (auto &KV : IVInfos) {
+ IVE...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/90263
More information about the llvm-commits
mailing list