[Polly] [BlockGen] Support partial writes in regions

Summary:
The RegionGenerator traditionally kept a BlockMap that mapped from original
basic blocks to newly generated basic blocks. With the introduction of partial
writes such a 1:1 mapping is not possible any more, as a single basic block
can be code generated into multiple basic blocks. Hence, depending on the use
case we need to either use the first basic block or the last basic block.

This is intended to address the last four cases of incorrect code generation
in our AOSP buildbot and hopefully should turn it green.

Reviewers: Meinersbur, bollu, gareevroman, efriedma, huihuiz, sebpop, simbuerg

Reviewed By: Meinersbur

Subscribers: pollydev, llvm-commits

Tags: #polly

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

llvm-svn: 304808
This commit is contained in:
Tobias Grosser 2017-06-06 17:17:30 +00:00
parent eafdd862e5
commit deefbced96
8 changed files with 400 additions and 38 deletions

View File

@ -795,10 +795,17 @@ public:
__isl_keep isl_id_to_ast_expr *IdToAstExp);
private:
/// A map from old to new blocks in the region.
DenseMap<BasicBlock *, BasicBlock *> BlockMap;
/// A map from old to the first new block in the region, that was created to
/// model the old basic block.
DenseMap<BasicBlock *, BasicBlock *> StartBlockMap;
/// The "BBMaps" for the whole region (one for each block).
/// A map from old to the last new block in the region, that was created to
/// model the old basic block.
DenseMap<BasicBlock *, BasicBlock *> EndBlockMap;
/// The "BBMaps" for the whole region (one for each block). In case a basic
/// block is code generated to multiple basic blocks (e.g., for partial
/// writes), the StartBasic is used as index for the RegionMap.
DenseMap<BasicBlock *, ValueMapT> RegionMaps;
/// Mapping to remember PHI nodes that still need incoming values.

View File

