Allow mapping scalar MemoryAccesses to array elements.

Change the code around setNewAccessRelation to allow to use a an existing array
element for memory instead of an ad-hoc alloca. This facility will be used for
DeLICM/DeGVN to convert scalar dependencies into regular ones.

The changes necessary include:
- Make the code generator use the implicit locations instead of the alloca ones.
- A test case
- Make the JScop importer accept changes of scalar accesses for that test case.
- Adapt the MemoryAccess interface to the fact that the MemoryKind can change.
  They are named (get|is)OriginalXXX() to get the status of the memory access
  before any change by setNewAccessRelation() (some properties such as
  getIncoming() do not change even if the kind is changed and are still
  required). To get the modified properties, there is (get|is)LatestXXX(). The
  old accessors without Original|Latest become synonyms of the
  (get|is)OriginalXXX() to not make functional changes in unrelated code.

Differential Revision: https://reviews.llvm.org/D23962

llvm-svn: 280408
This commit is contained in:
Michael Kruse 2016-09-01 19:53:31 +00:00
parent a78187a385
commit 2fa3519463
8 changed files with 585 additions and 46 deletions

View File

@ -366,8 +366,13 @@ protected:
/// @brief Generate reload of scalars demoted to memory and needed by @p Stmt.
///
/// @param Stmt The statement we generate code for.
/// @param LTS A mapping from loops virtual canonical induction
/// variable to their new values.
/// @param BBMap A mapping from old values to their new values in this block.
void generateScalarLoads(ScopStmt &Stmt, ValueMapT &BBMap);
/// @param NewAccesses A map from memory access ids to new ast expressions.
void generateScalarLoads(ScopStmt &Stmt, LoopToScevMapT &LTS,
ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses);
/// @brief Generate the scalar stores for the given statement.
///
@ -381,8 +386,10 @@ protected:
/// (for values recalculated in the new ScoP, but not
/// within this basic block)
/// @param BBMap A mapping from old values to their new values in this block.
/// @param NewAccesses A map from memory access ids to new ast expressions.
virtual void generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
ValueMapT &BBMap);
ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses);
/// @brief Handle users of @p Inst outside the SCoP.
///
@ -493,6 +500,48 @@ protected:
ValueMapT &BBMap, LoopToScevMapT &LTS,
isl_id_to_ast_expr *NewAccesses);
/// @brief Generate the operand address.
///
/// @param Stmt The statement to generate code for.
/// @param L The innermost loop that surrounds the statement.
/// @param Pointer If the access expression is not changed (ie. not found
/// in @p LTS), use this Pointer from the original code
/// instead.
/// @param BBMap A mapping from old values to their new values.
/// @param LTS A mapping from loops virtual canonical induction
/// variable to their new values.
/// @param NewAccesses Ahead-of-time generated access expressions.
/// @param Id Identifier of the MemoryAccess to generate.
/// @param ExpectedType The type the returned value should have.
///
/// @return The generated address.
Value *generateLocationAccessed(ScopStmt &Stmt, Loop *L, Value *Pointer,
ValueMapT &BBMap, LoopToScevMapT &LTS,
isl_id_to_ast_expr *NewAccesses,
__isl_take isl_id *Id, Type *ExpectedType);
/// @brief Generate the pointer value that is accesses by @p Access.
///
/// For write accesses, generate the target address. For read accesses,
/// generate the source address.
/// The access can be either an array access or a scalar access. In the first
/// case, the returned address will point to an element into that array. In
/// the scalar case, an alloca is used.
/// If a new AccessRelation is set for the MemoryAccess, the new relation will
/// be used.
///
/// @param Access The access to generate a pointer for.
/// @param L The innermost loop that surrounds the statement.
/// @param LTS A mapping from loops virtual canonical induction
/// variable to their new values.
/// @param BBMap A mapping from old values to their new values.
/// @param NewAccesses A map from memory access ids to new ast expressions.
///
/// @return The generated address.
Value *getImplicitAddress(MemoryAccess &Access, Loop *L, LoopToScevMapT &LTS,
ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses);
/// @param NewAccesses A map from memory access ids to new ast expressions,
/// which may contain new access expressions for certain
/// memory accesses.
@ -834,8 +883,11 @@ private:
/// their new values (for values recalculated in the new ScoP,
/// but not within this basic block)
/// @param BBMap A mapping from old values to their new values in this block.
virtual void generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
ValueMapT &BBMAp) override;
/// @param LTS A mapping from loops virtual canonical induction variable to
/// their new values.
virtual void
generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMAp,
__isl_keep isl_id_to_ast_expr *NewAccesses) override;
/// @brief Copy a single PHI instruction.
///

