Skip to content

Commit 8fb4b97

Browse files
committed
removed memInit and refactored LICM
1 parent 0c23f0c commit 8fb4b97

File tree

6 files changed

+353
-91
lines changed

6 files changed

+353
-91
lines changed

mlir/include/mlir/Interfaces/SideEffectInterfaces.h

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define MLIR_INTERFACES_SIDEEFFECTINTERFACES_H
1616

1717
#include "mlir/IR/OpDefinition.h"
18+
#include "mlir/IR/Dominance.h"
1819

1920
namespace mlir {
2021
namespace SideEffects {
@@ -378,12 +379,6 @@ struct Read : public Effect::Base<Read> {};
378379
/// dereference or read.
379380
struct Write : public Effect::Base<Write> {};
380381

381-
// The following effect indicates that the operation initializes some
382-
// memory resource to a known value i.e., an idempotent MemWrite.
383-
// An 'init' effect implies only mutating a resource in a way that's
384-
// identical across calls if inputs are the same, and not any visible
385-
// dereference or read.
386-
struct Init : public Effect::Base<Init> {};
387382
} // namespace MemoryEffects
388383

389384
//===----------------------------------------------------------------------===//
@@ -428,13 +423,15 @@ bool isOpTriviallyDead(Operation *op);
428423
/// Note: Terminators and symbols are never considered to be trivially dead.
429424
bool wouldOpBeTriviallyDead(Operation *op);
430425

431-
/// Returns true if the given operation is movable under memory effects.
426+
/// Returns true if the given operation is allowed to be moved under the
427+
/// memory effects interface.
432428
///
433-
/// An operation is movable if any of the following are true:
434-
/// (1) isMemoryEffectFree(op) --> true
435-
/// (2) isMemoryInitMovable(op) --> true
429+
/// An operation is movable if either case is true:
430+
/// (a) free of memory effects as defined in isMemoryEffectFree()
431+
/// (b) if the operation does have memory effects, it must be conflict-free
432+
/// as defined in isMemoryEffectConflictFree()
436433
///
437-
/// If the operation meets either criteria, then it is movable
434+
/// If the operation meets either criteria, then it is movable under memory effects
438435
bool isMemoryEffectMovable(Operation *op);
439436

440437
/// Returns true if the given operation is free of memory effects.
@@ -449,32 +446,32 @@ bool isMemoryEffectMovable(Operation *op);
449446
/// conditions are satisfied.
450447
bool isMemoryEffectFree(Operation *op);
451448

452-
/// Returns true if the given operation has a collision-free 'Init' memory
453-
/// effect.
449+
/// Returns true if the given operation has conflict-free write effects
454450
///
455-
/// An operation is movable if:
456-
/// (1) it has memory effects AND all of its memory effects are of type 'Init'
457-
/// (2) there are no other ops with memory effects on any ofthose same resources
458-
/// within the operation's region(s)
451+
/// An operation is conflict free:
452+
/// (1) all of its memory effects are of type Write
453+
/// (2) there are no other ops with Alloc/Free/Write effects on the same
454+
/// resources within the ops parent region
455+
/// (3) all ops in the parent region with Read effects on the same resources
456+
/// are dominated by the operation
459457
///
460-
/// If the operation meets both criteria, then it is movable
461-
bool isMemoryInitMovable(Operation *op);
458+
/// If the operation meets all 3 criteria, then it is conflict free
459+
bool isMemoryEffectConflictFree(Operation *op);
462460

463-
/// Returns true if op and all operations within its nested regions
464-
/// have >1 Memory Effects on ANY of the input resources.
461+
/// Returns true if op and/or any operations within its nested regions
462+
/// have a memory effect conflict with mainOp as defined below:
465463
///
466-
/// The first call to this function is by an op with >=1 MemInit effect on
467-
/// >=1 unique resources. To check that none of these resources are in conflict
468-
/// with other Memory Effects, we scan the entire parent region and maintain
469-
/// a count of Memory Effects that apply to the resources of the original op.
470-
/// If any resource has more than 1 Memory Effect in that region, the resource
471-
/// is in conflict and the op can't be moved by LICM.
464+
/// op has a memory effect conflict with mainOp if op and/or any of
465+
/// the operations in its nested regions meet any of these criteria:
466+
/// (a) they have any Alloc/Free/Write effects on the resources used by mainOp
467+
/// (b) they dominate mainOp and have any read effect on the resources used by mainOp
472468
///
473469
/// Function mutates resources map
474470
///
475-
/// If no resources are in conflict, the op is movable.
476-
bool hasMemoryEffectInitConflict(
477-
Operation *op, DenseMap<TypeID, int> &resourceCounts);
471+
/// If none of the critera above are met, mainOp and op are conflict free
472+
bool hasMemoryEffectConflict(
473+
Operation *mainOp, Operation *op,
474+
mlir::DominanceInfo &dom, DenseMap<TypeID, int> &resourceCounts);
478475

479476
/// Returns the side effects of an operation. If the operation has
480477
/// RecursiveMemoryEffects, include all side effects of child operations.

mlir/include/mlir/Interfaces/SideEffectInterfaces.td

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,6 @@ def MemWrite : MemWrite<DefaultResource, 0, PartialEffect>;
8787
class MemWriteAt<int stage, EffectRange range = PartialEffect>
8888
: MemWrite<DefaultResource, stage, range>;
8989

90-
// The following effect indicates that the operation initializes some
91-
// memory resource to a known value i.e., an idempotent MemWrite.
92-
// An 'init' effect implies only mutating a resource in a way that's
93-
// identical across calls if inputs are the same, and not any visible
94-
// dereference or read.
95-
class MemInit<Resource resource, int stage = 0,
96-
EffectRange range = PartialEffect>
97-
: MemoryEffect<"::mlir::MemoryEffects::Init", resource, stage, range>;
98-
def MemInit : MemInit<DefaultResource, 0, PartialEffect>;
99-
class MemInitAt<int stage, EffectRange range = PartialEffect>
100-
: MemInit<DefaultResource, stage, range>;
10190

10291
//===----------------------------------------------------------------------===//
10392
// Effect Traits

mlir/lib/Interfaces/SideEffectInterfaces.cpp

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "mlir/Interfaces/SideEffectInterfaces.h"
1010

11+
#include "mlir/IR/Dominance.h"
1112
#include "mlir/IR/SymbolTable.h"
1213
#include "llvm/ADT/SmallPtrSet.h"
1314
#include <unordered_set>
@@ -27,7 +28,7 @@ using namespace mlir;
2728
//===----------------------------------------------------------------------===//
2829

2930
bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) {
30-
return isa<Allocate, Free, Read, Write, Init>(effect);
31+
return isa<Allocate, Free, Read, Write>(effect);
3132
}
3233

