Index: polly/trunk/include/polly/CodeGen/BlockGenerators.h =================================================================== --- polly/trunk/include/polly/CodeGen/BlockGenerators.h +++ polly/trunk/include/polly/CodeGen/BlockGenerators.h @@ -483,9 +483,8 @@ /// @param NewAccesses A map from memory access ids to new ast expressions, /// which may contain new access expressions for certain /// memory accesses. - Value *generateLocationAccessed(ScopStmt &Stmt, const Instruction *Inst, - Value *Pointer, ValueMapT &BBMap, - LoopToScevMapT <S, + Value *generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst, + ValueMapT &BBMap, LoopToScevMapT <S, isl_id_to_ast_expr *NewAccesses); /// @param NewAccesses A map from memory access ids to new ast expressions, Index: polly/trunk/include/polly/ScopDetection.h =================================================================== --- polly/trunk/include/polly/ScopDetection.h +++ polly/trunk/include/polly/ScopDetection.h @@ -357,7 +357,7 @@ /// @param Context The context of scop detection. /// /// @return True if the memory access is valid, false otherwise. - bool isValidMemoryAccess(Instruction &Inst, DetectionContext &Context) const; + bool isValidMemoryAccess(MemAccInst Inst, DetectionContext &Context) const; /// @brief Check if an instruction has any non trivial scalar dependencies /// as part of a Scop. Index: polly/trunk/include/polly/ScopInfo.h =================================================================== --- polly/trunk/include/polly/ScopInfo.h +++ polly/trunk/include/polly/ScopInfo.h @@ -65,6 +65,8 @@ class ScopStmt; class ScopInfo; +typedef DenseMap OutgoingValueMapTy; + //===---------------------------------------------------------------------===// /// @brief Enumeration of assumptions Polly can take. @@ -1894,7 +1896,7 @@ /// @param R The region on which to build the data access dictionary. /// @param BoxedLoops The set of loops that are overapproximated in @p R. /// @param ScopRIL The required invariant loads equivalence classes. - void buildMemoryAccess(Instruction *Inst, Loop *L, Region *R, + void buildMemoryAccess(MemAccInst Inst, Loop *L, Region *R, const ScopDetection::BoxedLoopsSetTy *BoxedLoops, const InvariantLoadsSetTy &ScopRIL); @@ -1977,7 +1979,7 @@ /// @param Sizes The array dimension's sizes. /// @param AccessValue Value read or written. /// @see ScopArrayInfo::MemoryKind - void addArrayAccess(Instruction *MemAccInst, MemoryAccess::AccessType Type, + void addArrayAccess(MemAccInst MemAccInst, MemoryAccess::AccessType Type, Value *BaseAddress, unsigned ElemBytes, bool IsAffine, ArrayRef Subscripts, ArrayRef Sizes, Value *AccessValue); Index: polly/trunk/include/polly/Support/ScopHelper.h =================================================================== --- polly/trunk/include/polly/Support/ScopHelper.h +++ polly/trunk/include/polly/Support/ScopHelper.h @@ -16,27 +16,17 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" namespace llvm { -class Type; -class Instruction; -class LoadInst; class LoopInfo; -class Loop; class ScalarEvolution; class SCEV; -class Value; -class PHINode; class Region; class Pass; -class BasicBlock; -class StringRef; -class DataLayout; class DominatorTree; class RegionInfo; -class TerminatorInst; -class ScalarEvolution; } namespace polly { @@ -49,6 +39,166 @@ /// @brief Type for a set of invariant loads. using InvariantLoadsSetTy = llvm::SetVector>; +/// @brief Utility proxy to wrap the common members of LoadInst and StoreInst. +/// +/// This works like the LLVM utility class CallSite, ie. it forwards all calls +/// to either a LoadInst or StoreInst. +/// It is similar to LLVM's utility classes IntrinsicInst, MemIntrinsic, +/// MemTransferInst, etc. in that it offers a common interface, but does not act +/// as a fake base class. +/// It is similar to StringRef and ArrayRef in that it holds a pointer to the +/// referenced object and should be passed by-value as it is small enough. +/// +/// This proxy can either represent a LoadInst instance, a StoreInst instance, +/// or a nullptr (only creatable using the default constructor); never an +/// Instruction that is not a load or store. +/// When representing a nullptr, only the following methods are defined: +/// isNull(), isInstruction(), isLoad(), isStore(), operator bool(), operator!() +/// +/// The functions isa, cast, cast_or_null, dyn_cast are modeled te resemble +/// those from llvm/Support/Casting.h. Partial template function specialization +/// is currently not supported in C++ such that those cannot be used directly. +/// (llvm::isa could, but then llvm:cast etc. would not have the expected +/// behaviour) +class MemAccInst { +private: + llvm::Instruction *I; + +public: + MemAccInst() : I(nullptr) {} + MemAccInst(const MemAccInst &Inst) : I(Inst.I) {} + /* implicit */ MemAccInst(llvm::LoadInst &LI) : I(&LI) {} + /* implicit */ MemAccInst(llvm::LoadInst *LI) : I(LI) {} + /* implicit */ MemAccInst(llvm::StoreInst &SI) : I(&SI) {} + /* implicit */ MemAccInst(llvm::StoreInst *SI) : I(SI) {} + explicit MemAccInst(llvm::Instruction &I) : I(&I) { assert(isa(I)); } + explicit MemAccInst(llvm::Instruction *I) : I(I) { assert(isa(I)); } + + static bool isa(const llvm::Value &V) { + return llvm::isa(V) || llvm::isa(V); + } + static bool isa(const llvm::Value *V) { + return llvm::isa(V) || llvm::isa(V); + } + static MemAccInst cast(llvm::Value &V) { + return MemAccInst(llvm::cast(V)); + } + static MemAccInst cast(llvm::Value *V) { + return MemAccInst(llvm::cast(V)); + } + static MemAccInst cast_or_null(llvm::Value &V) { + return MemAccInst(llvm::cast(V)); + } + static MemAccInst cast_or_null(llvm::Value *V) { + if (!V) + return MemAccInst(); + return MemAccInst(llvm::cast(V)); + } + static MemAccInst dyn_cast(llvm::Value &V) { + if (isa(V)) + return MemAccInst(llvm::cast(V)); + return MemAccInst(); + } + static MemAccInst dyn_cast(llvm::Value *V) { + assert(V); + if (isa(V)) + return MemAccInst(llvm::cast(V)); + return MemAccInst(); + } + + MemAccInst &operator=(const MemAccInst &Inst) { + I = Inst.I; + return *this; + } + MemAccInst &operator=(llvm::LoadInst &LI) { + I = &LI; + return *this; + } + MemAccInst &operator=(llvm::LoadInst *LI) { + I = LI; + return *this; + } + MemAccInst &operator=(llvm::StoreInst &SI) { + I = &SI; + return *this; + } + MemAccInst &operator=(llvm::StoreInst *SI) { + I = SI; + return *this; + } + + operator llvm::Instruction *() const { return asInstruction(); } + explicit operator bool() const { return isInstruction(); } + bool operator!() const { return isNull(); } + + llvm::Value *getOperand(unsigned i) const { return I->getOperand(i); } + llvm::BasicBlock *getParent() const { return I->getParent(); } + llvm::LLVMContext &getContext() const { return I->getContext(); } + void getAAMetadata(llvm::AAMDNodes &N, bool Merge = false) const { + I->getAAMetadata(N, Merge); + } + + llvm::Value *getValueOperand() const { + if (isLoad()) + return asLoad(); + if (isStore()) + return asStore()->getValueOperand(); + llvm_unreachable("Operation not supported on nullptr"); + } + llvm::Value *getPointerOperand() const { + if (isLoad()) + return asLoad()->getPointerOperand(); + if (isStore()) + return asStore()->getPointerOperand(); + llvm_unreachable("Operation not supported on nullptr"); + } + + unsigned getAlignment() const { + if (isLoad()) + return asLoad()->getAlignment(); + if (isStore()) + return asStore()->getAlignment(); + llvm_unreachable("Operation not supported on nullptr"); + } + bool isVolatile() const { + if (isLoad()) + return asLoad()->isVolatile(); + if (isStore()) + return asStore()->isVolatile(); + llvm_unreachable("Operation not supported on nullptr"); + } + bool isSimple() const { + if (isLoad()) + return asLoad()->isSimple(); + if (isStore()) + return asStore()->isSimple(); + llvm_unreachable("Operation not supported on nullptr"); + } + llvm::AtomicOrdering getOrdering() const { + if (isLoad()) + return asLoad()->getOrdering(); + if (isStore()) + return asStore()->getOrdering(); + llvm_unreachable("Operation not supported on nullptr"); + } + bool isUnordered() const { + if (isLoad()) + return asLoad()->isUnordered(); + if (isStore()) + return asStore()->isUnordered(); + llvm_unreachable("Operation not supported on nullptr"); + } + + bool isNull() const { return !I; } + bool isInstruction() const { return I; } + bool isLoad() const { return I && llvm::isa(I); } + bool isStore() const { return I && llvm::isa(I); } + + llvm::Instruction *asInstruction() const { return I; } + llvm::LoadInst *asLoad() const { return llvm::cast(I); } + llvm::StoreInst *asStore() const { return llvm::cast(I); } +}; + /// @brief Check if the PHINode has any incoming Invoke edge. /// /// @param PN The PHINode to check. @@ -58,8 +208,6 @@ /// otherwise, return false. bool hasInvokeEdge(const llvm::PHINode *PN); -llvm::Value *getPointerOperand(llvm::Instruction &Inst); - /// @brief Simplify the region to have a single unconditional entry edge and a /// single exit edge. /// Index: polly/trunk/lib/Analysis/ScopDetection.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopDetection.cpp +++ polly/trunk/lib/Analysis/ScopDetection.cpp @@ -758,11 +758,11 @@ return true; } -bool ScopDetection::isValidMemoryAccess(Instruction &Inst, +bool ScopDetection::isValidMemoryAccess(MemAccInst Inst, DetectionContext &Context) const { Region &CurRegion = Context.CurRegion; - Value *Ptr = getPointerOperand(Inst); + Value *Ptr = Inst.getPointerOperand(); Loop *L = LI->getLoopFor(Inst.getParent()); const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L); const SCEVUnknown *BasePointer; @@ -771,26 +771,26 @@ BasePointer = dyn_cast(SE->getPointerBase(AccessFunction)); if (!BasePointer) - return invalid(Context, /*Assert=*/true, &Inst); + return invalid(Context, /*Assert=*/true, Inst); BaseValue = BasePointer->getValue(); if (isa(BaseValue)) - return invalid(Context, /*Assert=*/true, &Inst); + return invalid(Context, /*Assert=*/true, Inst); // Check that the base address of the access is invariant in the current // region. if (!isInvariant(*BaseValue, CurRegion)) return invalid(Context, /*Assert=*/true, BaseValue, - &Inst); + Inst); AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer); - const SCEV *Size = SE->getElementSize(&Inst); + const SCEV *Size = SE->getElementSize(Inst); if (Context.ElementSize.count(BasePointer)) { if (Context.ElementSize[BasePointer] != Size) return invalid(Context, /*Assert=*/true, - &Inst, BaseValue); + Inst, BaseValue); } else { Context.ElementSize[BasePointer] = Size; } @@ -803,7 +803,7 @@ isVariantInNonAffineLoop = true; if (PollyDelinearize && !isVariantInNonAffineLoop) { - Context.Accesses[BasePointer].push_back({&Inst, AccessFunction}); + Context.Accesses[BasePointer].push_back({Inst, AccessFunction}); if (!isAffine(AccessFunction, Context, BaseValue)) Context.NonAffineAccesses.insert(BasePointer); @@ -811,7 +811,7 @@ if (isVariantInNonAffineLoop || !isAffine(AccessFunction, Context, BaseValue)) return invalid(Context, /*Assert=*/true, - AccessFunction, &Inst, BaseValue); + AccessFunction, Inst, BaseValue); } // FIXME: Think about allowing IntToPtrInst @@ -853,7 +853,7 @@ if (CanBuildRunTimeCheck) return true; } - return invalid(Context, /*Assert=*/true, &Inst, AS); + return invalid(Context, /*Assert=*/true, Inst, AS); } return true; @@ -887,19 +887,14 @@ } // Check the access function. - if (isa(Inst) || isa(Inst)) { - Context.hasStores |= isa(Inst); - Context.hasLoads |= isa(Inst); - if (auto *Load = dyn_cast(&Inst)) - if (!Load->isSimple()) - return invalid(Context, /*Assert=*/true, - &Inst); - if (auto *Store = dyn_cast(&Inst)) - if (!Store->isSimple()) - return invalid(Context, /*Assert=*/true, - &Inst); + if (auto MemInst = MemAccInst::dyn_cast(Inst)) { + Context.hasStores |= MemInst.isLoad(); + Context.hasLoads |= MemInst.isStore(); + if (!MemInst.isSimple()) + return invalid(Context, /*Assert=*/true, + &Inst); - return isValidMemoryAccess(Inst, Context); + return isValidMemoryAccess(MemInst, Context); } // We do not know this instruction, therefore we assume it is invalid. Index: polly/trunk/lib/Analysis/ScopInfo.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopInfo.cpp +++ polly/trunk/lib/Analysis/ScopInfo.cpp @@ -533,7 +533,7 @@ void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) { ScalarEvolution *SE = Statement->getParent()->getSE(); - Value *Ptr = getPointerOperand(*getAccessInstruction()); + Value *Ptr = MemAccInst(getAccessInstruction()).getPointerOperand(); if (!Ptr || !SE->isSCEVable(Ptr->getType())) return; @@ -2497,8 +2497,8 @@ continue; if (!MA->isRead()) HasWriteAccess.insert(MA->getBaseAddr()); - Instruction *Acc = MA->getAccessInstruction(); - PtrToAcc[getPointerOperand(*Acc)] = MA; + MemAccInst Acc(MA->getAccessInstruction()); + PtrToAcc[Acc.getPointerOperand()] = MA; AST.add(Acc); } } @@ -3703,28 +3703,16 @@ extern MapInsnToMemAcc InsnToMemAcc; void ScopInfo::buildMemoryAccess( - Instruction *Inst, Loop *L, Region *R, + MemAccInst Inst, Loop *L, Region *R, const ScopDetection::BoxedLoopsSetTy *BoxedLoops, const InvariantLoadsSetTy &ScopRIL) { - unsigned Size; - Type *SizeType; - Value *Val; - enum MemoryAccess::AccessType Type; - - if (LoadInst *Load = dyn_cast(Inst)) { - SizeType = Load->getType(); - Size = TD->getTypeAllocSize(SizeType); - Type = MemoryAccess::READ; - Val = Load; - } else { - StoreInst *Store = cast(Inst); - SizeType = Store->getValueOperand()->getType(); - Size = TD->getTypeAllocSize(SizeType); - Type = MemoryAccess::MUST_WRITE; - Val = Store->getValueOperand(); - } - auto Address = getPointerOperand(*Inst); + Value *Address = Inst.getPointerOperand(); + Value *Val = Inst.getValueOperand(); + Type *SizeType = Val->getType(); + unsigned Size = TD->getTypeAllocSize(SizeType); + enum MemoryAccess::AccessType Type = + Inst.isLoad() ? MemoryAccess::READ : MemoryAccess::MUST_WRITE; const SCEV *AccessFunction = SE->getSCEVAtScope(Address, L); const SCEVUnknown *BasePointer = @@ -3809,7 +3797,7 @@ // FIXME: Size of the number of bytes of an array element, not the number of // elements as probably intended here. const SCEV *SizeSCEV = - SE->getConstant(TD->getIntPtrType(Inst->getContext()), Size); + SE->getConstant(TD->getIntPtrType(Inst.getContext()), Size); if (!IsAffine && Type == MemoryAccess::MUST_WRITE) Type = MemoryAccess::MAY_WRITE; @@ -3881,8 +3869,8 @@ // invariant and will be hoisted for the SCoP to be processed. Though, // there might be other invariant accesses that will be hoisted and // that would allow to make a non-affine access affine. - if (isa(Inst) || isa(Inst)) - buildMemoryAccess(Inst, L, &R, BoxedLoops, ScopRIL); + if (auto MemInst = MemAccInst::dyn_cast(Inst)) + buildMemoryAccess(MemInst, L, &R, BoxedLoops, ScopRIL); if (isIgnoredIntrinsic(Inst)) continue; @@ -3947,15 +3935,14 @@ return &AccList.back(); } -void ScopInfo::addArrayAccess(Instruction *MemAccInst, +void ScopInfo::addArrayAccess(MemAccInst MemAccInst, MemoryAccess::AccessType Type, Value *BaseAddress, unsigned ElemBytes, bool IsAffine, ArrayRef Subscripts, ArrayRef Sizes, Value *AccessValue) { - assert(isa(MemAccInst) || isa(MemAccInst)); - assert(isa(MemAccInst) == (Type == MemoryAccess::READ)); - addMemoryAccess(MemAccInst->getParent(), MemAccInst, Type, BaseAddress, + assert(MemAccInst.isLoad() == (Type == MemoryAccess::READ)); + addMemoryAccess(MemAccInst.getParent(), MemAccInst, Type, BaseAddress, ElemBytes, IsAffine, AccessValue, Subscripts, Sizes, ScopArrayInfo::MK_Array); } Index: polly/trunk/lib/CodeGen/BlockGenerators.cpp =================================================================== --- polly/trunk/lib/CodeGen/BlockGenerators.cpp +++ polly/trunk/lib/CodeGen/BlockGenerators.cpp @@ -168,9 +168,10 @@ NewInst->setName("p_" + Inst->getName()); } -Value *BlockGenerator::generateLocationAccessed( - ScopStmt &Stmt, const Instruction *Inst, Value *Pointer, ValueMapT &BBMap, - LoopToScevMapT <S, isl_id_to_ast_expr *NewAccesses) { +Value * +BlockGenerator::generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst, + ValueMapT &BBMap, LoopToScevMapT <S, + isl_id_to_ast_expr *NewAccesses) { const MemoryAccess &MA = Stmt.getArrayAccessFor(Inst); isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, MA.getId()); @@ -196,7 +197,8 @@ return Address; } - return getNewValue(Stmt, Pointer, BBMap, LTS, getLoopForInst(Inst)); + return getNewValue(Stmt, Inst.getPointerOperand(), BBMap, LTS, + getLoopForInst(Inst)); } Loop *BlockGenerator::getLoopForInst(const llvm::Instruction *Inst) { @@ -209,9 +211,8 @@ if (Value *PreloadLoad = GlobalMap.lookup(Load)) return PreloadLoad; - auto *Pointer = Load->getPointerOperand(); Value *NewPointer = - generateLocationAccessed(Stmt, Load, Pointer, BBMap, LTS, NewAccesses); + generateLocationAccessed(Stmt, Load, BBMap, LTS, NewAccesses); Value *ScalarLoad = Builder.CreateAlignedLoad( NewPointer, Load->getAlignment(), Load->getName() + "_p_scalar_"); @@ -225,9 +226,8 @@ void BlockGenerator::generateScalarStore(ScopStmt &Stmt, StoreInst *Store, ValueMapT &BBMap, LoopToScevMapT <S, isl_id_to_ast_expr *NewAccesses) { - auto *Pointer = Store->getPointerOperand(); Value *NewPointer = - generateLocationAccessed(Stmt, Store, Pointer, BBMap, LTS, NewAccesses); + generateLocationAccessed(Stmt, Store, BBMap, LTS, NewAccesses); Value *ValueOperand = getNewValue(Stmt, Store->getValueOperand(), BBMap, LTS, getLoopForInst(Store)); @@ -667,7 +667,7 @@ unsigned Offset = NegativeStride ? VectorWidth - 1 : 0; Value *NewPointer = nullptr; - NewPointer = generateLocationAccessed(Stmt, Load, Pointer, ScalarMaps[Offset], + NewPointer = generateLocationAccessed(Stmt, Load, ScalarMaps[Offset], VLTS[Offset], NewAccesses); Value *VectorPtr = Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr"); @@ -694,8 +694,8 @@ __isl_keep isl_id_to_ast_expr *NewAccesses) { auto *Pointer = Load->getPointerOperand(); Type *VectorPtrType = getVectorPtrTy(Pointer, 1); - Value *NewPointer = generateLocationAccessed(Stmt, Load, Pointer, BBMap, - VLTS[0], NewAccesses); + Value *NewPointer = + generateLocationAccessed(Stmt, Load, BBMap, VLTS[0], NewAccesses); Value *VectorPtr = Builder.CreateBitCast(NewPointer, VectorPtrType, Load->getName() + "_p_vec_p"); LoadInst *ScalarLoad = @@ -723,8 +723,8 @@ Value *Vector = UndefValue::get(VectorType); for (int i = 0; i < VectorWidth; i++) { - Value *NewPointer = generateLocationAccessed( - Stmt, Load, Pointer, ScalarMaps[i], VLTS[i], NewAccesses); + Value *NewPointer = generateLocationAccessed(Stmt, Load, ScalarMaps[i], + VLTS[i], NewAccesses); Value *ScalarLoad = Builder.CreateLoad(NewPointer, Load->getName() + "_p_scalar_"); Vector = Builder.CreateInsertElement( @@ -814,8 +814,8 @@ if (Access.isStrideOne(isl_map_copy(Schedule))) { Type *VectorPtrType = getVectorPtrTy(Pointer, getVectorWidth()); - Value *NewPointer = generateLocationAccessed( - Stmt, Store, Pointer, ScalarMaps[0], VLTS[0], NewAccesses); + Value *NewPointer = generateLocationAccessed(Stmt, Store, ScalarMaps[0], + VLTS[0], NewAccesses); Value *VectorPtr = Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr"); @@ -826,8 +826,8 @@ } else { for (unsigned i = 0; i < ScalarMaps.size(); i++) { Value *Scalar = Builder.CreateExtractElement(Vector, Builder.getInt32(i)); - Value *NewPointer = generateLocationAccessed( - Stmt, Store, Pointer, ScalarMaps[i], VLTS[i], NewAccesses); + Value *NewPointer = generateLocationAccessed(Stmt, Store, ScalarMaps[i], + VLTS[i], NewAccesses); Builder.CreateStore(Scalar, NewPointer); } } Index: polly/trunk/lib/CodeGen/IRBuilder.cpp =================================================================== --- polly/trunk/lib/CodeGen/IRBuilder.cpp +++ polly/trunk/lib/CodeGen/IRBuilder.cpp @@ -131,10 +131,11 @@ if (!AliasScopeDomain) return; - if (!(isa(Inst) || isa(Inst))) + auto MemInst = MemAccInst::dyn_cast(Inst); + if (!MemInst) return; - auto *PtrSCEV = SE->getSCEV(getPointerOperand(*Inst)); + auto *PtrSCEV = SE->getSCEV(MemInst.getPointerOperand()); auto *BaseSCEV = SE->getPointerBase(PtrSCEV); auto *SU = dyn_cast(BaseSCEV); Index: polly/trunk/lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- polly/trunk/lib/CodeGen/IslNodeBuilder.cpp +++ polly/trunk/lib/CodeGen/IslNodeBuilder.cpp @@ -839,7 +839,8 @@ // the parent of Inst and lastly if the parent of Inst has an empty // domain. In the first and last case the instruction is dead but if // there is a statement or the domain is not empty Inst is not dead. - auto *Address = getPointerOperand(*Inst); + auto MemInst = MemAccInst::dyn_cast(Inst); + auto Address = MemInst ? MemInst.getPointerOperand() : nullptr; if (Address && SE.getUnknown(UndefValue::get(Address->getType())) == SE.getPointerBase(SE.getSCEV(Address))) { Index: polly/trunk/lib/Support/ScopHelper.cpp =================================================================== --- polly/trunk/lib/Support/ScopHelper.cpp +++ polly/trunk/lib/Support/ScopHelper.cpp @@ -30,17 +30,6 @@ #define DEBUG_TYPE "polly-scop-helper" -Value *polly::getPointerOperand(Instruction &Inst) { - if (LoadInst *load = dyn_cast(&Inst)) - return load->getPointerOperand(); - else if (StoreInst *store = dyn_cast(&Inst)) - return store->getPointerOperand(); - else if (GetElementPtrInst *gep = dyn_cast(&Inst)) - return gep->getPointerOperand(); - - return 0; -} - bool polly::hasInvokeEdge(const PHINode *PN) { for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) if (InvokeInst *II = dyn_cast(PN->getIncomingValue(i)))