Skip to content

Commit 326e0ee

Browse files
authored
Fix OpenMPOpt interchange and bump if (#191)
* Fix if interchange * Fix allocation region * Fix format * Fix test * Fix sizecheck * Fix affine for raising * Fix canonicalize * Fix memory issue * fix idx * Fix mem2reg switch
1 parent f117ae9 commit 326e0ee

File tree

15 files changed

+420
-101
lines changed

15 files changed

+420
-101
lines changed

lib/polygeist/Ops.cpp

Lines changed: 194 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ bool getEffectsAfter(Operation *op,
142142

143143
void BarrierOp::getEffects(
144144
SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
145+
146+
// If this doesn't synchronize any values, it has no effects.
147+
if (llvm::all_of(getOperands(), [](Value v) {
148+
IntegerAttr constValue;
149+
return matchPattern(v, m_Constant(&constValue));
150+
}))
151+
return;
152+
145153
Operation *op = getOperation();
146154

147155
if (!getEffectsBefore(op, effects))
@@ -151,6 +159,8 @@ void BarrierOp::getEffects(
151159
return;
152160
}
153161

162+
bool isReadNone(Operation *op);
163+
154164
class BarrierHoist final : public OpRewritePattern<BarrierOp> {
155165
public:
156166
using OpRewritePattern<BarrierOp>::OpRewritePattern;
@@ -162,12 +172,7 @@ class BarrierHoist final : public OpRewritePattern<BarrierOp> {
162172
bool below = true;
163173
for (Operation *it = barrier->getNextNode(); it != nullptr;
164174
it = it->getNextNode()) {
165-
auto memInterface = dyn_cast<MemoryEffectOpInterface>(it);
166-
if (!memInterface) {
167-
below = false;
168-
break;
169-
}
170-
if (!memInterface.hasNoEffect()) {
175+
if (!isReadNone(it)) {
171176
below = false;
172177
break;
173178
}
@@ -181,12 +186,7 @@ class BarrierHoist final : public OpRewritePattern<BarrierOp> {
181186
bool above = true;
182187
for (Operation *it = barrier->getPrevNode(); it != nullptr;
183188
it = it->getPrevNode()) {
184-
auto memInterface = dyn_cast<MemoryEffectOpInterface>(it);
185-
if (!memInterface) {
186-
above = false;
187-
break;
188-
}
189-
if (!memInterface.hasNoEffect()) {
189+
if (!isReadNone(it)) {
190190
above = false;
191191
break;
192192
}
@@ -198,6 +198,30 @@ class BarrierHoist final : public OpRewritePattern<BarrierOp> {
198198
return success();
199199
}
200200
}
201+
// Move barrier into after region and after loop, if possible
202+
if (auto whileOp = dyn_cast<scf::WhileOp>(barrier->getParentOp())) {
203+
if (barrier->getParentRegion() == &whileOp.getBefore()) {
204+
auto cond = whileOp.getBefore().front().getTerminator();
205+
206+
bool above = true;
207+
for (Operation *it = cond; it != nullptr; it = it->getPrevNode()) {
208+
if (it == barrier)
209+
break;
210+
if (!isReadNone(it)) {
211+
above = false;
212+
break;
213+
}
214+
}
215+
if (above) {
216+
rewriter.setInsertionPointToStart(&whileOp.getAfter().front());
217+
rewriter.create<BarrierOp>(barrier.getLoc(), barrier.getOperands());
218+
rewriter.setInsertionPoint(whileOp->getNextNode());
219+
rewriter.create<BarrierOp>(barrier.getLoc(), barrier.getOperands());
220+
rewriter.eraseOp(barrier);
221+
return success();
222+
}
223+
}
224+
}
201225
return failure();
202226
}
203227
};
@@ -1531,6 +1555,13 @@ struct MoveIntoIfs : public OpRewritePattern<scf::IfOp> {
15311555
if (!thenUse && !elseUse)
15321556
return failure();
15331557

1558+
// If this is used in an affine if/for/parallel op, do not move it, as it
1559+
// may no longer be a legal symbol
1560+
for (OpOperand &use : prevOp->getUses()) {
1561+
if (isa<AffineForOp, AffineIfOp, AffineParallelOp>(use.getOwner()))
1562+
return failure();
1563+
}
1564+
15341565
rewriter.startRootUpdate(nextIf);
15351566
rewriter.startRootUpdate(prevOp);
15361567
prevOp->moveBefore(thenUse ? &nextIf.thenBlock()->front()
@@ -1853,6 +1884,7 @@ class CmpProp final : public OpRewritePattern<CmpIOp> {
18531884
resultTypes.push_back(op.getType());
18541885

18551886
auto rhs2 = rewriter.clone(*rhs)->getResult(0);
1887+
rewriter.setInsertionPoint(ifOp);
18561888
auto nop = rewriter.create<scf::IfOp>(
18571889
ifOp.getLoc(), resultTypes, ifOp.getCondition(), /*hasElse*/ true);
18581890
nop.getThenRegion().takeBody(ifOp.getThenRegion());
@@ -1877,9 +1909,156 @@ class CmpProp final : public OpRewritePattern<CmpIOp> {
18771909
}
18781910
};
18791911

1912+
/// Given an operation, return whether this op is guaranteed to
1913+
/// allocate an AutomaticAllocationScopeResource
1914+
static bool isGuaranteedAutomaticAllocation(Operation *op) {
1915+
MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
1916+
if (!interface)
1917+
return false;
1918+
for (auto res : op->getResults()) {
1919+
if (auto effect =
1920+
interface.getEffectOnValue<MemoryEffects::Allocate>(res)) {
1921+
if (isa<SideEffects::AutomaticAllocationScopeResource>(
1922+
effect->getResource()))
1923+
return true;
1924+
}
1925+
}
1926+
return false;
1927+
}
1928+
1929+
template <typename T>
1930+
struct AlwaysAllocaScopeHoister : public OpRewritePattern<T> {
1931+
using OpRewritePattern<T>::OpRewritePattern;
1932+
1933+
LogicalResult matchAndRewrite(T top,
1934+
PatternRewriter &rewriter) const override {
1935+
1936+
Operation *op = top;
1937+
if (!op->getParentWithTrait<OpTrait::AutomaticAllocationScope>())
1938+
return failure();
1939+
1940+
Operation *lastParentWithoutScope =
1941+
op->hasTrait<OpTrait::AutomaticAllocationScope>() ? op
1942+
: op->getParentOp();
1943+
1944+
if (!lastParentWithoutScope)
1945+
return failure();
1946+
1947+
while (!lastParentWithoutScope->getParentOp()
1948+
->hasTrait<OpTrait::AutomaticAllocationScope>()) {
1949+
lastParentWithoutScope = lastParentWithoutScope->getParentOp();
1950+
if (!lastParentWithoutScope)
1951+
return failure();
1952+
}
1953+
assert(lastParentWithoutScope->getParentOp()
1954+
->hasTrait<OpTrait::AutomaticAllocationScope>());
1955+
1956+
Region *containingRegion = nullptr;
1957+
if (lastParentWithoutScope == op)
1958+
containingRegion = &op->getRegion(0);
1959+
for (auto &r : lastParentWithoutScope->getRegions()) {
1960+
if (r.isAncestor(op->getParentRegion())) {
1961+
assert(containingRegion == nullptr &&
1962+
"only one region can contain the op");
1963+
containingRegion = &r;
1964+
}
1965+
}
1966+
assert(containingRegion && "op must be contained in a region");
1967+
1968+
SmallVector<Operation *> toHoist;
1969+
op->walk<WalkOrder::PreOrder>([&](Operation *alloc) {
1970+
if (alloc != op && alloc->hasTrait<OpTrait::AutomaticAllocationScope>())
1971+
return WalkResult::skip();
1972+
1973+
if (!isGuaranteedAutomaticAllocation(alloc))
1974+
return WalkResult::advance();
1975+
1976+
// If any operand is not defined before the location of
1977+
// lastParentWithoutScope (i.e. where we would hoist to), skip.
1978+
if (llvm::any_of(alloc->getOperands(), [&](Value v) {
1979+
return containingRegion->isAncestor(v.getParentRegion());
1980+
}))
1981+
return WalkResult::skip();
1982+
toHoist.push_back(alloc);
1983+
return WalkResult::advance();
1984+
});
1985+
1986+
if (toHoist.empty())
1987+
return failure();
1988+
rewriter.setInsertionPoint(lastParentWithoutScope);
1989+
for (auto *op : toHoist) {
1990+
auto *cloned = rewriter.clone(*op);
1991+
rewriter.replaceOp(op, cloned->getResults());
1992+
}
1993+
return success();
1994+
}
1995+
};
1996+
1997+
static bool isOpItselfPotentialAutomaticAllocation(Operation *op) {
1998+
// This op itself doesn't create a stack allocation,
1999+
// the inner allocation should be handled separately.
2000+
if (op->hasTrait<OpTrait::HasRecursiveSideEffects>())
2001+
return false;
2002+
MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
2003+
if (!interface)
2004+
return true;
2005+
for (auto res : op->getResults()) {
2006+
if (auto effect =
2007+
interface.getEffectOnValue<MemoryEffects::Allocate>(res)) {
2008+
if (isa<SideEffects::AutomaticAllocationScopeResource>(
2009+
effect->getResource()))
2010+
return true;
2011+
}
2012+
}
2013+
return false;
2014+
}
2015+
2016+
struct AggressiveAllocaScopeInliner
2017+
: public OpRewritePattern<memref::AllocaScopeOp> {
2018+
using OpRewritePattern<memref::AllocaScopeOp>::OpRewritePattern;
2019+
2020+
LogicalResult matchAndRewrite(memref::AllocaScopeOp op,
2021+
PatternRewriter &rewriter) const override {
2022+
bool hasPotentialAlloca =
2023+
op->walk<WalkOrder::PreOrder>([&](Operation *alloc) {
2024+
if (alloc == op || isa<LLVM::CallOp>(alloc) ||
2025+
isa<func::CallOp>(alloc))
2026+
return WalkResult::advance();
2027+
if (isOpItselfPotentialAutomaticAllocation(alloc))
2028+
return WalkResult::interrupt();
2029+
if (alloc->hasTrait<OpTrait::AutomaticAllocationScope>())
2030+
return WalkResult::skip();
2031+
return WalkResult::advance();
2032+
}).wasInterrupted();
2033+
2034+
// If this contains no potential allocation, it is always legal to
2035+
// inline. Otherwise, consider two conditions:
2036+
if (hasPotentialAlloca) {
2037+
// If the parent isn't an allocation scope, or we are not the last
2038+
// non-terminator op in the parent, we will extend the lifetime.
2039+
if (!op->getParentOp()->hasTrait<OpTrait::AutomaticAllocationScope>())
2040+
return failure();
2041+
// if (!lastNonTerminatorInRegion(op))
2042+
// return failure();
2043+
}
2044+
2045+
Block *block = &op.getRegion().front();
2046+
Operation *terminator = block->getTerminator();
2047+
ValueRange results = terminator->getOperands();
2048+
rewriter.mergeBlockBefore(block, op);
2049+
rewriter.replaceOp(op, results);
2050+
rewriter.eraseOp(terminator);
2051+
return success();
2052+
}
2053+
};
2054+
18802055
void TypeAlignOp::getCanonicalizationPatterns(RewritePatternSet &results,
18812056
MLIRContext *context) {
1882-
results.insert<TypeAlignCanonicalize, OrIExcludedMiddle, SelectI1Ext,
1883-
UndefProp<ExtUIOp>, UndefProp<ExtSIOp>, UndefProp<TruncIOp>,
1884-
CmpProp, UndefCmpProp>(context);
2057+
results.insert<
2058+
TypeAlignCanonicalize, OrIExcludedMiddle, SelectI1Ext, UndefProp<ExtUIOp>,
2059+
UndefProp<ExtSIOp>, UndefProp<TruncIOp>, CmpProp, UndefCmpProp,
2060+
AlwaysAllocaScopeHoister<memref::AllocaScopeOp>,
2061+
AlwaysAllocaScopeHoister<scf::ForOp>,
2062+
AlwaysAllocaScopeHoister<AffineForOp>, AggressiveAllocaScopeInliner>(
2063+
context);
18852064
}

lib/polygeist/Passes/AffineCFG.cpp

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -189,17 +189,7 @@ AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map,
189189
auto t = operands[i];
190190
if (!isValidSymbolInt(t, /*recur*/ false)) {
191191
while (auto idx = t.getDefiningOp<IndexCastOp>()) {
192-
if (idx.getIn().getDefiningOp<ConstantIntOp>() ||
193-
idx.getIn().getDefiningOp<ConstantIndexOp>() ||
194-
idx.getIn().getDefiningOp<AddIOp>() ||
195-
idx.getIn().getDefiningOp<SubIOp>() ||
196-
idx.getIn().getDefiningOp<MulIOp>() ||
197-
idx.getIn().getDefiningOp<DivSIOp>() ||
198-
idx.getIn().getDefiningOp<DivUIOp>() ||
199-
idx.getIn().getDefiningOp<RemUIOp>())
200-
t = idx.getIn();
201-
else
202-
break;
192+
t = idx.getIn();
203193
}
204194
}
205195

@@ -325,7 +315,7 @@ AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map,
325315
auxiliaryExprs.push_back(affineApplyMap.getResult(0));
326316
} else {
327317
if (!isValidSymbolInt(t, /*recur*/ false)) {
328-
if (auto idx = t.getDefiningOp<IndexCastOp>()) {
318+
if (auto idx = t.getDefiningOp()) {
329319
auto scope = getAffineScope(idx)->getParentOp();
330320
DominanceInfo DI(scope);
331321

@@ -367,10 +357,10 @@ AffineApplyNormalizer::AffineApplyNormalizer(AffineMap map,
367357
op->moveAfter(front);
368358
return true;
369359
};
370-
if (fix(idx))
371-
assert(isValidSymbolInt(idx, /*recur*/ false));
360+
if (fix(t))
361+
assert(isValidSymbolInt(t, /*recur*/ false));
372362
else
373-
t = idx.getIn();
363+
assert(0 && "cannot move");
374364
} else
375365
assert(0 && "cannot move");
376366
}
@@ -472,9 +462,8 @@ bool need(AffineMap *map, SmallVectorImpl<Value> *operands) {
472462
assert(map->getNumInputs() == operands->size());
473463
for (size_t i = 0; i < map->getNumInputs(); ++i) {
474464
auto v = (*operands)[i];
475-
if (legalCondition(v, i < map->getNumDims())) {
465+
if (legalCondition(v, i < map->getNumDims()))
476466
return true;
477-
}
478467
}
479468
return false;
480469
}
@@ -491,7 +480,18 @@ void fully2ComposeAffineMapAndOperands(OpBuilder &builder, AffineMap *map,
491480
SmallVectorImpl<Value> *operands) {
492481
BlockAndValueMapping indexMap;
493482
for (auto op : *operands) {
494-
if (auto idx = op.getDefiningOp<IndexCastOp>()) {
483+
SmallVector<IndexCastOp> attempt;
484+
auto idx0 = op.getDefiningOp<IndexCastOp>();
485+
attempt.push_back(idx0);
486+
if (!idx0)
487+
continue;
488+
489+
for (auto &u : idx0.getIn().getUses()) {
490+
if (auto idx = dyn_cast<IndexCastOp>(u.getOwner()))
491+
attempt.push_back(idx);
492+
}
493+
494+
for (auto idx : attempt) {
495495
Operation *start = idx;
496496
bool immediate = false;
497497

@@ -513,22 +513,16 @@ void fully2ComposeAffineMapAndOperands(OpBuilder &builder, AffineMap *map,
513513
}
514514
break;
515515
}
516-
if (immediate)
516+
if (immediate) {
517517
indexMap.map(idx.getIn(), idx);
518+
break;
519+
}
518520
}
519521
}
520522
assert(map->getNumInputs() == operands->size());
521523
while (need(map, operands)) {
522-
// llvm::errs() << "pre: " << *map << "\n";
523-
// for(auto op : *operands) {
524-
// llvm::errs() << " -- operands: " << op << "\n";
525-
//}
526524
composeAffineMapAndOperands(map, operands);
527525
assert(map->getNumInputs() == operands->size());
528-
// llvm::errs() << "post: " << *map << "\n";
529-
// for(auto op : *operands) {
530-
// llvm::errs() << " -- operands: " << op << "\n";
531-
//}
532526
}
533527
for (auto &op : *operands) {
534528
if (!op.getType().isIndex()) {

lib/polygeist/Passes/CanonicalizeFor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,12 @@ struct WhileToForHelper {
442442
}
443443

444444
// Before region contains more than just the comparison
445-
if (sizeCheck) {
445+
{
446446
size_t size = loop.getBefore().front().getOperations().size();
447447
if (extType)
448448
size--;
449+
if (!sizeCheck)
450+
size--;
449451
if (size != 2) {
450452
return false;
451453
}

lib/polygeist/Passes/LoopRestructure.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,8 @@ void LoopRestructure::runOnRegion(DominanceInfo &domInfo, Region &region) {
655655
Block *block = &insertRegion.front();
656656
IRRewriter B(exec->getContext());
657657
Operation *terminator = block->getTerminator();
658-
ValueRange results = terminator->getOperands();
658+
SmallVector<Value> results;
659+
llvm::append_range(results, terminator->getOperands());
659660
terminator->erase();
660661
B.mergeBlockBefore(block, exec);
661662
exec.replaceAllUsesWith(results);

0 commit comments

Comments
 (0)