3334
//===----------------------------------------------------------------------===//
@@ -132,7 +133,6 @@ template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *);
132133
template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *);
133134
template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *);
134135
template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *);
135-
template bool mlir::hasSingleEffect<MemoryEffects::Init>(Operation *);
136136

137137
template <typename EffectTy>
138138
bool mlir::hasSingleEffect(Operation *op, Value value) {
@@ -162,8 +162,6 @@ template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *,
162162
Value value);
163163
template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *,
164164
Value value);
165-
template bool mlir::hasSingleEffect<MemoryEffects::Init>(Operation *,
166-
Value value);
167165

168166
template <typename ValueTy, typename EffectTy>
169167
bool mlir::hasSingleEffect(Operation *op, ValueTy value) {
@@ -198,18 +196,13 @@ template bool
198196
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Write>(Operation *,
199197
OpOperand *);
200198
template bool
201-
mlir::hasSingleEffect<OpOperand *, MemoryEffects::Init>(Operation *,
202-
OpOperand *);
203-
template bool
204199
mlir::hasSingleEffect<OpResult, MemoryEffects::Allocate>(Operation *, OpResult);
205200
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Free>(Operation *,
206201
OpResult);
207202
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Read>(Operation *,
208203
OpResult);
209204
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Write>(Operation *,
210205
OpResult);
211-
template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Init>(Operation *,
212-
OpResult);
213206
template bool
214207
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
215208
BlockArgument);
@@ -222,9 +215,6 @@ mlir::hasSingleEffect<BlockArgument, MemoryEffects::Read>(Operation *,
222215
template bool
223216
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Write>(Operation *,
224217
BlockArgument);
225-
template bool
226-
mlir::hasSingleEffect<BlockArgument, MemoryEffects::Init>(Operation *,
227-
BlockArgument);
228218

229219
template <typename... EffectTys>
230220
bool mlir::hasEffect(Operation *op) {
@@ -241,7 +231,6 @@ template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *);
241231
template bool mlir::hasEffect<MemoryEffects::Free>(Operation *);
242232
template bool mlir::hasEffect<MemoryEffects::Read>(Operation *);
243233
template bool mlir::hasEffect<MemoryEffects::Write>(Operation *);
244-
template bool mlir::hasEffect<MemoryEffects::Init>(Operation *);
245234
template bool
246235
mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *);
247236

