[mlir][SideEffects] Mark the CFG only terminator operations as NoSideEffect

These terminator operations don't really have any side effects, and this allows for more accurate side-effect analysis for region operations. For example, currently we can't detect like a loop.for or affine.for are dead because the affine.terminator is "side effecting".

Note: Marking as NoSideEffect doesn't mean that these operations can be opaquely erased.

Differential Revision: https://reviews.llvm.org/D75888
This commit is contained in:
River Riddle 2020-03-12 14:05:27 -07:00
parent 56926a9146
commit d5f53253a0
16 changed files with 44 additions and 26 deletions

View File

@ -190,7 +190,8 @@ def ReshapeOp : Toy_Op<"reshape"> {
}];
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -193,7 +193,8 @@ def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> {
let hasCanonicalizer = 1;
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -218,7 +218,8 @@ def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> {
let hasCanonicalizer = 1;
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -219,7 +219,8 @@ def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> {
let hasCanonicalizer = 1;
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -219,7 +219,8 @@ def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> {
let results = (outs StaticShapeTensorOf<[F64]>);
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -232,7 +232,8 @@ def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> {
let results = (outs StaticShapeTensorOf<[F64]>);
}
def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -433,7 +433,7 @@ def AffinePrefetchOp : Affine_Op<"prefetch"> {
}
def AffineTerminatorOp :
Affine_Op<"terminator", [Terminator]> {
Affine_Op<"terminator", [NoSideEffect, Terminator]> {
let summary = "affine terminator operation";
let description = [{
Affine terminator is a special terminator operation for blocks inside affine

View File

@ -439,7 +439,8 @@ def GPU_LaunchOp : GPU_Op<"launch">,
let verifier = [{ return ::verify(*this); }];
}
def GPU_ReturnOp : GPU_Op<"return", [HasParent<"GPUFuncOp">, Terminator]>,
def GPU_ReturnOp : GPU_Op<"return", [HasParent<"GPUFuncOp">, NoSideEffect,
Terminator]>,
Arguments<(ins Variadic<AnyType>:$operands)>, Results<(outs)> {
let summary = "Terminator for GPU functions.";
let description = [{
@ -455,7 +456,8 @@ def GPU_ReturnOp : GPU_Op<"return", [HasParent<"GPUFuncOp">, Terminator]>,
let verifier = [{ return ::verify(*this); }];
}
def GPU_TerminatorOp : GPU_Op<"terminator", [HasParent<"LaunchOp">, Terminator]>,
def GPU_TerminatorOp : GPU_Op<"terminator", [HasParent<"LaunchOp">,
NoSideEffect, Terminator]>,
Arguments<(ins)>, Results<(outs)> {
let summary = "Terminator for GPU launch regions.";
let description = [{
@ -468,7 +470,7 @@ def GPU_TerminatorOp : GPU_Op<"terminator", [HasParent<"LaunchOp">, Terminator]>
let printer = [{ p << getOperationName(); }];
}
def GPU_YieldOp : GPU_Op<"yield", [Terminator]>,
def GPU_YieldOp : GPU_Op<"yield", [NoSideEffect, Terminator]>,
Arguments<(ins Variadic<AnyType>:$values)> {
let summary = "GPU yield operation";
let description = [{

View File

@ -452,7 +452,7 @@ def LLVM_FreezeOp : LLVM_OneResultOp<"freeze", [SameOperandsAndResultType]>,
// Terminators.
def LLVM_BrOp : LLVM_TerminatorOp<"br",
[DeclareOpInterfaceMethods<BranchOpInterface>]> {
[DeclareOpInterfaceMethods<BranchOpInterface>, NoSideEffect]> {
let arguments = (ins Variadic<LLVM_Type>:$destOperands);
let successors = (successor AnySuccessor:$dest);
let assemblyFormat = [{
@ -461,7 +461,8 @@ def LLVM_BrOp : LLVM_TerminatorOp<"br",
let builders = [LLVM_TerminatorPassthroughOpBuilder];
}
def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br",
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>]> {
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>,
NoSideEffect]> {
let arguments = (ins LLVMI1:$condition,
Variadic<LLVM_Type>:$trueDestOperands,
Variadic<LLVM_Type>:$falseDestOperands);
@ -486,7 +487,7 @@ def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br",
falseOperands);
}]>, LLVM_TerminatorPassthroughOpBuilder];
}
def LLVM_ReturnOp : LLVM_TerminatorOp<"return", []>,
def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]>,
Arguments<(ins Variadic<LLVM_Type>:$args)> {
string llvmBuilder = [{
if ($_numOperands != 0)

View File

@ -233,7 +233,7 @@ def Linalg_TransposeOp : Linalg_Op<"transpose", [NoSideEffect]>,
let hasFolder = 1;
}
def Linalg_YieldOp : Linalg_Op<"yield", [NativeOpTrait<"IsTerminator">]>,
def Linalg_YieldOp : Linalg_Op<"yield", [NoSideEffect, Terminator]>,
Arguments<(ins Variadic<AnyType>:$values)> {
let summary = "Linalg yield operation";
let description = [{

View File

@ -360,7 +360,8 @@ def ReduceOp : Loop_Op<"reduce", [HasParent<"ParallelOp">]> {
}
def ReduceReturnOp :
Loop_Op<"reduce.return", [HasParent<"ReduceOp">, Terminator]> {
Loop_Op<"reduce.return", [HasParent<"ReduceOp">, NoSideEffect,
Terminator]> {
let summary = "terminator for reduce operation";
let description = [{
"loop.reduce.return" is a special terminator operation for the block inside
@ -376,7 +377,7 @@ def ReduceReturnOp :
let assemblyFormat = "$result attr-dict `:` type($result)";
}
def YieldOp : Loop_Op<"yield", [Terminator]> {
def YieldOp : Loop_Op<"yield", [NoSideEffect, Terminator]> {
let summary = "loop yield and termination operation";
let description = [{
"loop.yield" yields an SSA value from a loop dialect op region and

View File

@ -21,7 +21,7 @@ include "mlir/Interfaces/ControlFlowInterfaces.td"
// -----
def SPV_BranchOp : SPV_Op<"Branch", [
DeclareOpInterfaceMethods<BranchOpInterface>, InFunctionScope,
DeclareOpInterfaceMethods<BranchOpInterface>, InFunctionScope, NoSideEffect,
Terminator]> {
let summary = "Unconditional branch to target block.";
@ -83,7 +83,7 @@ def SPV_BranchOp : SPV_Op<"Branch", [
def SPV_BranchConditionalOp : SPV_Op<"BranchConditional", [
AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>,
InFunctionScope, Terminator]> {
InFunctionScope, NoSideEffect, Terminator]> {
let summary = [{
If Condition is true, branch to true block, otherwise branch to false
block.
@ -316,7 +316,7 @@ def SPV_LoopOp : SPV_Op<"loop", [InFunctionScope]> {
// -----
def SPV_MergeOp : SPV_Op<"_merge", [Terminator]> {
def SPV_MergeOp : SPV_Op<"_merge", [NoSideEffect, Terminator]> {
let summary = "A special terminator for merging a structured selection/loop.";
let description = [{
@ -340,7 +340,8 @@ def SPV_MergeOp : SPV_Op<"_merge", [Terminator]> {
// -----
def SPV_ReturnOp : SPV_Op<"Return", [InFunctionScope, Terminator]> {
def SPV_ReturnOp : SPV_Op<"Return", [InFunctionScope, NoSideEffect,
Terminator]> {
let summary = "Return with no value from a function with void return type.";
let description = [{
@ -384,7 +385,8 @@ def SPV_UnreachableOp : SPV_Op<"Unreachable", [InFunctionScope, Terminator]> {
// -----
def SPV_ReturnValueOp : SPV_Op<"ReturnValue", [InFunctionScope, Terminator]> {
def SPV_ReturnValueOp : SPV_Op<"ReturnValue", [InFunctionScope, NoSideEffect,
Terminator]> {
let summary = "Return a value from a function.";
let description = [{

View File

@ -334,7 +334,7 @@ def AtomicRMWOp : Std_Op<"atomic_rmw", [
//===----------------------------------------------------------------------===//
def BranchOp : Std_Op<"br",
[DeclareOpInterfaceMethods<BranchOpInterface>, Terminator]> {
[DeclareOpInterfaceMethods<BranchOpInterface>, NoSideEffect, Terminator]> {
let summary = "branch operation";
let description = [{
The "br" operation represents a branch operation in a function.
@ -678,7 +678,7 @@ def CmpIOp : Std_Op<"cmpi",
def CondBranchOp : Std_Op<"cond_br",
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>,
Terminator]> {
NoSideEffect, Terminator]> {
let summary = "conditional branch operation";
let description = [{
The "cond_br" operation represents a conditional branch operation in a
@ -1288,7 +1288,8 @@ def RemFOp : FloatArithmeticOp<"remf"> {
// ReturnOp
//===----------------------------------------------------------------------===//
def ReturnOp : Std_Op<"return", [Terminator, HasParent<"FuncOp">]> {
def ReturnOp : Std_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
Terminator]> {
let summary = "return operation";
let description = [{
The "return" operation represents a return operation within a function.

View File

@ -123,6 +123,10 @@ private:
/// Attempt to eliminate a redundant operation.
LogicalResult CSE::simplifyOperation(ScopedMapTy &knownValues, Operation *op) {
// Don't simplify terminator operations.
if (op->isKnownTerminator())
return failure();
// Don't simplify operations with nested blocks. We don't currently model
// equality comparisons correctly among other things. It is also unclear
// whether we would want to CSE such operations.

View File

@ -164,7 +164,8 @@ bool GreedyPatternRewriteDriver::simplify(MutableArrayRef<Region> regions,
// If the operation has no side effects, and no users, then it is
// trivially dead - remove it.
if (op->hasNoSideEffect() && op->use_empty()) {
if (op->isKnownNonTerminator() && op->hasNoSideEffect() &&
op->use_empty()) {
// Be careful to update bookkeeping.
notifyOperationRemoved(op);
op->erase();

View File

@ -868,7 +868,7 @@ static LogicalResult hoistOpsBetween(loop::ForOp outer, loop::ForOp inner) {
});
LogicalResult status = success();
SmallVector<Operation *, 8> toHoist;
for (auto &op : outer.getBody()->getOperations()) {
for (auto &op : outer.getBody()->without_terminator()) {
// Stop when encountering the inner loop.
if (&op == inner.getOperation())
break;