Index: include/polly/CodeGen/BlockGenerators.h =================================================================== --- include/polly/CodeGen/BlockGenerators.h +++ 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: include/polly/ScopDetection.h =================================================================== --- include/polly/ScopDetection.h +++ 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: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -65,6 +65,8 @@ class ScopStmt; class ScopInfo; +typedef DenseMap OutgoingValueMapTy; + //===---------------------------------------------------------------------===// /// @brief Enumeration of assumptions Polly can take. @@ -1894,21 +1896,22 @@ /// @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); /// @brief Analyze and extract the cross-BB scalar dependences (or, /// dataflow dependencies) of an instruction. /// - /// @param Inst The instruction to be analyzed - /// @param R The SCoP region - /// @param NonAffineSubRegion The non affine sub-region @p Inst is in. + /// @param Inst The instruction to be analyzed. + void buildScalarDependences(Instruction *Inst); + + /// @brief Search for uses of the llvm::Value defined by @p Inst that are not + /// within the SCoP. If there is such use, add a SCALAR WRITE such that + /// it is available after the SCoP as escaping value. /// - /// @return True if the Instruction is used in other BB and a scalar write - /// Access is required. - bool buildScalarDependences(Instruction *Inst, Region *R, - Region *NonAffineSubRegio); + /// @param Inst The instruction to be analyzed. + void buildEscapingDependences(Instruction *Inst); /// @brief Create MemoryAccesses for the given PHI node in the given region. /// @@ -1977,7 +1980,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: include/polly/Support/ScopHelper.h =================================================================== --- include/polly/Support/ScopHelper.h +++ 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. /// @@ -164,5 +312,14 @@ /// otherwise return false. bool canSynthesize(const llvm::Value *V, const llvm::LoopInfo *LI, llvm::ScalarEvolution *SE, const llvm::Region *R); + +/// @brief Return the block in which a value is used. +/// +/// For normal instructions, this is the instruction's parent block. For PHI +/// nodes, this is the incoming block of that use, because this is where the +/// operand must be defined (i.e. its definition dominates this block). +/// Non-instructions do not use operands at a specific point such that in this +/// case this function returns nullptr. +llvm::BasicBlock *getUseBlock(llvm::Use &U); } #endif Index: lib/Analysis/ScopDetection.cpp =================================================================== --- lib/Analysis/ScopDetection.cpp +++ 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); - - return isValidMemoryAccess(Inst, Context); + 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(MemInst, Context); } // We do not know this instruction, therefore we assume it is invalid. Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ 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); } } @@ -3562,25 +3562,6 @@ continue; OnlyNonAffineSubRegionOperands = false; - - if (!R.contains(OpBB)) - continue; - - Instruction *OpI = dyn_cast(Op); - if (OpI) { - BasicBlock *OpIBB = OpI->getParent(); - // As we pretend there is a use (or more precise a write) of OpI in OpBB - // we have to insert a scalar dependence from the definition of OpI to - // OpBB if the definition is not in OpBB. - if (scop->getStmtForBasicBlock(OpIBB) != - scop->getStmtForBasicBlock(OpBB)) { - ensureValueRead(OpI, OpBB); - ensureValueWrite(OpI); - } - } else if (ModelReadOnlyScalars && !isa(Op)) { - ensureValueRead(Op, OpBB); - } - ensurePHIWrite(PHI, OpBB, Op, IsExitBlock); } @@ -3589,142 +3570,56 @@ } } -bool ScopInfo::buildScalarDependences(Instruction *Inst, Region *R, - Region *NonAffineSubRegion) { - bool canSynthesizeInst = canSynthesize(Inst, LI, SE, R); - if (isIgnoredIntrinsic(Inst)) - return false; - - bool AnyCrossStmtUse = false; - BasicBlock *ParentBB = Inst->getParent(); - - for (User *U : Inst->users()) { - Instruction *UI = dyn_cast(U); - - // Ignore the strange user - if (UI == 0) - continue; - - BasicBlock *UseParent = UI->getParent(); - - // Ignore basic block local uses. A value that is defined in a scop, but - // used in a PHI node in the same basic block does not count as basic block - // local, as for such cases a control flow edge is passed between definition - // and use. - if (UseParent == ParentBB && !isa(UI)) - continue; - - // Uses by PHI nodes in the entry node count as external uses in case the - // use is through an incoming block that is itself not contained in the - // region. - if (R->getEntry() == UseParent) { - if (auto *PHI = dyn_cast(UI)) { - bool ExternalUse = false; - for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) { - if (PHI->getIncomingValue(i) == Inst && - !R->contains(PHI->getIncomingBlock(i))) { - ExternalUse = true; - break; - } - } - - if (ExternalUse) { - AnyCrossStmtUse = true; - continue; - } - } - } +void ScopInfo::buildScalarDependences(Instruction *Inst) { + assert(!isa(Inst)); - // Do not build scalar dependences inside a non-affine subregion. - if (NonAffineSubRegion && NonAffineSubRegion->contains(UseParent)) - continue; - - // Check for PHI nodes in the region exit and skip them, if they will be - // modeled as PHI nodes. - // - // PHI nodes in the region exit that have more than two incoming edges need - // to be modeled as PHI-Nodes to correctly model the fact that depending on - // the control flow a different value will be assigned to the PHI node. In - // case this is the case, there is no need to create an additional normal - // scalar dependence. Hence, bail out before we register an "out-of-region" - // use for this definition. - if (isa(UI) && UI->getParent() == R->getExit() && - !R->getExitingBlock()) - continue; - - // Check whether or not the use is in the SCoP. - if (!R->contains(UseParent)) { - AnyCrossStmtUse = true; - continue; - } - - // If the instruction can be synthesized and the user is in the region - // we do not need to add scalar dependences. - if (canSynthesizeInst) - continue; + // Pull-in required operands. + for (Use &Op : Inst->operands()) + ensureValueRead(Op.get(), Inst->getParent()); +} - // No need to translate these scalar dependences into polyhedral form, - // because synthesizable scalars can be generated by the code generator. - if (canSynthesize(UI, LI, SE, R)) - continue; +void ScopInfo::buildEscapingDependences(Instruction *Inst) { + Region *R = &scop->getRegion(); - // Skip PHI nodes in the region as they handle their operands on their own. - if (isa(UI)) + // Check for uses of this instruction outside the scop. Because we do not + // iterate over such instructions and therefore did not "ensure" the existence + // of a write, we must determine such use here. + for (Use &U : Inst->uses()) { + Instruction *UI = dyn_cast(U.getUser()); + if (!UI) continue; - // Now U is used in another statement. - AnyCrossStmtUse = true; - - // Do not build a read access that is not in the current SCoP - // Use the def instruction as base address of the MemoryAccess, so that it - // will become the name of the scalar access in the polyhedral form. - ensureValueRead(Inst, UI->getParent()); - } - - if (ModelReadOnlyScalars && !isa(Inst)) { - for (Value *Op : Inst->operands()) { - if (canSynthesize(Op, LI, SE, R)) - continue; - - if (Instruction *OpInst = dyn_cast(Op)) - if (R->contains(OpInst)) - continue; - - if (isa(Op)) - continue; - - ensureValueRead(Op, Inst->getParent()); + BasicBlock *UseParent = getUseBlock(U); + BasicBlock *UserParent = UI->getParent(); + + // An escaping value is either used by an instruction not within the scop, + // or (when the scop region's exit needs to be simplified) by a PHI in the + // scop's exit block. This is because region simplification before code + // generation inserts new basic blocks before the PHI such that its incoming + // blocks are not in the scop anymore. + if (!R->contains(UseParent) || + (isa(UI) && UserParent == R->getExit() && + R->getExitingBlock())) { + // At least one escaping use found. + ensureValueWrite(Inst); + break; } } - - return AnyCrossStmtUse; } 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 +3704,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; @@ -3866,10 +3761,8 @@ // The set of loads that are required to be invariant. auto &ScopRIL = *SD->getRequiredInvariantLoads(&R); - for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) { - Instruction *Inst = &*I; - - PHINode *PHI = dyn_cast(Inst); + for (Instruction &Inst : BB) { + PHINode *PHI = dyn_cast(&Inst); if (PHI) buildPHIAccesses(PHI, R, NonAffineSubRegion, IsExitBlock); @@ -3881,21 +3774,21 @@ // 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)) + if (isIgnoredIntrinsic(&Inst)) continue; // Do not build scalar dependences for required invariant loads as we will // hoist them later on anyway or drop the SCoP if we cannot. - if (ScopRIL.count(dyn_cast(Inst))) + if (ScopRIL.count(dyn_cast(&Inst))) continue; - if (buildScalarDependences(Inst, &R, NonAffineSubRegion)) { - if (!isa(Inst)) - ensureValueWrite(Inst); - } + if (!PHI) + buildScalarDependences(&Inst); + if (!IsExitBlock) + buildEscapingDependences(&Inst); } } @@ -3947,15 +3840,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); } @@ -3975,12 +3867,38 @@ ArrayRef(), ScopArrayInfo::MK_Value); } void ScopInfo::ensureValueRead(Value *Value, BasicBlock *UserBB) { + + // There cannot be an "access" for constants. + if (isa(Value) || isa(Value)) + return; + + // If the instruction can be synthesized and the user is in the region we do + // not need to add a value dependences. + Region &ScopRegion = scop->getRegion(); + if (canSynthesize(Value, LI, SE, &ScopRegion)) + return; + + // Determine the ScopStmt containing the value's definition and use. There is + // no defining ScopStmt if the value is a function argument, a global value, + // or defined outside the SCoP. + Instruction *ValueInst = dyn_cast(Value); + ScopStmt *ValueStmt = + ValueInst ? scop->getStmtForBasicBlock(ValueInst->getParent()) : nullptr; + ScopStmt *UserStmt = scop->getStmtForBasicBlock(UserBB); // We do not model uses outside the scop. if (!UserStmt) return; + // Add MemoryAccess for invariant values only if requested. + if (!ModelReadOnlyScalars && !ValueStmt) + return; + + // Ignore use-def chains within the same ScopStmt. + if (ValueStmt == UserStmt) + return; + // Do not create another MemoryAccess for reloading the value if one already // exists. if (UserStmt->lookupValueReadOf(Value)) @@ -3989,10 +3907,21 @@ addMemoryAccess(UserBB, nullptr, MemoryAccess::READ, Value, 1, true, Value, ArrayRef(), ArrayRef(), ScopArrayInfo::MK_Value); + if (ValueInst) + ensureValueWrite(ValueInst); } void ScopInfo::ensurePHIWrite(PHINode *PHI, BasicBlock *IncomingBlock, Value *IncomingValue, bool IsExitBlock) { ScopStmt *IncomingStmt = scop->getStmtForBasicBlock(IncomingBlock); + if (!IncomingStmt) + return; + + // Take care for the incoming value being available in the incoming block. + // This must be done before the check for multiple PHI writes because multiple + // exiting edges from subregion each can be the effective written value of the + // subregion. As such, all of them must be made available in the subregion + // statement. + ensureValueRead(IncomingValue, IncomingBlock); // Do not add more than one MemoryAccess per PHINode and ScopStmt. if (MemoryAccess *Acc = IncomingStmt->lookupPHIWriteOf(PHI)) { Index: lib/CodeGen/BlockGenerators.cpp =================================================================== --- lib/CodeGen/BlockGenerators.cpp +++ 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: lib/CodeGen/IRBuilder.cpp =================================================================== --- lib/CodeGen/IRBuilder.cpp +++ 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: lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- lib/CodeGen/IslNodeBuilder.cpp +++ 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: lib/Support/ScopHelper.cpp =================================================================== --- lib/Support/ScopHelper.cpp +++ 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))) @@ -453,3 +442,14 @@ return false; } + +llvm::BasicBlock *polly::getUseBlock(llvm::Use &U) { + Instruction *UI = dyn_cast(U.getUser()); + if (!UI) + return nullptr; + + if (PHINode *PHI = dyn_cast(UI)) + return PHI->getIncomingBlock(U); + + return UI->getParent(); +} Index: test/Isl/CodeGen/MemAccess/update_access_functions.ll =================================================================== --- test/Isl/CodeGen/MemAccess/update_access_functions.ll +++ test/Isl/CodeGen/MemAccess/update_access_functions.ll @@ -8,8 +8,8 @@ ; CHECK: polly.stmt.loop3: ; CHECK-NEXT: %val.s2a.reload = load double, double* %val.s2a -; CHECK-NEXT: %polly.access.A20 = getelementptr double, double* %A, i64 42 -; CHECK-NEXT: store double %val.s2a.reload, double* %polly.access.A20 +; CHECK-NEXT: %scevgep[[R21:[0-9]*]] = getelementptr double, double* %scevgep{{[0-9]*}}, i64 %polly.indvar16 +; CHECK-NEXT: store double %val.s2a.reload, double* %scevgep[[R21]] target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/Isl/CodeGen/phi-defined-before-scop.ll =================================================================== --- test/Isl/CodeGen/phi-defined-before-scop.ll +++ test/Isl/CodeGen/phi-defined-before-scop.ll @@ -4,8 +4,7 @@ ; CHECK-NEXT: %tmp7.ph.merge = phi %struct.wibble* [ %tmp7.ph.final_reload, %polly.exiting ], [ %tmp7.ph, %bb6.region_exiting ] ; CHECK-LABEL: polly.stmt.bb3: -; CHECK-NEXT: %tmp2.s2a.reload = load %struct.wibble*, %struct.wibble** %tmp2.s2a -; CHECK-NEXT: store %struct.wibble* %tmp2.s2a.reload, %struct.wibble** %tmp7.s2a +; CHECK-NEXT: store %struct.wibble* %tmp2, %struct.wibble** %tmp7.s2a target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll =================================================================== --- test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll +++ test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll @@ -8,17 +8,11 @@ ; In this case the Loop passed to the expander must NOT be the loop ; - Overwriting the same alloca in each iteration s.t. the last value will ; retain in %i.inc.s2a -; The latter is currently generated by Polly and tested here. +; The first is currently generated by Polly and tested here. ; CHECK: polly.stmt.next: -; CHECK-NEXT: %i.inc.s2a.reload = load i32, i32* %i.inc.s2a -; CHECK-NEXT: store i32 %i.inc.s2a.reload, i32* %phi.phiops +; CHECK-NEXT: store i32 2, i32* %phi.phiops ; CHECK-NEXT: br label %polly.stmt.join -; -; CHECK: polly.stmt.loop: -; CHECK: %0 = trunc i64 %polly.indvar to i32 -; CHECK: %1 = add i32 %0, 1 -; CHECK: store i32 %1, i32* %i.inc.s2a define i32 @func() { entry: Index: test/Isl/CodeGen/uninitialized_scalar_memory.ll =================================================================== --- test/Isl/CodeGen/uninitialized_scalar_memory.ll +++ test/Isl/CodeGen/uninitialized_scalar_memory.ll @@ -5,7 +5,6 @@ ; ; CHECK: polly.start: ; CHECK-NEXT: store float %ebig.0, float* %ebig.0.s2a -; CHECK-NEXT: store i32 %iebig.0, i32* %iebig.0.s2a ; CHECK-NEXT: br label %polly.stmt.if.end.entry ; ; int g(void); Index: test/ScopInfo/NonAffine/non_affine_loop_used_later.ll =================================================================== --- test/ScopInfo/NonAffine/non_affine_loop_used_later.ll +++ test/ScopInfo/NonAffine/non_affine_loop_used_later.ll @@ -25,7 +25,6 @@ ; CHECK-NEXT: i32 MemRef_j_0__phi; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_0; // Element size 4 ; CHECK-NEXT: i32 MemRef_A[*]; // Element size 4 -; CHECK-NEXT: i32 MemRef_smax; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_2__phi; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_2; // Element size 4 ; CHECK-NEXT: } @@ -33,7 +32,6 @@ ; CHECK-NEXT: i32 MemRef_j_0__phi; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_0; // Element size 4 ; CHECK-NEXT: i32 MemRef_A[*]; // Element size 4 -; CHECK-NEXT: i32 MemRef_smax; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_2__phi; // Element size 4 ; CHECK-NEXT: i32 MemRef_j_2; // Element size 4 ; CHECK-NEXT: } @@ -60,8 +58,6 @@ ; CHECK-NEXT: [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] }; ; CHECK-NEXT: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_smax[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_2__phi[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] Index: test/ScopInfo/invariant-loads-leave-read-only-statements.ll =================================================================== --- test/ScopInfo/invariant-loads-leave-read-only-statements.ll +++ test/ScopInfo/invariant-loads-leave-read-only-statements.ll @@ -8,24 +8,36 @@ ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_top_split[] -> [0, 0, 0, 0] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_top_split[] -> MemRef_25[] }; -; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_top_split[] -> MemRef_26[] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_top_split[] -> MemRef_25[] }; ; CHECK-NEXT: Stmt_L_4 ; CHECK-NEXT: Domain := ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] : 0 <= i0 < p_0 and 0 <= i1 < p_0 and 0 <= i2 < p_0 }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> [1, i0, i1, i2] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_25[] }; +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_22[] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_19[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_19[i1, i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_8[] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_5[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_5[i2, i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_15[] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_12[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_12[i2, i1] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_19[i1, i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [p_0, p_1, p_2] -> { Stmt_L_4[i0, i1, i2] -> MemRef_25[] }; ; CHECK-NEXT: } target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/ScopInfo/long-sequence-of-error-blocks.ll =================================================================== --- test/ScopInfo/long-sequence-of-error-blocks.ll +++ test/ScopInfo/long-sequence-of-error-blocks.ll @@ -28,6 +28,8 @@ ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] : tmp17 < 0 or tmp17 > 0 }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] -> [1] : tmp17 < 0 or tmp17 > 0 }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] -> MemRef_tmp[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] -> MemRef_A[0] }; ; CHECK-NEXT: Stmt_bb24 @@ -42,6 +44,8 @@ ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] : tmp27 = 3 }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] -> [3] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] -> MemRef_tmp25[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] -> MemRef_A[0] }; ; CHECK-NEXT: } Index: test/ScopInfo/many-scalar-dependences.ll =================================================================== --- test/ScopInfo/many-scalar-dependences.ll +++ test/ScopInfo/many-scalar-dependences.ll @@ -92,12 +92,12 @@ ; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> [i0, 2, i1, 2, i2, 3] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> MemRef_x_3__phi[] }; -; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> MemRef_x_3[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> MemRef_a[i0, i1] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> MemRef_a[i0, i1] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: { Stmt_bb12[i0, i1, i2] -> MemRef_x_3[] }; ; CHECK-NEXT: Stmt_bb16 ; CHECK-NEXT: Domain := ; CHECK-NEXT: { Stmt_bb16[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 99 and 0 <= i2 <= 99 }; Index: test/ScopInfo/multidim_fortran_srem.ll =================================================================== --- test/ScopInfo/multidim_fortran_srem.ll +++ test/ScopInfo/multidim_fortran_srem.ll @@ -18,10 +18,10 @@ ; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> [i0, 1, i1, i2] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp192[] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp194[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp173[o0, 1 + i1, 1 + i2] : 3*floor((-i0 + o0)/3) = -i0 + o0 and 0 <= o0 <= 2 }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp194[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp173[o0, 1 + i1, 1 + i2] : 3*floor((-2 - i0 + o0)/3) = -2 - i0 + o0 and 0 <= o0 <= 2 }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] Index: test/ScopInfo/non_affine_region_1.ll =================================================================== --- test/ScopInfo/non_affine_region_1.ll +++ test/ScopInfo/non_affine_region_1.ll @@ -41,8 +41,6 @@ ; CHECK-NEXT: [b] -> { Stmt_bb8[0] : b = 0 }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [b] -> { Stmt_bb8[i0] -> [0, 0] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [b] -> { Stmt_bb8[i0] -> MemRef_b[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [b] -> { Stmt_bb8[i0] -> MemRef_x_1__phi[] }; ; CHECK-NEXT: Stmt_bb10__TO__bb18 Index: test/ScopInfo/non_affine_region_3.ll =================================================================== --- test/ScopInfo/non_affine_region_3.ll +++ test/ScopInfo/non_affine_region_3.ll @@ -31,8 +31,6 @@ ; CHECK-NEXT: { Stmt_bb3__TO__bb18[i0] -> MemRef_A[i0] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2__phi[] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: { Stmt_bb3__TO__bb18[i0] -> MemRef_b[] }; ; CHECK-NEXT: Stmt_bb18 ; CHECK-NEXT: Domain := ; CHECK-NEXT: { Stmt_bb18[i0] : 0 <= i0 <= 1023 }; Index: test/ScopInfo/non_affine_region_4.ll =================================================================== --- test/ScopInfo/non_affine_region_4.ll +++ test/ScopInfo/non_affine_region_4.ll @@ -16,14 +16,14 @@ ; ; CHECK: Arrays { ; CHECK-NEXT: i32 MemRef_A[*]; // Element size 4 -; CHECK-NEXT: i32 MemRef_x; [BasePtrOrigin: MemRef_A] // Element size 4 ; CHECK-NEXT: i32 MemRef_y__phi; // Element size 4 +; CHECK-NEXT: i32 MemRef_x; [BasePtrOrigin: MemRef_A] // Element size 4 ; CHECK-NEXT: } ; ; CHECK: Arrays (Bounds as pw_affs) { ; CHECK-NEXT: i32 MemRef_A[*]; // Element size 4 -; CHECK-NEXT: i32 MemRef_x; [BasePtrOrigin: MemRef_A] // Element size 4 ; CHECK-NEXT: i32 MemRef_y__phi; // Element size 4 +; CHECK-NEXT: i32 MemRef_x; [BasePtrOrigin: MemRef_A] // Element size 4 ; CHECK-NEXT: } ; ; CHECK: Statements { @@ -35,18 +35,18 @@ ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: { Stmt_bb2__TO__bb7[i0] -> MemRef_A[i0] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: { Stmt_bb2__TO__bb7[i0] -> MemRef_x[] }; -; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: { Stmt_bb2__TO__bb7[i0] -> MemRef_y__phi[] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: { Stmt_bb2__TO__bb7[i0] -> MemRef_x[] }; ; CHECK-NEXT: Stmt_bb7 ; CHECK-NEXT: Domain := ; CHECK-NEXT: { Stmt_bb7[i0] : 0 <= i0 <= 1023 }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: { Stmt_bb7[i0] -> [i0, 1] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: { Stmt_bb7[i0] -> MemRef_x[] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: { Stmt_bb7[i0] -> MemRef_y__phi[] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: { Stmt_bb7[i0] -> MemRef_x[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: { Stmt_bb7[i0] -> MemRef_A[i0] }; ; CHECK-NEXT: } Index: test/ScopInfo/phi_condition_modeling_2.ll =================================================================== --- test/ScopInfo/phi_condition_modeling_2.ll +++ test/ScopInfo/phi_condition_modeling_2.ll @@ -40,10 +40,10 @@ ; CHECK-NEXT: [N, c] -> { Stmt_bb8b[i0] : 0 <= i0 < N }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [N, c] -> { Stmt_bb8b[i0] -> [i0, 3] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N, c] -> { Stmt_bb8b[i0] -> MemRef_tmp_0[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N, c] -> { Stmt_bb8b[i0] -> MemRef_A[i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N, c] -> { Stmt_bb8b[i0] -> MemRef_tmp_0[] }; ; CHECK-NEXT: } target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/ScopInfo/phi_loop_carried_float.ll =================================================================== --- test/ScopInfo/phi_loop_carried_float.ll +++ test/ScopInfo/phi_loop_carried_float.ll @@ -23,10 +23,10 @@ ; CHECK-NEXT: [N] -> { Stmt_bb4[i0] -> [i0, 1] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0__phi[] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N] -> { Stmt_bb4[i0] -> MemRef_A[i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] }; ; CHECK-NEXT: } target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/ScopInfo/phi_scalar_simple_1.ll =================================================================== --- test/ScopInfo/phi_scalar_simple_1.ll +++ test/ScopInfo/phi_scalar_simple_1.ll @@ -51,10 +51,10 @@ ; CHECK-NEXT: [N] -> { Stmt_for_inc[i0, i1] -> [i0, 2, i1, 1] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1__phi[] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N] -> { Stmt_for_inc[i0, i1] -> MemRef_A[1 + i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] }; ; CHECK-NEXT: Stmt_for_end ; CHECK-NEXT: Domain := ; CHECK-NEXT: [N] -> { Stmt_for_end[i0] : N >= 3 and 0 <= i0 <= -2 + N }; Index: test/ScopInfo/phi_scalar_simple_2.ll =================================================================== --- test/ScopInfo/phi_scalar_simple_2.ll +++ test/ScopInfo/phi_scalar_simple_2.ll @@ -52,10 +52,10 @@ ; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] : 0 <= i0 < c and i0 < N and 0 <= i1 < N }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] -> [i0, 2, i1, 2] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_1[] }; ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_A[i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_1[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_2__phi[] }; ; CHECK-NEXT: Stmt_if_end Index: test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll =================================================================== --- test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll +++ test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll @@ -6,16 +6,12 @@ ; CHECK: Arrays { ; CHECK-NEXT: float MemRef_A[*]; // Element size 4 -; CHECK-NEXT: float* MemRef_A; // Element size 8 ; CHECK-NEXT: float* MemRef_x__phi; // Element size 8 -; CHECK-NEXT: float* MemRef_B; // Element size 8 ; CHECK-NEXT: float* MemRef_C[*]; // Element size 8 ; CHECK-NEXT: } ; CHECK: Arrays (Bounds as pw_affs) { ; CHECK-NEXT: float MemRef_A[*]; // Element size 4 -; CHECK-NEXT: float* MemRef_A; // Element size 8 ; CHECK-NEXT: float* MemRef_x__phi; // Element size 8 -; CHECK-NEXT: float* MemRef_B; // Element size 8 ; CHECK-NEXT: float* MemRef_C[*]; // Element size 8 ; CHECK-NEXT: } ; CHECK: Alias Groups (0): @@ -28,8 +24,6 @@ ; CHECK-NEXT: [p] -> { Stmt_then[i0] -> [i0, 1] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p] -> { Stmt_then[i0] -> MemRef_A[0] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [p] -> { Stmt_then[i0] -> MemRef_A[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [p] -> { Stmt_then[i0] -> MemRef_x__phi[] }; ; CHECK-NEXT: Stmt_else @@ -39,8 +33,6 @@ ; CHECK-NEXT: [p] -> { Stmt_else[i0] -> [i0, 0] : p >= 33 or p <= 31 }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [p] -> { Stmt_else[i0] -> MemRef_A[0] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [p] -> { Stmt_else[i0] -> MemRef_B[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [p] -> { Stmt_else[i0] -> MemRef_x__phi[] }; ; CHECK-NEXT: Stmt_bb8 Index: test/ScopInfo/same-base-address-scalar-and-array.ll =================================================================== --- test/ScopInfo/same-base-address-scalar-and-array.ll +++ test/ScopInfo/same-base-address-scalar-and-array.ll @@ -4,7 +4,6 @@ ; as it is used as a memory base pointer (%0) but also as a scalar (%out.addr.0.lcssa). ; ; CHECK: Arrays { -; CHECK-NEXT: float* MemRef_out; // Element size 8 ; CHECK-NEXT: float* MemRef_out_addr_0_lcssa; // Element size 8 ; CHECK-NEXT: float MemRef_out[*]; // Element size 4 ; CHECK-NEXT: } Index: test/ScopInfo/scalar.ll =================================================================== --- test/ScopInfo/scalar.ll +++ test/ScopInfo/scalar.ll @@ -55,8 +55,8 @@ ; CHECK-NEXT: [N] -> { Stmt_S2[i0] : 0 <= i0 < N }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [N] -> { Stmt_S2[i0] -> [i0, 1] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N] -> { Stmt_S2[i0] -> MemRef_val[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N] -> { Stmt_S2[i0] -> MemRef_a[i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N] -> { Stmt_S2[i0] -> MemRef_val[] }; ; CHECK-NEXT: } Index: test/ScopInfo/tempscop-printing.ll =================================================================== --- test/ScopInfo/tempscop-printing.ll +++ test/ScopInfo/tempscop-printing.ll @@ -33,10 +33,10 @@ ; CHECK-NEXT: [N] -> { Stmt_for_j[i0, i1] : 0 <= i0 < N and 0 <= i1 < N }; ; CHECK-NEXT: Schedule := ; CHECK-NEXT: [N] -> { Stmt_for_j[i0, i1] -> [i0, i1] }; -; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] -; CHECK-NEXT: [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] }; ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] ; CHECK-NEXT: [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] }; ; CHECK-NEXT: } target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"