@@ -263,7 +252,6 @@ template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *,
263252
template bool mlir::hasEffect<MemoryEffects::Free>(Operation *, Value value);
264253
template bool mlir::hasEffect<MemoryEffects::Read>(Operation *, Value value);
265254
template bool mlir::hasEffect<MemoryEffects::Write>(Operation *, Value value);
266-
template bool mlir::hasEffect<MemoryEffects::Init>(Operation *, Value value);
267255
template bool
268256
mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *,
269257
Value value);
@@ -289,8 +277,6 @@ template bool mlir::hasEffect<OpOperand *, MemoryEffects::Read>(Operation *,
289277
OpOperand *);
290278
template bool mlir::hasEffect<OpOperand *, MemoryEffects::Write>(Operation *,
291279
OpOperand *);
292-
template bool mlir::hasEffect<OpOperand *, MemoryEffects::Init>(Operation *,
293-
OpOperand *);
294280
template bool
295281
mlir::hasEffect<OpOperand *, MemoryEffects::Write, MemoryEffects::Free>(
296282
Operation *, OpOperand *);
@@ -303,8 +289,6 @@ template bool mlir::hasEffect<OpResult, MemoryEffects::Read>(Operation *,
303289
OpResult);
304290
template bool mlir::hasEffect<OpResult, MemoryEffects::Write>(Operation *,
305291
OpResult);
306-
template bool mlir::hasEffect<OpResult, MemoryEffects::Init>(Operation *,
307-
OpResult);
308292
template bool
309293
mlir::hasEffect<OpResult, MemoryEffects::Write, MemoryEffects::Free>(
310294
Operation *, OpResult);
@@ -320,8 +304,6 @@ template bool
320304
mlir::hasEffect<BlockArgument, MemoryEffects::Write>(Operation *,
321305
BlockArgument);
322306
template bool
323-
mlir::hasEffect<BlockArgument, MemoryEffects::Init>(Operation *, BlockArgument);
324-
template bool
325307
mlir::hasEffect<BlockArgument, MemoryEffects::Write, MemoryEffects::Free>(
326308
Operation *, BlockArgument);
327309

@@ -334,7 +316,13 @@ bool mlir::wouldOpBeTriviallyDead(Operation *op) {
334316
}
335317

336318
bool mlir::isMemoryEffectMovable(Operation *op) {
337-
return (isMemoryEffectFree(op) || isMemoryInitMovable(op));
319+
if (isMemoryEffectFree(op))
320+
return true;
321+
322+
if (isMemoryEffectConflictFree(op))
323+
return true;
324+
325+
return false;
338326
}
339327