@ -1273,12 +1273,12 @@ BasicBlock *RegionGenerator::repairDominance(BasicBlock *BB,
BasicBlock *BBCopy) {
BasicBlock *BBIDom = DT.getNode(BB)->getIDom()->getBlock();
BasicBlock *BBCopyIDom = BlockMap.lookup(BBIDom);
BasicBlock *BBCopyIDom = EndBlockMap.lookup(BBIDom);
if (BBCopyIDom)
DT.changeImmediateDominator(BBCopy, BBCopyIDom);
return BBCopyIDom;
return StartBlockMap.lookup(BBIDom);
}
// This is to determine whether an llvm::Value (defined in @p BB) is usable when
@ -1331,7 +1331,8 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
"Only region statements can be copied by the region generator");
// Forget all old mappings.
BlockMap.clear();
StartBlockMap.clear();
EndBlockMap.clear();
RegionMaps.clear();
IncompletePHINodeMap.clear();
@ -1353,8 +1354,10 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
generateScalarLoads(Stmt, LTS, EntryBBMap, IdToAstExp);
for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
if (!R->contains(*PI))
BlockMap[*PI] = EntryBBCopy;
if (!R->contains(*PI)) {
StartBlockMap[*PI] = EntryBBCopy;
EndBlockMap[*PI] = EntryBBCopy;
}
// Iterate over all blocks in the region in a breadth-first search.
std::deque<BasicBlock *> Blocks;
@ -1388,7 +1391,8 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
copyBB(Stmt, BB, BBCopy, RegionMap, LTS, IdToAstExp);
// In order to remap PHI nodes we store also basic block mappings.
BlockMap[BB] = BBCopy;
StartBlockMap[BB] = BBCopy;
EndBlockMap[BB] = Builder.GetInsertBlock();
// Add values to incomplete PHI nodes waiting for this block to be copied.
for (const PHINodePairTy &PHINodePair : IncompletePHINodeMap[BB])
@ -1409,9 +1413,10 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
BasicBlock *ExitBBCopy = SplitBlock(Builder.GetInsertBlock(),
&*Builder.GetInsertPoint(), &DT, &LI);
ExitBBCopy->setName("polly.stmt." + R->getExit()->getName() + ".exit");
BlockMap[R->getExit()] = ExitBBCopy;
StartBlockMap[R->getExit()] = ExitBBCopy;
EndBlockMap[R->getExit()] = ExitBBCopy;
BasicBlock *ExitDomBBCopy = BlockMap.lookup(findExitDominator(DT, R));
BasicBlock *ExitDomBBCopy = EndBlockMap.lookup(findExitDominator(DT, R));
assert(ExitDomBBCopy &&
"Common exit dominator must be within region; at least the entry node "
"must match");
@ -1421,19 +1426,20 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
// region control flow by hand after all blocks have been copied.
for (BasicBlock *BB : SeenBlocks) {
BasicBlock *BBCopy = BlockMap[BB];
BasicBlock *BBCopyStart = StartBlockMap[BB];
BasicBlock *BBCopyEnd = EndBlockMap[BB];
TerminatorInst *TI = BB->getTerminator();
if (isa<UnreachableInst>(TI)) {
while (!BBCopy->empty())
BBCopy->begin()->eraseFromParent();
new UnreachableInst(BBCopy->getContext(), BBCopy);
while (!BBCopyEnd->empty())
BBCopyEnd->begin()->eraseFromParent();
new UnreachableInst(BBCopyEnd->getContext(), BBCopyEnd);
continue;
}
Instruction *BICopy = BBCopy->getTerminator();
Instruction *BICopy = BBCopyEnd->getTerminator();
ValueMapT &RegionMap = RegionMaps[BBCopy];
RegionMap.insert(BlockMap.begin(), BlockMap.end());
ValueMapT &RegionMap = RegionMaps[BBCopyStart];
RegionMap.insert(StartBlockMap.begin(), StartBlockMap.end());
Builder.SetInsertPoint(BICopy);
copyInstScalar(Stmt, TI, RegionMap, LTS);
@ -1447,7 +1453,7 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
if (L == nullptr || L->getHeader() != BB || !R->contains(L))
continue;
BasicBlock *BBCopy = BlockMap[BB];
BasicBlock *BBCopy = StartBlockMap[BB];
Value *NullVal = Builder.getInt32(0);
PHINode *LoopPHI =
PHINode::Create(Builder.getInt32Ty(), 2, "polly.subregion.iv");
@ -1460,9 +1466,9 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
if (!R->contains(PredBB))
continue;
if (L->contains(PredBB))
LoopPHI->addIncoming(LoopPHIInc, BlockMap[PredBB]);
LoopPHI->addIncoming(LoopPHIInc, EndBlockMap[PredBB]);
else
LoopPHI->addIncoming(NullVal, BlockMap[PredBB]);
LoopPHI->addIncoming(NullVal, EndBlockMap[PredBB]);
}
for (auto *PredBBCopy : make_range(pred_begin(BBCopy), pred_end(BBCopy)))
@ -1477,7 +1483,8 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
// Write values visible to other statements.
generateScalarStores(Stmt, LTS, ValueMap, IdToAstExp);
BlockMap.clear();
StartBlockMap.clear();
EndBlockMap.clear();
RegionMaps.clear();
IncompletePHINodeMap.clear();
}
@ -1497,7 +1504,7 @@ PHINode *RegionGenerator::buildExitPHI(MemoryAccess *MA, LoopToScevMapT &LTS,
if (OrigPHI->getParent() != SubR->getExit()) {
BasicBlock *FormerExit = SubR->getExitingBlock();
if (FormerExit)
NewSubregionExit = BlockMap.lookup(FormerExit);
NewSubregionExit = StartBlockMap.lookup(FormerExit);
}
PHINode *NewPHI = PHINode::Create(OrigPHI->getType(), Incoming.size(),
@ -1507,15 +1514,17 @@ PHINode *RegionGenerator::buildExitPHI(MemoryAccess *MA, LoopToScevMapT &LTS,
// Add the incoming values to the PHI.
for (auto &Pair : Incoming) {
BasicBlock *OrigIncomingBlock = Pair.first;
BasicBlock *NewIncomingBlock = BlockMap.lookup(OrigIncomingBlock);
Builder.SetInsertPoint(NewIncomingBlock->getTerminator());
assert(RegionMaps.count(NewIncomingBlock));
ValueMapT *LocalBBMap = &RegionMaps[NewIncomingBlock];
BasicBlock *NewIncomingBlockStart = StartBlockMap.lookup(OrigIncomingBlock);
BasicBlock *NewIncomingBlockEnd = EndBlockMap.lookup(OrigIncomingBlock);
Builder.SetInsertPoint(NewIncomingBlockEnd->getTerminator());
assert(RegionMaps.count(NewIncomingBlockStart));
assert(RegionMaps.count(NewIncomingBlockEnd));
ValueMapT *LocalBBMap = &RegionMaps[NewIncomingBlockStart];
Value *OrigIncomingValue = Pair.second;
Value *NewIncomingValue =
getNewValue(*Stmt, OrigIncomingValue, *LocalBBMap, LTS, L);
NewPHI->addIncoming(NewIncomingValue, NewIncomingBlock);
NewPHI->addIncoming(NewIncomingValue, NewIncomingBlockEnd);
}
return NewPHI;
@ -1584,16 +1593,19 @@ void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, PHINode *PHI,
LoopToScevMapT &LTS) {
// If the incoming block was not yet copied mark this PHI as incomplete.
// Once the block will be copied the incoming value will be added.
BasicBlock *BBCopy = BlockMap[IncomingBB];
if (!BBCopy) {
BasicBlock *BBCopyStart = StartBlockMap[IncomingBB];
BasicBlock *BBCopyEnd = EndBlockMap[IncomingBB];
if (!BBCopyStart) {
assert(!BBCopyEnd);
assert(Stmt.contains(IncomingBB) &&
"Bad incoming block for PHI in non-affine region");
IncompletePHINodeMap[IncomingBB].push_back(std::make_pair(PHI, PHICopy));
return;
}
assert(RegionMaps.count(BBCopy) && "Incoming PHI block did not have a BBMap");
ValueMapT &BBCopyMap = RegionMaps[BBCopy];
assert(RegionMaps.count(BBCopyStart) &&
"Incoming PHI block did not have a BBMap");
ValueMapT &BBCopyMap = RegionMaps[BBCopyStart];
Value *OpCopy = nullptr;
@ -1603,17 +1615,17 @@ void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, PHINode *PHI,
// If the current insert block is different from the PHIs incoming block
// change it, otherwise do not.
auto IP = Builder.GetInsertPoint();
if (IP->getParent() != BBCopy)
Builder.SetInsertPoint(BBCopy->getTerminator());
if (IP->getParent() != BBCopyEnd)
Builder.SetInsertPoint(BBCopyEnd->getTerminator());
OpCopy = getNewValue(Stmt, Op, BBCopyMap, LTS, getLoopForStmt(Stmt));
if (IP->getParent() != BBCopy)
if (IP->getParent() != BBCopyEnd)
Builder.SetInsertPoint(&*IP);
} else {
// All edges from outside the non-affine region become a single edge
// in the new copy of the non-affine region. Make sure to only add the
// corresponding edge the first time we encounter a basic block from
// outside the non-affine region.
if (PHICopy->getBasicBlockIndex(BBCopy) >= 0)
if (PHICopy->getBasicBlockIndex(BBCopyEnd) >= 0)
return;
// Get the reloaded value.
@ -1621,8 +1633,7 @@ void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, PHINode *PHI,
}
assert(OpCopy && "Incoming PHI value was not copied properly");
assert(BBCopy && "Incoming PHI block was not copied properly");
PHICopy->addIncoming(OpCopy, BBCopy);
PHICopy->addIncoming(OpCopy, BBCopyEnd);
}
void RegionGenerator::copyPHIInstruction(ScopStmt &Stmt, PHINode *PHI,

View File

@ -0,0 +1,68 @@
; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S \
; RUN: -polly-import-jscop-postfix=transformed -polly-codegen \
; RUN: -verify-dom-info \
; RUN: -S < %s | FileCheck %s
;
; void foo(long A[], float B[], float C[]) {
; for (long i = 0; i < 1024; i++) {
; if (A[i]) {
; S: B[i]++;
; T: C[42] = 1;
; }
; }
; }
; CHECK: polly.stmt.bb5: ; preds = %polly.stmt.bb2
; CHECK-NEXT: %scevgep10 = getelementptr float, float* %B, i64 %polly.indvar
; CHECK-NEXT: %tmp7_p_scalar_ = load float, float* %scevgep10
; CHECK-NEXT: %p_tmp8 = fadd float %tmp7_p_scalar_, 1.000000e+00
; CHECK-NEXT: %24 = icmp sle i64 %polly.indvar, 9
; CHECK-NEXT: %polly.Stmt_bb2__TO__bb9_MayWrite2.cond = icmp ne i1 %24, false
; CHECK-NEXT: br i1 %polly.Stmt_bb2__TO__bb9_MayWrite2.cond, label %polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial, label %polly.stmt.bb5.cont
; CHECK: polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial: ; preds = %polly.stmt.bb5
; CHECK-NEXT: %polly.access.B11 = getelementptr float, float* %B, i64 %polly.indvar
; CHECK-NEXT: store float %p_tmp8, float* %polly.access.B11
; CHECK-NEXT: br label %polly.stmt.bb5.cont
; CHECK: polly.stmt.bb5.cont: ; preds = %polly.stmt.bb5, %polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial
; CHECK-NEXT: br label %polly.stmt.bb9b
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @partial_write_in_region(i64* %A, float* %B, float* %C) {
bb:
br label %bb1
bb1: ; preds = %bb10, %bb
%i.0 = phi i64 [ 0, %bb ], [ %tmp11, %bb10 ]
%exitcond = icmp ne i64 %i.0, 1024
br i1 %exitcond, label %bb2, label %bb12
bb2: ; preds = %bb1
%tmp = getelementptr inbounds i64, i64* %A, i64 %i.0
%tmp3 = load i64, i64* %tmp, align 8
%tmp4 = icmp eq i64 %tmp3, 0
br i1 %tmp4, label %bb9, label %bb5
bb5: ; preds = %bb2
%tmp6 = getelementptr inbounds float, float* %B, i64 %i.0
%tmp7 = load float, float* %tmp6, align 4
%tmp8 = fadd float %tmp7, 1.000000e+00
store float %tmp8, float* %tmp6, align 4
br label %bb9b
bb9b:
store float 42.0, float* %C
br label %bb9
bb9: ; preds = %bb2, %bb5
br label %bb10
bb10: ; preds = %bb9
%tmp11 = add nuw nsw i64 %i.0, 1
br label %bb1
bb12: ; preds = %bb1
ret void
}

View File

@ -0,0 +1,46 @@
{
"arrays" : [
{
"name" : "MemRef_A",
"sizes" : [ "*" ],
"type" : "i64"
},
{
"name" : "MemRef_B",
"sizes" : [ "*" ],
"type" : "float"
},
{
"name" : "MemRef_C",
"sizes" : [ "*" ],
"type" : "float"
}
],
"context" : "{ : }",
"name" : "%bb1---%bb12",
"statements" : [
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_A[i0] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_C[0] }"
}
],
"domain" : "{ Stmt_bb2__TO__bb9[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb2__TO__bb9",
"schedule" : "{ Stmt_bb2__TO__bb9[i0] -> [i0] }"
}
]
}

