//===---- Delinearization.cpp - MultiDimensional Index Delinearization ----===// // // 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 implements an analysis pass that tries to delinearize all GEP // instructions in all loops using the SCEV analysis functionality. This pass is // only used for testing purposes: if your pass needs delinearization, please // use the on-demand SCEVAddRecExpr::delinearize() function. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/Delinearization.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DL_NAME "delinearize" #define DEBUG_TYPE DL_NAME namespace { class Delinearization : public FunctionPass { Delinearization(const Delinearization &); // do not implement protected: Function *F; LoopInfo *LI; ScalarEvolution *SE; public: static char ID; // Pass identification, replacement for typeid Delinearization() : FunctionPass(ID) { initializeDelinearizationPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override; void print(raw_ostream &O, const Module *M = nullptr) const override; }; void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI, ScalarEvolution *SE) { O << "Delinearization on function " << F->getName() << ":\n"; for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { Instruction *Inst = &(*I); // Only analyze loads and stores. if (!isa(Inst) && !isa(Inst) && !isa(Inst)) continue; const BasicBlock *BB = Inst->getParent(); // Delinearize the memory access as analyzed in all the surrounding loops. // Do not analyze memory accesses outside loops. for (Loop *L = LI->getLoopFor(BB); L != nullptr; L = L->getParentLoop()) { const SCEV *AccessFn = SE->getSCEVAtScope(getPointerOperand(Inst), L); const SCEVUnknown *BasePointer = dyn_cast(SE->getPointerBase(AccessFn)); // Do not delinearize if we cannot find the base pointer. if (!BasePointer) break; AccessFn = SE->getMinusSCEV(AccessFn, BasePointer); O << "\n"; O << "Inst:" << *Inst << "\n"; O << "In Loop with Header: " << L->getHeader()->getName() << "\n"; O << "AccessFunction: " << *AccessFn << "\n"; SmallVector Subscripts, Sizes; SE->delinearize(AccessFn, Subscripts, Sizes, SE->getElementSize(Inst)); if (Subscripts.size() == 0 || Sizes.size() == 0 || Subscripts.size() != Sizes.size()) { O << "failed to delinearize\n"; continue; } O << "Base offset: " << *BasePointer << "\n"; O << "ArrayDecl[UnknownSize]"; int Size = Subscripts.size(); for (int i = 0; i < Size - 1; i++) O << "[" << *Sizes[i] << "]"; O << " with elements of " << *Sizes[Size - 1] << " bytes.\n"; O << "ArrayRef"; for (int i = 0; i < Size; i++) O << "[" << *Subscripts[i] << "]"; O << "\n"; } } } } // end anonymous namespace void Delinearization::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); AU.addRequired(); } bool Delinearization::runOnFunction(Function &F) { this->F = &F; SE = &getAnalysis().getSE(); LI = &getAnalysis().getLoopInfo(); return false; } void Delinearization::print(raw_ostream &O, const Module *) const { printDelinearization(O, F, LI, SE); } char Delinearization::ID = 0; static const char delinearization_name[] = "Delinearization"; INITIALIZE_PASS_BEGIN(Delinearization, DL_NAME, delinearization_name, true, true) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(Delinearization, DL_NAME, delinearization_name, true, true) FunctionPass *llvm::createDelinearizationPass() { return new Delinearization; } DelinearizationPrinterPass::DelinearizationPrinterPass(raw_ostream &OS) : OS(OS) {} PreservedAnalyses DelinearizationPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { printDelinearization(OS, &F, &AM.getResult(F), &AM.getResult(F)); return PreservedAnalyses::all(); }