View File

@ -317,6 +317,9 @@ public:
/// @brief Return the isl id for the base pointer.
__isl_give isl_id *getBasePtrId() const;
/// @brief Return what kind of memory this represents.
enum MemoryKind getKind() const { return Kind; }
/// @brief Is this array info modeling an llvm::Value?
bool isValueKind() const { return Kind == MK_Value; }
@ -743,11 +746,16 @@ public:
/// As 2) is by construction "newer" than 1) we return the new access
/// relation if present.
///
__isl_give isl_map *getAccessRelation() const {
__isl_give isl_map *getLatestAccessRelation() const {
return hasNewAccessRelation() ? getNewAccessRelation()
: getOriginalAccessRelation();
}
/// @brief Old name of getLatestAccessRelation().
__isl_give isl_map *getAccessRelation() const {
return getLatestAccessRelation();
}
/// @brief Get an isl map describing the memory address accessed.
///
/// In most cases the memory address accessed is well described by the access
@ -773,14 +781,44 @@ public:
/// @brief Get an isl string representing a new access function, if available.
std::string getNewAccessRelationStr() const;
/// @brief Get the base address of this access (e.g. A for A[i+j]).
Value *getBaseAddr() const { return BaseAddr; }
/// @brief Get the base address of this access (e.g. A for A[i+j]) when
/// detected.
Value *getOriginalBaseAddr() const {
assert(!getOriginalScopArrayInfo() /* may noy yet be initialized */ ||
getOriginalScopArrayInfo()->getBasePtr() == BaseAddr);
return BaseAddr;
}
/// @brief Get the base array isl_id for this access.
__isl_give isl_id *getArrayId() const;
/// @brief Get the base address of this access (e.g. A for A[i+j]) after a
/// potential change by setNewAccessRelation().
Value *getLatestBaseAddr() const {
return getLatestScopArrayInfo()->getBasePtr();
}
/// @brief Get the ScopArrayInfo object for the base address.
const ScopArrayInfo *getScopArrayInfo() const;
/// @brief Old name for getOriginalBaseAddr().
Value *getBaseAddr() const { return getOriginalBaseAddr(); }
/// @brief Get the detection-time base array isl_id for this access.
__isl_give isl_id *getOriginalArrayId() const;
/// @brief Get the base array isl_id for this access, modifiable through
/// setNewAccessRelation().
__isl_give isl_id *getLatestArrayId() const;
/// @brief Old name of getOriginalArrayId().
__isl_give isl_id *getArrayId() const { return getOriginalArrayId(); }
/// @brief Get the detection-time ScopArrayInfo object for the base address.
const ScopArrayInfo *getOriginalScopArrayInfo() const;
/// @brief Get the ScopArrayInfo object for the base address, or the one set
/// by setNewAccessRelation().
const ScopArrayInfo *getLatestScopArrayInfo() const;
/// @brief Legacy name of getOriginalScopArrayInfo().
const ScopArrayInfo *getScopArrayInfo() const {
return getOriginalScopArrayInfo();
}
/// @brief Return a string representation of the access's reduction type.
const std::string getReductionOperatorStr() const;
@ -842,26 +880,105 @@ public:
/// statement.
bool isStrideZero(__isl_take const isl_map *Schedule) const;
/// @brief Whether this is an access of an explicit load or store in the IR.
bool isArrayKind() const { return Kind == ScopArrayInfo::MK_Array; }
/// @brief Return the kind when this access was first detected.
ScopArrayInfo::MemoryKind getOriginalKind() const {
assert(!getOriginalScopArrayInfo() /* not yet initialized */ ||
getOriginalScopArrayInfo()->getKind() == Kind);
return Kind;
}
/// @brief Whether this access is an array to a scalar memory object.
/// @brief Return the kind considering a potential setNewAccessRelation.
ScopArrayInfo::MemoryKind getLatestKind() const {
return getLatestScopArrayInfo()->getKind();
}
/// @brief Whether this is an access of an explicit load or store in the IR.
bool isOriginalArrayKind() const {
return getOriginalKind() == ScopArrayInfo::MK_Array;
}
/// @brief Whether storage memory is either an custom .s2a/.phiops alloca
/// (false) or an existing pointer into an array (true).
bool isLatestArrayKind() const {
return getLatestKind() == ScopArrayInfo::MK_Array;
}
/// @brief Old name of isOriginalArrayKind.
bool isArrayKind() const { return isOriginalArrayKind(); }
/// @brief Whether this access is an array to a scalar memory object, without
/// considering changes by setNewAccessRelation.
///
/// Scalar accesses are accesses to MK_Value, MK_PHI or MK_ExitPHI.
bool isScalarKind() const { return !isArrayKind(); }
bool isOriginalScalarKind() const {
return getOriginalKind() != ScopArrayInfo::MK_Array;
}
/// @brief Is this MemoryAccess modeling scalar dependences?
bool isValueKind() const { return Kind == ScopArrayInfo::MK_Value; }
/// @brief Whether this access is an array to a scalar memory object, also
/// considering changes by setNewAccessRelation.
bool isLatestScalarKind() const {
return getLatestKind() != ScopArrayInfo::MK_Array;
}
/// @brief Is this MemoryAccess modeling special PHI node accesses?
bool isPHIKind() const { return Kind == ScopArrayInfo::MK_PHI; }
/// @brief Old name of isOriginalScalarKind.
bool isScalarKind() const { return isOriginalScalarKind(); }
/// @brief Was this MemoryAccess detected as a scalar dependences?
bool isOriginalValueKind() const {
return getOriginalKind() == ScopArrayInfo::MK_Value;
}
/// @brief Is this MemoryAccess currently modeling scalar dependences?
bool isLatestValueKind() const {
return getLatestKind() == ScopArrayInfo::MK_Value;
}
/// @brief Old name of isOriginalValueKind().
bool isValueKind() const { return isOriginalValueKind(); }
/// @brief Was this MemoryAccess detected as a special PHI node access?
bool isOriginalPHIKind() const {
return getOriginalKind() == ScopArrayInfo::MK_PHI;
}
/// @brief Is this MemoryAccess modeling special PHI node accesses, also
/// considering a potential change by setNewAccessRelation?
bool isLatestPHIKind() const {
return getLatestKind() == ScopArrayInfo::MK_PHI;
}
/// @brief Old name of isOriginalPHIKind.
bool isPHIKind() const { return isOriginalPHIKind(); }
/// @brief Was this MemoryAccess detected as the accesses of a PHI node in the
/// SCoP's exit block?
bool isOriginalExitPHIKind() const {
return getOriginalKind() == ScopArrayInfo::MK_ExitPHI;
}
/// @brief Is this MemoryAccess modeling the accesses of a PHI node in the
/// SCoP's exit block?
bool isExitPHIKind() const { return Kind == ScopArrayInfo::MK_ExitPHI; }
/// SCoP's exit block? Can be changed to an array access using
/// setNewAccessRelation().
bool isLatestExitPHIKind() const {
return getLatestKind() == ScopArrayInfo::MK_ExitPHI;
}
/// @brief Does this access orginate from one of the two PHI types?
bool isAnyPHIKind() const { return isPHIKind() || isExitPHIKind(); }
/// @brief Old name of isOriginalExitPHIKind().
bool isExitPHIKind() const { return isOriginalExitPHIKind(); }
/// @brief Was this access detected as one of the two PHI types?
bool isOriginalAnyPHIKind() const {
return isOriginalPHIKind() || isOriginalExitPHIKind();
}
/// @brief Does this access orginate from one of the two PHI types? Can be
/// changed to an array access using setNewAccessRelation().
bool isLatestAnyPHIKind() const {
return isLatestPHIKind() || isLatestExitPHIKind();
}
/// @brief Old name of isOriginalAnyPHIKind().
bool isAnyPHIKind() const { return isOriginalAnyPHIKind(); }
/// @brief Get the statement that contains this memory access.
ScopStmt *getStatement() const { return Statement; }

View File

@ -499,7 +499,7 @@ MemoryAccess::~MemoryAccess() {
isl_map_free(NewAccessRelation);
}
const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const {
isl_id *ArrayId = getArrayId();
void *User = isl_id_get_user(ArrayId);
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
@ -507,10 +507,24 @@ const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
return SAI;
}
__isl_give isl_id *MemoryAccess::getArrayId() const {
const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const {
isl_id *ArrayId = getLatestArrayId();
void *User = isl_id_get_user(ArrayId);
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
isl_id_free(ArrayId);
return SAI;
}
__isl_give isl_id *MemoryAccess::getOriginalArrayId() const {
return isl_map_get_tuple_id(AccessRelation, isl_dim_out);
}
__isl_give isl_id *MemoryAccess::getLatestArrayId() const {
if (!hasNewAccessRelation())
return getOriginalArrayId();
return isl_map_get_tuple_id(NewAccessRelation, isl_dim_out);
}
__isl_give isl_map *MemoryAccess::getAddressFunction() const {
return isl_map_lexmin(getAccessRelation());
}

View File

@ -172,8 +172,17 @@ BlockGenerator::generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst,
ValueMapT &BBMap, LoopToScevMapT &LTS,
isl_id_to_ast_expr *NewAccesses) {
const MemoryAccess &MA = Stmt.getArrayAccessFor(Inst);
return generateLocationAccessed(
Stmt, getLoopForStmt(Stmt),
Inst.isNull() ? nullptr : Inst.getPointerOperand(), BBMap, LTS,
NewAccesses, MA.getId(), MA.getAccessValue()->getType());
}
isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, MA.getId());
Value *BlockGenerator::generateLocationAccessed(
ScopStmt &Stmt, Loop *L, Value *Pointer, ValueMapT &BBMap,
LoopToScevMapT &LTS, isl_id_to_ast_expr *NewAccesses, __isl_take isl_id *Id,
Type *ExpectedType) {
isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, Id);
if (AccessExpr) {
AccessExpr = isl_ast_expr_address_of(AccessExpr);
@ -182,7 +191,7 @@ BlockGenerator::generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst,
// Cast the address of this memory access to a pointer type that has the
// same element type as the original access, but uses the address space of
// the newly generated pointer.
auto OldPtrTy = MA.getAccessValue()->getType()->getPointerTo();
auto OldPtrTy = ExpectedType->getPointerTo();
auto NewPtrTy = Address->getType();
OldPtrTy = PointerType::get(OldPtrTy->getElementType(),
NewPtrTy->getPointerAddressSpace());
@ -191,9 +200,28 @@ BlockGenerator::generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst,
Address = Builder.CreateBitOrPointerCast(Address, OldPtrTy);
return Address;
}
assert(
Pointer &&
"If expression was not generated, must use the original pointer value");
return getNewValue(Stmt, Pointer, BBMap, LTS, L);
}
return getNewValue(Stmt, Inst.getPointerOperand(), BBMap, LTS,
getLoopForStmt(Stmt));
Value *
BlockGenerator::getImplicitAddress(MemoryAccess &Access, Loop *L,
LoopToScevMapT &LTS, ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses) {
if (Access.isLatestArrayKind())
return generateLocationAccessed(*Access.getStatement(), L, nullptr, BBMap,
LTS, NewAccesses, Access.getId(),
Access.getAccessValue()->getType());
if (Access.isLatestValueKind() || Access.isLatestExitPHIKind())
return getOrCreateScalarAlloca(Access.getBaseAddr());
if (Access.isLatestPHIKind())
return getOrCreatePHIAlloca(Access.getBaseAddr());
llvm_unreachable("Unknown access type");
}
Loop *BlockGenerator::getLoopForStmt(const ScopStmt &Stmt) const {
@ -320,13 +348,13 @@ BasicBlock *BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB,
isl_id_to_ast_expr *NewAccesses) {
BasicBlock *CopyBB = splitBB(BB);
Builder.SetInsertPoint(&CopyBB->front());
generateScalarLoads(Stmt, BBMap);
generateScalarLoads(Stmt, LTS, BBMap, NewAccesses);
copyBB(Stmt, BB, CopyBB, BBMap, LTS, NewAccesses);
// After a basic block was copied store all scalars that escape this block in
// their alloca.
generateScalarStores(Stmt, LTS, BBMap);
generateScalarStores(Stmt, LTS, BBMap, NewAccesses);
return CopyBB;
}
@ -417,12 +445,15 @@ void BlockGenerator::handleOutsideUsers(const Scop &S, Instruction *Inst) {
EscapeMap[Inst] = std::make_pair(ScalarAddr, std::move(EscapeUsers));
}
void BlockGenerator::generateScalarLoads(ScopStmt &Stmt, ValueMapT &BBMap) {
void BlockGenerator::generateScalarLoads(
ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses) {
for (MemoryAccess *MA : Stmt) {
if (MA->isArrayKind() || MA->isWrite())
if (MA->isOriginalArrayKind() || MA->isWrite())
continue;
auto *Address = getOrCreateAlloca(*MA);
auto *Address =
getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
assert((!isa<Instruction>(Address) ||
DT.dominates(cast<Instruction>(Address)->getParent(),
Builder.GetInsertBlock())) &&
@ -432,8 +463,9 @@ void BlockGenerator::generateScalarLoads(ScopStmt &Stmt, ValueMapT &BBMap) {
}
}
void BlockGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
ValueMapT &BBMap) {
void BlockGenerator::generateScalarStores(
ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses) {
Loop *L = LI.getLoopFor(Stmt.getBasicBlock());
assert(Stmt.isBlockStmt() && "Region statements need to use the "
@ -441,7 +473,7 @@ void BlockGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
"RegionGenerator");
for (MemoryAccess *MA : Stmt) {
if (MA->isArrayKind() || MA->isRead())
if (MA->isOriginalArrayKind() || MA->isRead())
continue;
Value *Val = MA->getAccessValue();
@ -456,7 +488,8 @@ void BlockGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
"Incoming block must be statement's block");
Val = MA->getIncoming()[0].second;
}
auto *Address = getOrCreateAlloca(*MA);
auto Address =
getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
Val = getNewValue(Stmt, Val, BBMap, LTS, L);
assert((!isa<Instruction>(Val) ||
@ -1132,7 +1165,7 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
Builder.SetInsertPoint(&EntryBBCopy->front());
ValueMapT &EntryBBMap = RegionMaps[EntryBBCopy];
generateScalarLoads(Stmt, EntryBBMap);
generateScalarLoads(Stmt, LTS, EntryBBMap, IdToAstExp);
for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
if (!R->contains(*PI))
@ -1257,7 +1290,7 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
Builder.SetInsertPoint(&*ExitBBCopy->getFirstInsertionPt());
// Write values visible to other statements.
generateScalarStores(Stmt, LTS, ValueMap);
generateScalarStores(Stmt, LTS, ValueMap, IdToAstExp);
BlockMap.clear();
RegionMaps.clear();
IncompletePHINodeMap.clear();
@ -1329,18 +1362,20 @@ Value *RegionGenerator::getExitScalar(MemoryAccess *MA, LoopToScevMapT &LTS,
return getNewValue(*Stmt, OldVal, BBMap, LTS, L);
}
void RegionGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
ValueMapT &BBMap) {
void RegionGenerator::generateScalarStores(
ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
__isl_keep isl_id_to_ast_expr *NewAccesses) {
assert(Stmt.getRegion() &&
"Block statements need to use the generateScalarStores() "
"function in the BlockGenerator");
for (MemoryAccess *MA : Stmt) {
if (MA->isArrayKind() || MA->isRead())
if (MA->isOriginalArrayKind() || MA->isRead())
continue;
Value *NewVal = getExitScalar(MA, LTS, BBMap);
Value *Address = getOrCreateAlloca(*MA);
Value *Address =
getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
assert((!isa<Instruction>(NewVal) ||
DT.dominates(cast<Instruction>(NewVal)->getParent(),
Builder.GetInsertBlock())) &&

View File

@ -348,7 +348,11 @@ bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop,
isl_id *NewOutId;
if (MA->isArrayKind()) {
// If the NewAccessMap has zero dimensions, it is the scalar access; it
// must be the same as before.
// If it has at least one dimension, it's an array access; search for its
// ScopArrayInfo.
if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
@ -376,12 +380,14 @@ bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop,
bool SpecialAlignment = true;
if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
SpecialAlignment =
LoadI->getAlignment() &&
DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment();
} else if (StoreInst *StoreI =
dyn_cast<StoreInst>(MA->getAccessInstruction())) {
SpecialAlignment =
StoreI->getAlignment() &&
DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) !=
StoreI->getAlignment();
StoreI->getAlignment();
}
if (SpecialAlignment) {

View File

@ -0,0 +1,149 @@
; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-import-jscop -analyze < %s | FileCheck %s
; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-import-jscop -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
define void @map_scalar_access(double* noalias nonnull %A) {
entry:
br label %outer.for
outer.for:
%j = phi i32 [0, %entry], [%j.inc, %outer.inc]
%j.cmp = icmp slt i32 %j, 1
br i1 %j.cmp, label %reduction.for, label %outer.exit
reduction.for:
%i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
%phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
%i.cmp = icmp slt i32 %i, 4
br i1 %i.cmp, label %body, label %reduction.exit
body:
%add = fadd double %phi, 4.2
br label %reduction.inc
reduction.inc:
%i.inc = add nuw nsw i32 %i, 1
br label %reduction.for
reduction.exit:
%A_idx = getelementptr inbounds double, double* %A, i32 %j
store double %phi, double* %A_idx
br label %outer.inc
outer.inc:
%j.inc = add nuw nsw i32 %j, 1
br label %outer.for
outer.exit:
br label %return
return:
ret void
}
; CHECK: Arrays {
; CHECK-NEXT: double MemRef_phi__phi; // Element size 8
; CHECK-NEXT: double MemRef_phi; // Element size 8
; CHECK-NEXT: double MemRef_add; // Element size 8
; CHECK-NEXT: double MemRef_A[*]; // Element size 8
; CHECK-NEXT: }
; CHECK: Statements {
; CHECK-NEXT: Stmt_outer_for
; CHECK-NEXT: Domain :=
; CHECK-NEXT: { Stmt_outer_for[i0] : 0 <= i0 <= 1 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_outer_for[i0] -> [i0, 0, 0, 0] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
; CHECK-NEXT: new: { Stmt_outer_for[i0] -> MemRef_A[i0] };
; CHECK-NEXT: Stmt_reduction_for
; CHECK-NEXT: Domain :=
; CHECK-NEXT: { Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
; CHECK-NEXT: new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
; CHECK-NEXT: new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: Stmt_body
; CHECK-NEXT: Domain :=
; CHECK-NEXT: { Stmt_body[0, i1] : 0 <= i1 <= 3 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_body[i0, i1] -> [0, 1, i1, 1] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_body[i0, i1] -> MemRef_add[] };
; CHECK-NEXT: new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_body[i0, i1] -> MemRef_phi[] };
; CHECK-NEXT: new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: Stmt_reduction_inc
; CHECK-NEXT: Domain :=
; CHECK-NEXT: { Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
; CHECK-NEXT: new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
; CHECK-NEXT: new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
; CHECK-NEXT: Stmt_reduction_exit
; CHECK-NEXT: Domain :=
; CHECK-NEXT: { Stmt_reduction_exit[0] };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_reduction_exit[i0] -> [0, 2, 0, 0] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_reduction_exit[i0] -> MemRef_A[0] };
; CHECK-NEXT: new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
; CHECK-NEXT: { Stmt_reduction_exit[i0] -> MemRef_phi[] };
; CHECK-NEXT: new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
; CHECK-NEXT: }
; CHECK: New access function '{ Stmt_outer_for[i0] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
; CODEGEN: polly.stmt.outer.for:
; CODEGEN-NEXT: %polly.access.A[[R0:[0-9]*]] = getelementptr double, double* %A, i64 %polly.indvar
; CODEGEN-NEXT: store double 0.000000e+00, double* %polly.access.A[[R0]]
; CODEGEN-NEXT: br label %polly.cond
; CODEGEN: polly.stmt.reduction.exit:
; CODEGEN-NEXT: %polly.access.A[[R1:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: %polly.access.A[[R1]].reload = load double, double* %polly.access.A[[R1]]
; CODEGEN-NEXT: %polly.access.A[[R2:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: store double %polly.access.A[[R1]].reload, double* %polly.access.A[[R2]]
; CODEGEN-NEXT: br label %polly.merge
; CODEGEN: polly.stmt.reduction.for:
; CODEGEN-NEXT: %polly.access.A[[R3:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: %polly.access.A[[R3]].reload = load double, double* %polly.access.A[[R3]]
; CODEGEN-NEXT: %polly.access.A[[R4:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: store double %polly.access.A[[R3]].reload, double* %polly.access.A[[R4]]
; CODEGEN-NEXT: br label %polly.cond9
; CODEGEN: polly.stmt.body:
; CODEGEN-NEXT: %polly.access.A[[R5:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: %polly.access.A[[R5]].reload = load double, double* %polly.access.A[[R5]]
; CODEGEN-NEXT: %p_add = fadd double %polly.access.A13.reload, 4.200000e+00
; CODEGEN-NEXT: %polly.access.A[[R6:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: store double %p_add, double* %polly.access.A[[R6]]
; CODEGEN-NEXT: br label %polly.stmt.reduction.inc
; CODEGEN: polly.stmt.reduction.inc:
; CODEGEN-NEXT: %polly.access.A[[R7:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: %polly.access.A[[R7]].reload = load double, double* %polly.access.A[[R7]]
; CODEGEN-NEXT: %polly.access.A[[R8:[0-9]*]] = getelementptr double, double* %A, i64 0
; CODEGEN-NEXT: store double %polly.access.A[[R7]].reload, double* %polly.access.A[[R8]]
; CODEGEN-NEXT: br label %polly.merge10

View File

@ -0,0 +1,83 @@
{
"arrays" : [
{
"name" : "MemRef_A",
"type" : "double"
}
],
"context" : "{ : }",
"name" : "%outer.for---%return",
"statements" : [
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_outer_for[i0] -> MemRef_phi__phi[] }"
}
],
"domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
"name" : "Stmt_outer_for",
"schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi[] }"
}
],
"domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
"name" : "Stmt_reduction_for",
"schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
},
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_body[i0, i1] -> MemRef_add[] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_body[i0, i1] -> MemRef_phi[] }"
}
],
"domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
"name" : "Stmt_body",
"schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_add[] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] }"
}
],
"domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
"name" : "Stmt_reduction_inc",
"schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
},
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[0] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_reduction_exit[i0] -> MemRef_phi[] }"
}
],
"domain" : "{ Stmt_reduction_exit[0] }",
"name" : "Stmt_reduction_exit",
"schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
}
]
}

View File

@ -0,0 +1,83 @@
{
"arrays" : [
{
"name" : "MemRef_A",
"type" : "double"
}
],
"context" : "{ : }",
"name" : "%outer.for---%return",
"statements" : [
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_outer_for[i0] -> MemRef_A[i0] }"
}
],
"domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
"name" : "Stmt_outer_for",
"schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
}
],
"domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
"name" : "Stmt_reduction_for",
"schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
},
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
}
],
"domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
"name" : "Stmt_body",
"schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
}
],
"domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
"name" : "Stmt_reduction_inc",
"schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
},
{
"accesses" : [
{
"kind" : "write",
"relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
}
],
"domain" : "{ Stmt_reduction_exit[0] }",
"name" : "Stmt_reduction_exit",
"schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
}
]
}