340328
bool mlir::isMemoryEffectFree(Operation *op) {
@@ -358,16 +346,15 @@ bool mlir::isMemoryEffectFree(Operation *op) {
358346
// free.
359347
for (Region &region : op->getRegions())
360348
for (Operation &op : region.getOps())
361-
if (!isMemoryEffectFree(&op))
349+
if (!isMemoryEffectMovable(&op))
362350
return false;
363351

364352
return true;
365353
}
366354

367-
bool mlir::isMemoryInitMovable(Operation *op) {
355+
bool mlir::isMemoryEffectConflictFree(Operation *op) {
368356
auto memInterface = dyn_cast<MemoryEffectOpInterface>(op);
369357
// op does not implement the memory effect op interface
370-
// meaning it doesn't have any memory init effects and
371358
// shouldn't be flagged as movable to be conservative
372359
if (!memInterface) return false;
373360

@@ -378,60 +365,68 @@ bool mlir::isMemoryInitMovable(Operation *op) {
378365
// op has interface but no effects, be conservative
379366
if (effects.empty()) return false;
380367

381-
382368
DenseMap<TypeID, int> resourceCounts;
383369

384-
// ensure op only has Init effects and gather unique
370+
// ensure op only has Write effects and gather unique
385371
// resource names
386372
for (const MemoryEffects::EffectInstance &effect : effects) {
387-
if (!isa<MemoryEffects::Init>(effect.getEffect()))
373+
if (!isa<MemoryEffects::Write>(effect.getEffect()))
388374
return false;
389375

390376
resourceCounts.try_emplace(effect.getResource()->getResourceID(), 0);
391377
}
392378

393379
// op itself is good, need to check rest of its parent region
394380
Operation *parent = op->getParentOp();
381+
mlir::DominanceInfo dom(parent);
395382

396383
for (Region &region : parent->getRegions())
397-
for (Operation &op_i : region.getOps())
398-
if (hasMemoryEffectInitConflict(&op_i, resourceCounts))
384+
for (Operation &opI : region.getOps())
385+
if (hasMemoryEffectConflict(op, &opI, dom, resourceCounts))
399386
return false;
400387

401388
return true;
402389
}
403390

404-
bool mlir::hasMemoryEffectInitConflict(
405-
Operation *op, DenseMap<TypeID, int> &resourceCounts) {
391+
bool mlir::hasMemoryEffectConflict(
392+
Operation *mainOp, Operation *op,
393+
mlir::DominanceInfo &dom, DenseMap<TypeID, int> &resourceCounts) {
406394

407395
if (auto memInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
408-
if (!memInterface.hasNoEffect()) {
409-
llvm::SmallVector<MemoryEffects::EffectInstance> effects;
410-
memInterface.getEffects(effects);
411-
412-
// ensure op only has Init effects and gather unique
413-
// resource names
414-
for (const MemoryEffects::EffectInstance &effect : effects) {
415-
if (!isa<MemoryEffects::Init>(effect.getEffect()))
416-
return true;
396+
397+
llvm::SmallVector<MemoryEffects::EffectInstance> effects;
398+
memInterface.getEffects(effects);
399+
400+
auto isDominated = dom.properlyDominates(mainOp, op);
417401

418-
// only care about resources of the op that called
419-
// this recursive function for the first time
420-
auto resourceID = effect.getResource()->getResourceID();
402+
// ensure op only has Write or dominated Read effects
403+
// check used resources
404+
for (const MemoryEffects::EffectInstance &effect : effects) {
405+
auto resourceID = effect.getResource()->getResourceID();
421406

422-
if (resourceCounts.contains(resourceID))
423-
if (++resourceCounts[resourceID] > 1)
424-
return true;
407+
if (resourceCounts.contains(resourceID)) {
408+
if (isa<MemoryEffects::Read>(effect.getEffect())) {
409+
if (isDominated) {
410+
continue; // skip dominated reads
411+
}
412+
}
413+
else if (!isa<MemoryEffects::Write>(effect.getEffect())) {
414+
return true; // count alloc/free in same region as conflict, be conservative
415+
}
416+
417+
// update write counts, should always be <=1 per resource in region
418+
if (++resourceCounts[resourceID] > 1) {
419+
return true;
420+
}
425421
}
426-
return false;
427422
}
428423
}
429424

430425
// Recurse into the regions and ensure that nested ops don't
431-
// conflict with each others MemInits
426+
// conflict with each other's MemWrites
432427
for (Region &region : op->getRegions())
433-
for (Operation &op : region.getOps())
434-
if (hasMemoryEffectInitConflict(&op, resourceCounts))
428+
for (Operation &opI : region.getOps())
429+
if (hasMemoryEffectConflict(mainOp, &opI, dom, resourceCounts))
435430
return true;
436431

437432
return false;

0 commit comments

Comments
 (0)