View File

@ -0,0 +1,46 @@
{
"arrays" : [
{
"name" : "MemRef_A",
"sizes" : [ "*" ],
"type" : "i64"
},
{
"name" : "MemRef_B",
"sizes" : [ "*" ],
"type" : "float"
},
{
"name" : "MemRef_C",
"sizes" : [ "*" ],
"type" : "float"
}
],
"context" : "{ : }",
"name" : "%bb1---%bb12",
"statements" : [
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_A[i0] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] : i0 < 10}"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_C[0] }"
}
],
"domain" : "{ Stmt_bb2__TO__bb9[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb2__TO__bb9",
"schedule" : "{ Stmt_bb2__TO__bb9[i0] -> [i0] }"
}
]
}

View File

@ -0,0 +1,80 @@
; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S \
; RUN: -polly-import-jscop-postfix=transformed -polly-codegen \
; RUN: -verify-dom-info -polly-allow-nonaffine-loops \
; RUN: -S < %s | FileCheck %s
; This test verifies that partial writes within non-affine loops are code
; generated correctly.
; CHECK:polly.stmt.bb3:
; CHECK-NEXT: %polly.subregion.iv = phi i32 [ %polly.subregion.iv.inc, %polly.stmt.bb5.cont ], [ 0, %polly.stmt.bb3.entry ]
; CHECK-NEXT: %polly.j.0 = phi i64 [ %j.0.phiops.reload, %polly.stmt.bb3.entry ], [ %p_tmp10, %polly.stmt.bb5.cont ]
; CHECK-NEXT: %p_tmp = mul nsw i64 %polly.indvar, %polly.indvar
; CHECK-NEXT: %p_tmp4 = icmp slt i64 %polly.j.0, %p_tmp
; CHECK-NEXT: %polly.subregion.iv.inc = add i32 %polly.subregion.iv, 1
; CHECK-NEXT: br i1 %p_tmp4, label %polly.stmt.bb5, label %polly.stmt.bb11.exit
; CHECK:polly.stmt.bb5:
; CHECK-NEXT: %p_tmp6 = getelementptr inbounds float, float* %B, i64 42
; CHECK-NEXT: %tmp7_p_scalar_ = load float, float* %p_tmp6
; CHECK-NEXT: %p_tmp8 = fadd float %tmp7_p_scalar_, 1.000000e+00
; CHECK-NEXT: %8 = icmp sle i64 %polly.indvar, 9
; CHECK-NEXT: %polly.Stmt_bb3__TO__bb11_MayWrite2.cond = icmp ne i1 %8, false
; CHECK-NEXT: br i1 %polly.Stmt_bb3__TO__bb11_MayWrite2.cond, label %polly.stmt.bb5.Stmt_bb3__TO__bb11_MayWrite2.partial, label %polly.stmt.bb5.cont
; CHECK:polly.stmt.bb5.Stmt_bb3__TO__bb11_MayWrite2.partial: ; preds = %polly.stmt.bb5
; CHECK-NEXT: %polly.access.B3 = getelementptr float, float* %B, i64 42
; CHECK-NEXT: store float %p_tmp8, float* %polly.access.B3
; CHECK-NEXT: br label %polly.stmt.bb5.cont
; CHECK:polly.stmt.bb5.cont:
; CHECK-NEXT: %p_tmp10 = add nuw nsw i64 %polly.j.0, 1
; CHECK-NEXT: br label %polly.stmt.bb3
; void foo(long A[], float B[], long *x) {
; for (long i = 0; i < 1024; i++)
; for (long j = *x; j < i * i; j++)
; B[42]++;
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @partial_write_in_region_with_loop(i64* %A, float* %B, i64* %xptr) {
bb:
br label %bb1
bb1: ; preds = %bb12, %bb
%i.0 = phi i64 [ 0, %bb ], [ %tmp13, %bb12 ]
%exitcond = icmp ne i64 %i.0, 1024
br i1 %exitcond, label %bb2, label %bb14
bb2: ; preds = %bb1
%x = load i64, i64* %xptr
br label %bb3
bb3: ; preds = %bb9, %bb2
%j.0 = phi i64 [ %x, %bb2 ], [ %tmp10, %bb5 ]
%tmp = mul nsw i64 %i.0, %i.0
%tmp4 = icmp slt i64 %j.0, %tmp
br i1 %tmp4, label %bb5, label %bb11
bb5: ; preds = %bb3
%tmp6 = getelementptr inbounds float, float* %B, i64 42
%tmp7 = load float, float* %tmp6, align 4
%tmp8 = fadd float %tmp7, 1.000000e+00
store float %tmp8, float* %tmp6, align 4
%tmp10 = add nuw nsw i64 %j.0, 1
br label %bb3
bb11: ; preds = %bb3
br label %bb12
bb12: ; preds = %bb11
%tmp13 = add nuw nsw i64 %i.0, 1
br label %bb1
bb14: ; preds = %bb1
ret void
}

View File

@ -0,0 +1,52 @@
{
"arrays" : [
{
"name" : "MemRef_xptr",
"sizes" : [ "*" ],
"type" : "i64"
},
{
"name" : "MemRef_B",
"sizes" : [ "*" ],
"type" : "float"
}
],
"context" : "{ : }",
"name" : "%bb1---%bb14",
"statements" : [
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb2[i0] -> MemRef_xptr[0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2[i0] -> MemRef_j_0__phi[] }"
}
],
"domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb2",
"schedule" : "{ Stmt_bb2[i0] -> [i0, 0] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_j_0__phi[] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
}
],
"domain" : "{ Stmt_bb3__TO__bb11[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb3__TO__bb11",
"schedule" : "{ Stmt_bb3__TO__bb11[i0] -> [i0, 1] }"
}
]
}

View File

@ -0,0 +1,52 @@
{
"arrays" : [
{
"name" : "MemRef_xptr",
"sizes" : [ "*" ],
"type" : "i64"
},
{
"name" : "MemRef_B",
"sizes" : [ "*" ],
"type" : "float"
}
],
"context" : "{ : }",
"name" : "%bb1---%bb14",
"statements" : [
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb2[i0] -> MemRef_xptr[0] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb2[i0] -> MemRef_j_0__phi[] }"
}
],
"domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb2",
"schedule" : "{ Stmt_bb2[i0] -> [i0, 0] }"
},
{
"accesses" : [
{
"kind" : "read",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_j_0__phi[] }"
},
{
"kind" : "read",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
},
{
"kind" : "write",
"relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] : i0 < 10 }"
}
],
"domain" : "{ Stmt_bb3__TO__bb11[i0] : 0 <= i0 <= 1023 }",
"name" : "Stmt_bb3__TO__bb11",
"schedule" : "{ Stmt_bb3__TO__bb11[i0] -> [i0, 1] }"
}
]
}