[mlir][IR] Remove the concept of `OperationProperties`

These properties were useful for a few things before traits had a better integration story, but don't really carry their weight well these days. Most of these properties are already checked via traits in most of the code. It is better to align the system around traits, and improve the performance/cost of traits in general.

Differential Revision: https://reviews.llvm.org/D96088
This commit is contained in:
River Riddle 2021-02-09 11:41:10 -08:00
parent dea74b2820
commit fe7c0d90b2
28 changed files with 70 additions and 179 deletions

View File

@ -671,10 +671,6 @@ class VariadicResults
template <typename ConcreteType>
class IsTerminator : public TraitBase<ConcreteType, IsTerminator> {
public:
static AbstractOperation::OperationProperties getTraitProperties() {
return static_cast<AbstractOperation::OperationProperties>(
OperationProperty::Terminator);
}
static LogicalResult verifyTrait(Operation *op) {
return impl::verifyIsTerminator(op);
}
@ -1001,13 +997,7 @@ public:
/// This class adds property that the operation is commutative.
template <typename ConcreteType>
class IsCommutative : public TraitBase<ConcreteType, IsCommutative> {
public:
static AbstractOperation::OperationProperties getTraitProperties() {
return static_cast<AbstractOperation::OperationProperties>(
OperationProperty::Commutative);
}
};
class IsCommutative : public TraitBase<ConcreteType, IsCommutative> {};
/// This class adds property that the operation is an involution.
/// This means a unary to unary operation "f" that satisfies f(f(x)) = x
@ -1110,10 +1100,6 @@ template <typename ConcreteType>
class IsIsolatedFromAbove
: public TraitBase<ConcreteType, IsIsolatedFromAbove> {
public:
static AbstractOperation::OperationProperties getTraitProperties() {
return static_cast<AbstractOperation::OperationProperties>(
OperationProperty::IsolatedFromAbove);
}
static LogicalResult verifyTrait(Operation *op) {
for (auto &region : op->getRegions())
if (!region.isIsolatedFromAbove(op->getLoc()))
@ -1425,34 +1411,6 @@ foldTraits(Operation *op, ArrayRef<Attribute> operands,
return failure();
}
//===----------------------------------------------------------------------===//
// Trait Properties
/// Trait to check if T provides a `getTraitProperties` method.
template <typename T, typename... Args>
using has_get_trait_properties = decltype(T::getTraitProperties());
template <typename T>
using detect_has_get_trait_properties =
llvm::is_detected<has_get_trait_properties, T>;
/// The internal implementation of `getTraitProperties` below that returns the
/// OR of invoking `getTraitProperties` on all of the provided trait types `Ts`.
template <typename... Ts>
static AbstractOperation::OperationProperties
getTraitPropertiesImpl(std::tuple<Ts...> *) {
AbstractOperation::OperationProperties result = 0;
(void)std::initializer_list<int>{(result |= Ts::getTraitProperties(), 0)...};
return result;
}
/// Given a tuple type containing a set of traits that contain a
/// `getTraitProperties` method, return the OR of all of the results of invoking
/// those methods.
template <typename TraitTupleT>
static AbstractOperation::OperationProperties getTraitProperties() {
return getTraitPropertiesImpl((TraitTupleT *)nullptr);
}
//===----------------------------------------------------------------------===//
// Trait Verification
@ -1574,14 +1532,6 @@ private:
typename detail::FilterTypes<op_definition_impl::detect_has_verify_trait,
Traits<ConcreteType>...>::type;
/// Returns the properties of this operation by combining the properties
/// defined by the traits.
static AbstractOperation::OperationProperties getOperationProperties() {
return op_definition_impl::getTraitProperties<typename detail::FilterTypes<
op_definition_impl::detect_has_get_trait_properties,
Traits<ConcreteType>...>::type>();
}
/// Returns an interface map containing the interfaces registered to this
/// operation.
static detail::InterfaceMap getInterfaceMap() {

View File

@ -455,47 +455,6 @@ public:
// Accessors for various properties of operations
//===--------------------------------------------------------------------===//
/// Returns whether the operation is commutative.
bool isCommutative() {
if (auto *absOp = getAbstractOperation())
return absOp->hasProperty(OperationProperty::Commutative);
return false;
}
/// Represents the status of whether an operation is a terminator. We
/// represent an 'unknown' status because we want to support unregistered
/// terminators.
enum class TerminatorStatus { Terminator, NonTerminator, Unknown };
/// Returns the status of whether this operation is a terminator or not.
TerminatorStatus getTerminatorStatus() {
if (auto *absOp = getAbstractOperation()) {
return absOp->hasProperty(OperationProperty::Terminator)
? TerminatorStatus::Terminator
: TerminatorStatus::NonTerminator;
}
return TerminatorStatus::Unknown;
}
/// Returns true if the operation is known to be a terminator.
bool isKnownTerminator() {
return getTerminatorStatus() == TerminatorStatus::Terminator;
}
/// Returns true if the operation is known to *not* be a terminator.
bool isKnownNonTerminator() {
return getTerminatorStatus() == TerminatorStatus::NonTerminator;
}
/// Returns true if the operation is known to be completely isolated from
/// enclosing regions, i.e., no internal regions reference values defined
/// above this operation.
bool isKnownIsolatedFromAbove() {
if (auto *absOp = getAbstractOperation())
return absOp->hasProperty(OperationProperty::IsolatedFromAbove);
return false;
}
/// Attempt to fold this operation with the specified constant operand values
/// - the elements in "operands" will correspond directly to the operands of
/// the operation, but may be null if non-constant. If folding is successful,
@ -506,8 +465,16 @@ public:
/// Returns true if the operation was registered with a particular trait, e.g.
/// hasTrait<OperandsAreSignlessIntegerLike>().
template <template <typename T> class Trait> bool hasTrait() {
auto *absOp = getAbstractOperation();
return absOp ? absOp->hasTrait<Trait>() : false;
const AbstractOperation *abstractOp = getAbstractOperation();
return abstractOp ? abstractOp->hasTrait<Trait>() : false;
}
/// Returns true if the operation is *might* have the provided trait. This
/// means that either the operation is unregistered, or it was registered with
/// the provide trait.
template <template <typename T> class Trait> bool mightHaveTrait() {
const AbstractOperation *abstractOp = getAbstractOperation();
return abstractOp ? abstractOp->hasTrait<Trait>() : true;
}
//===--------------------------------------------------------------------===//

View File

@ -55,33 +55,12 @@ class OwningRewritePatternList;
// AbstractOperation
//===----------------------------------------------------------------------===//
enum class OperationProperty {
/// This bit is set for an operation if it is a commutative
/// operation: that is an operator where order of operands does not
/// change the result of the operation. For example, in a binary
/// commutative operation, "a op b" and "b op a" produce the same
/// results.
Commutative = 0x1,
/// This bit is set for an operation if it is a terminator: that means
/// an operation at the end of a block.
Terminator = 0x2,
/// This bit is set for operations that are completely isolated from above.
/// This is used for operations whose regions are explicit capture only, i.e.
/// they are never allowed to implicitly reference values defined above the
/// parent operation.
IsolatedFromAbove = 0x4,
};
/// This is a "type erased" representation of a registered operation. This
/// should only be used by things like the AsmPrinter and other things that need
/// to be parameterized by generic operation hooks. Most user code should use
/// the concrete operation types.
class AbstractOperation {
public:
using OperationProperties = uint32_t;
using GetCanonicalizationPatternsFn = void (*)(OwningRewritePatternList &,
MLIRContext *);
using FoldHookFn = LogicalResult (*)(Operation *, ArrayRef<Attribute>,
@ -146,11 +125,6 @@ public:
return getCanonicalizationPatternsFn(results, context);
}
/// Returns whether the operation has a particular property.
bool hasProperty(OperationProperty property) const {
return opProperties & static_cast<OperationProperties>(property);
}
/// Returns an instance of the concept object for the given interface if it
/// was registered to this operation, null otherwise. This should not be used
/// directly.
@ -171,33 +145,28 @@ public:
/// This constructor is used by Dialect objects when they register the list of
/// operations they contain.
template <typename T> static void insert(Dialect &dialect) {
insert(T::getOperationName(), dialect, T::getOperationProperties(),
TypeID::get<T>(), T::getParseAssemblyFn(), T::getPrintAssemblyFn(),
insert(T::getOperationName(), dialect, TypeID::get<T>(),
T::getParseAssemblyFn(), T::getPrintAssemblyFn(),
T::getVerifyInvariantsFn(), T::getFoldHookFn(),
T::getGetCanonicalizationPatternsFn(), T::getInterfaceMap(),
T::getHasTraitFn());
}
private:
static void insert(StringRef name, Dialect &dialect,
OperationProperties opProperties, TypeID typeID,
static void insert(StringRef name, Dialect &dialect, TypeID typeID,
ParseAssemblyFn parseAssembly,
PrintAssemblyFn printAssembly,
VerifyInvariantsFn verifyInvariants, FoldHookFn foldHook,
GetCanonicalizationPatternsFn getCanonicalizationPatterns,
detail::InterfaceMap &&interfaceMap, HasTraitFn hasTrait);
AbstractOperation(StringRef name, Dialect &dialect,
OperationProperties opProperties, TypeID typeID,
AbstractOperation(StringRef name, Dialect &dialect, TypeID typeID,
ParseAssemblyFn parseAssembly,
PrintAssemblyFn printAssembly,
VerifyInvariantsFn verifyInvariants, FoldHookFn foldHook,
GetCanonicalizationPatternsFn getCanonicalizationPatterns,
detail::InterfaceMap &&interfaceMap, HasTraitFn hasTrait);
/// The properties of the operation.
const OperationProperties opProperties;
/// A map of interfaces that were registered to this operation.
detail::InterfaceMap interfaceMap;

View File

@ -485,7 +485,7 @@ MlirOperation mlirBlockGetTerminator(MlirBlock block) {
if (cppBlock->empty())
return wrap(static_cast<Operation *>(nullptr));
Operation &back = cppBlock->back();
if (!back.isKnownTerminator())
if (!back.hasTrait<OpTrait::IsTerminator>())
return wrap(static_cast<Operation *>(nullptr));
return wrap(&back);
}

View File

@ -387,7 +387,8 @@ bool mlir::isValidSymbol(Value value, Region *region) {
if (!defOp) {
// A block argument that is not a top-level value is a valid symbol if it
// dominates region's parent op.
if (region && !region->getParentOp()->isKnownIsolatedFromAbove())
Operation *regionOp = region ? region->getParentOp() : nullptr;
if (regionOp && !regionOp->hasTrait<OpTrait::IsIsolatedFromAbove>())
if (auto *parentOpRegion = region->getParentOp()->getParentRegion())
return isValidSymbol(value, parentOpRegion);
return false;
@ -407,7 +408,8 @@ bool mlir::isValidSymbol(Value value, Region *region) {
return isDimOpValidSymbol(dimOp, region);
// Check for values dominating `region`'s parent op.
if (region && !region->getParentOp()->isKnownIsolatedFromAbove())
Operation *regionOp = region ? region->getParentOp() : nullptr;
if (regionOp && !regionOp->hasTrait<OpTrait::IsIsolatedFromAbove>())
if (auto *parentRegion = region->getParentOp()->getParentRegion())
return isValidSymbol(value, parentRegion);

View File

@ -185,7 +185,8 @@ AffineDataCopyGeneration::runOnBlock(Block *block,
// Generate the copy for the final block range.
if (curBegin != block->end()) {
// Can't be a terminator because it would have been skipped above.
assert(!curBegin->isKnownTerminator() && "can't be a terminator");
assert(!curBegin->hasTrait<OpTrait::IsTerminator>() &&
"can't be a terminator");
// Exclude the affine.yield - hence, the std::prev.
affineDataCopyGenerate(/*begin=*/curBegin, /*end=*/std::prev(block->end()),
copyOptions, /*filterMemRef=*/llvm::None, copyNests);

View File

@ -34,7 +34,9 @@ class GpuAsyncRegionPass : public GpuAsyncRegionPassBase<GpuAsyncRegionPass> {
};
} // namespace
static bool isTerminator(Operation *op) { return !op->isKnownNonTerminator(); }
static bool isTerminator(Operation *op) {
return op->mightHaveTrait<OpTrait::IsTerminator>();
}
static bool hasSideEffects(Operation *op) {
return !MemoryEffectOpInterface::hasNoEffect(op);
}

View File

@ -51,7 +51,7 @@ struct FuncBufferizePass : public FuncBufferizeBase<FuncBufferizePass> {
// implement the trait or interface, mark them as illegal no matter what.
target.markUnknownOpDynamicallyLegal([&](Operation *op) {
// If it is not a terminator, ignore it.
if (op->isKnownNonTerminator())
if (!op->mightHaveTrait<OpTrait::IsTerminator>())
return true;
// If it is not the last operation in the block, also ignore it. We do
// this to handle unknown operations, as well.

View File

@ -85,7 +85,7 @@ void mlir::edsc::appendToBlock(Block *block,
OpBuilder &builder = ScopedContext::getBuilderRef();
OpBuilder::InsertionGuard guard(builder);
if (block->empty() || block->back().isKnownNonTerminator())
if (block->empty() || !block->back().mightHaveTrait<OpTrait::IsTerminator>())
builder.setInsertionPointToEnd(block);
else
builder.setInsertionPoint(&block->back());

View File

@ -878,7 +878,7 @@ void SSANameState::shadowRegionArgs(Region &region, ValueRange namesToUse) {
assert(!region.empty() && "cannot shadow arguments of an empty region");
assert(region.getNumArguments() == namesToUse.size() &&
"incorrect number of names passed in");
assert(region.getParentOp()->isKnownIsolatedFromAbove() &&
assert(region.getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>() &&
"only KnownIsolatedFromAbove ops can shadow names");
SmallVector<char, 16> nameStr;
@ -2646,22 +2646,22 @@ void Operation::print(raw_ostream &os, OpPrintingFlags flags) {
}
// Find the operation to number from based upon the provided flags.
Operation *printedOp = this;
Operation *op = this;
bool shouldUseLocalScope = flags.shouldUseLocalScope();
do {
// If we are printing local scope, stop at the first operation that is
// isolated from above.
if (shouldUseLocalScope && printedOp->isKnownIsolatedFromAbove())
if (shouldUseLocalScope && op->hasTrait<OpTrait::IsIsolatedFromAbove>())
break;
// Otherwise, traverse up to the next parent.
Operation *parentOp = printedOp->getParentOp();
Operation *parentOp = op->getParentOp();
if (!parentOp)
break;
printedOp = parentOp;
op = parentOp;
} while (true);
AsmState state(printedOp);
AsmState state(op);
print(os, state, flags);
}
void Operation::print(raw_ostream &os, AsmState &state, OpPrintingFlags flags) {

View File

@ -214,7 +214,7 @@ BlockArgument Block::insertArgument(args_iterator it, Type type) {
/// Get the terminator operation of this block. This function asserts that
/// the block has a valid terminator operation.
Operation *Block::getTerminator() {
assert(!empty() && !back().isKnownNonTerminator());
assert(!empty() && back().mightHaveTrait<OpTrait::IsTerminator>());
return &back();
}

View File

@ -659,15 +659,14 @@ const AbstractOperation *AbstractOperation::lookup(StringRef opName,
}
void AbstractOperation::insert(
StringRef name, Dialect &dialect, OperationProperties opProperties,
TypeID typeID, ParseAssemblyFn parseAssembly, PrintAssemblyFn printAssembly,
StringRef name, Dialect &dialect, TypeID typeID,
ParseAssemblyFn parseAssembly, PrintAssemblyFn printAssembly,
VerifyInvariantsFn verifyInvariants, FoldHookFn foldHook,
GetCanonicalizationPatternsFn getCanonicalizationPatterns,
detail::InterfaceMap &&interfaceMap, HasTraitFn hasTrait) {
AbstractOperation opInfo(name, dialect, opProperties, typeID, parseAssembly,
printAssembly, verifyInvariants, foldHook,
getCanonicalizationPatterns, std::move(interfaceMap),
hasTrait);
AbstractOperation opInfo(
name, dialect, typeID, parseAssembly, printAssembly, verifyInvariants,
foldHook, getCanonicalizationPatterns, std::move(interfaceMap), hasTrait);
auto &impl = dialect.getContext()->getImpl();
assert(impl.multiThreadedExecutionContext == 0 &&
@ -681,14 +680,14 @@ void AbstractOperation::insert(
}
AbstractOperation::AbstractOperation(
StringRef name, Dialect &dialect, OperationProperties opProperties,
TypeID typeID, ParseAssemblyFn parseAssembly, PrintAssemblyFn printAssembly,
StringRef name, Dialect &dialect, TypeID typeID,
ParseAssemblyFn parseAssembly, PrintAssemblyFn printAssembly,
VerifyInvariantsFn verifyInvariants, FoldHookFn foldHook,
GetCanonicalizationPatternsFn getCanonicalizationPatterns,
detail::InterfaceMap &&interfaceMap, HasTraitFn hasTrait)
: name(Identifier::get(name, dialect.getContext())), dialect(dialect),
typeID(typeID), opProperties(opProperties),
interfaceMap(std::move(interfaceMap)), foldHookFn(foldHook),
typeID(typeID), interfaceMap(std::move(interfaceMap)),
foldHookFn(foldHook),
getCanonicalizationPatternsFn(getCanonicalizationPatterns),
hasTraitFn(hasTrait), parseAssemblyFn(parseAssembly),
printAssemblyFn(printAssembly), verifyInvariantsFn(verifyInvariants) {}

View File

@ -139,7 +139,7 @@ Operation *Operation::create(Location location, OperationName name,
::new (rawMem) Operation(location, name, resultTypes, numSuccessors,
numRegions, attributes, needsOperandStorage);
assert((numSuccessors == 0 || !op->isKnownNonTerminator()) &&
assert((numSuccessors == 0 || op->mightHaveTrait<OpTrait::IsTerminator>()) &&
"unexpected successors in a non-terminator operation");
// Initialize the results.
@ -1286,7 +1286,7 @@ void impl::ensureRegionTerminator(
builder.createBlock(&region);
Block &block = region.back();
if (!block.empty() && block.back().isKnownTerminator())
if (!block.empty() && block.back().hasTrait<OpTrait::IsTerminator>())
return;
builder.setInsertionPointToEnd(&block);

View File

@ -145,9 +145,10 @@ LogicalResult OperationVerifier::verifyBlock(Block &block) {
}
// Verify the terminator.
if (failed(verifyOperation(block.back())))
Operation &terminator = block.back();
if (failed(verifyOperation(terminator)))
return failure();
if (block.back().isKnownNonTerminator())
if (!terminator.mightHaveTrait<OpTrait::IsTerminator>())
return block.back().emitError("block with no terminator");
// Verify that this block is not branching to a block of a different

View File

@ -91,7 +91,7 @@ static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
}
bool mlir::wouldOpBeTriviallyDead(Operation *op) {
if (!op->isKnownNonTerminator())
if (op->mightHaveTrait<OpTrait::IsTerminator>())
return false;
return wouldOpBeTriviallyDeadImpl(op);
}

View File

@ -808,7 +808,7 @@ Operation *OperationParser::parseGenericOperation() {
if (getToken().is(Token::l_square)) {
// Check if the operation is a known terminator.
const AbstractOperation *abstractOp = result.name.getAbstractOperation();
if (abstractOp && !abstractOp->hasProperty(OperationProperty::Terminator))
if (abstractOp && !abstractOp->hasTrait<OpTrait::IsTerminator>())
return emitError("successors in non-terminator"), nullptr;
SmallVector<Block *, 2> successors;
@ -1448,7 +1448,7 @@ public:
// Try to parse the region.
assert((!enableNameShadowing ||
opDefinition->hasProperty(OperationProperty::IsolatedFromAbove)) &&
opDefinition->hasTrait<OpTrait::IsIsolatedFromAbove>()) &&
"name shadowing is only allowed on isolated regions");
if (parser.parseRegion(region, regionArguments, enableNameShadowing))
return failure();

View File

@ -357,11 +357,10 @@ void OpPassManager::initialize(MLIRContext *context,
LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
AnalysisManager am, bool verifyPasses,
unsigned parentInitGeneration) {
if (!op->getName().getAbstractOperation())
if (!op->isRegistered())
return op->emitOpError()
<< "trying to schedule a pass on an unregistered operation";
if (!op->getName().getAbstractOperation()->hasProperty(
OperationProperty::IsolatedFromAbove))
if (!op->hasTrait<OpTrait::IsIsolatedFromAbove>())
return op->emitOpError() << "trying to schedule a pass on an operation not "
"marked as 'IsolatedFromAbove'";

View File

@ -1155,7 +1155,8 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
LogicalResult ModuleTranslation::checkSupportedModuleOps(Operation *m) {
for (Operation &o : getModuleBody(m).getOperations())
if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp>(&o) && !o.isKnownTerminator())
if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp>(&o) &&
!o.hasTrait<OpTrait::IsTerminator>())
return o.emitOpError("unsupported module-level operation");
return success();
}

View File

@ -90,7 +90,7 @@ private:
/// Attempt to eliminate a redundant operation.
LogicalResult CSE::simplifyOperation(ScopedMapTy &knownValues, Operation *op) {
// Don't simplify terminator operations.
if (op->isKnownTerminator())
if (op->hasTrait<OpTrait::IsTerminator>())
return failure();
// If the operation is already trivially dead just add it to the erase list.
@ -145,7 +145,7 @@ void CSE::simplifyBlock(ScopedMapTy &knownValues, DominanceInfo &domInfo,
// If this operation is isolated above, we can't process nested regions with
// the given 'knownValues' map. This would cause the insertion of implicit
// captures in explicit capture only regions.
if (!inst.isRegistered() || inst.isKnownIsolatedFromAbove()) {
if (inst.mightHaveTrait<OpTrait::IsIsolatedFromAbove>()) {
ScopedMapTy nestedKnownValues;
for (auto &region : inst.getRegions())
simplifyRegion(nestedKnownValues, domInfo, region);

View File

@ -414,7 +414,7 @@ struct Inliner : public InlinerInterface {
static bool shouldInline(ResolvedCall &resolvedCall) {
// Don't allow inlining terminator calls. We currently don't support this
// case.
if (resolvedCall.call->isKnownTerminator())
if (resolvedCall.call->hasTrait<OpTrait::IsTerminator>())
return false;
// Don't allow inlining if the target is an ancestor of the call. This
@ -654,7 +654,7 @@ LogicalResult InlinerPass::optimizeSCC(CallGraph &cg, CGUseList &useList,
// We also won't apply simplifications to nodes that can't have passes
// scheduled on them.
auto *region = node->getCallableRegion();
if (!region->getParentOp()->isKnownIsolatedFromAbove())
if (!region->getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>())
continue;
nodesToVisit.push_back(node);
}

View File

@ -487,7 +487,7 @@ void SCCPSolver::visitOperation(Operation *op) {
}
// If this is a terminator operation, process any control flow lattice state.
if (op->isKnownTerminator())
if (op->hasTrait<OpTrait::IsTerminator>())
visitTerminatorOperation(op, operandConstants);
// Process call operations. The call visitor processes result values, so we

View File

@ -30,7 +30,7 @@ getInsertionRegion(DialectInterfaceCollection<DialectFoldInterface> &interfaces,
// * The parent is unregistered, or is known to be isolated from above.
// * The parent is a top-level operation.
auto *parentOp = region->getParentOp();
if (!parentOp->isRegistered() || parentOp->isKnownIsolatedFromAbove() ||
if (parentOp->mightHaveTrait<OpTrait::IsIsolatedFromAbove>() ||
!parentOp->getBlock())
return region;
@ -182,7 +182,7 @@ LogicalResult OperationFolder::tryToFold(
SmallVector<OpFoldResult, 8> foldResults;
// If this is a commutative operation, move constants to be trailing operands.
if (op->getNumOperands() >= 2 && op->isCommutative()) {
if (op->getNumOperands() >= 2 && op->hasTrait<OpTrait::IsCommutative>()) {
std::stable_partition(
op->getOpOperands().begin(), op->getOpOperands().end(),
[&](OpOperand &O) { return !matchPattern(O.get(), m_Constant()); });

View File

@ -247,7 +247,7 @@ mlir::applyPatternsAndFoldGreedily(MutableArrayRef<Region> regions,
// prevent performing canonicalizations on operations defined at or above
// the region containing 'op'.
auto regionIsIsolated = [](Region &region) {
return region.getParentOp()->isKnownIsolatedFromAbove();
return region.getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>();
};
(void)regionIsIsolated;
assert(llvm::all_of(regions, regionIsIsolated) &&

View File

@ -173,7 +173,7 @@ static bool isUseSpeciallyKnownDead(OpOperand &use, LiveMap &liveMap) {
// And similarly, because each successor operand is really an operand to a phi
// node, rather than to the terminator op itself, a terminator op can't e.g.
// "print" the value of a successor operand.
if (owner->isKnownTerminator()) {
if (owner->hasTrait<OpTrait::IsTerminator>()) {
if (BranchOpInterface branchInterface = dyn_cast<BranchOpInterface>(owner))
if (auto arg = branchInterface.getSuccessorBlockArgument(operandIndex))
return !liveMap.wasProvenLive(*arg);
@ -194,7 +194,7 @@ static void processValue(Value value, LiveMap &liveMap) {
static bool isOpIntrinsicallyLive(Operation *op) {
// This pass doesn't modify the CFG, so terminators are never deleted.
if (!op->isKnownNonTerminator())
if (op->mightHaveTrait<OpTrait::IsTerminator>())
return true;
// If the op has a side effect, we treat it as live.
// TODO: Properly handle region side effects.
@ -234,7 +234,7 @@ static void propagateLiveness(Operation *op, LiveMap &liveMap) {
propagateLiveness(region, liveMap);
// Process terminator operations.
if (op->isKnownTerminator())
if (op->hasTrait<OpTrait::IsTerminator>())
return propagateTerminatorLiveness(op, liveMap);
// Process the op itself.

View File

@ -29,7 +29,7 @@ void ReportShapeFnPass::runOnOperation() {
// Report the shape function available to refine the op.
auto shapeFnId = Identifier::get("shape.function", &getContext());
auto remarkShapeFn = [&](shape::FunctionLibraryOp shapeFnLib, Operation *op) {
if (op->isKnownTerminator())
if (op->hasTrait<OpTrait::IsTerminator>())
return true;
if (auto typeInterface = dyn_cast<InferTypeOpInterface>(op)) {
op->emitRemark() << "implements InferType op interface";

View File

@ -1017,7 +1017,7 @@ struct TestSelectiveOpReplacementPattern : public OpRewritePattern<TestCastOp> {
// Replace non-terminator uses with the first operand.
rewriter.replaceOpWithIf(op, operands[0], [](OpOperand &operand) {
return operand.getOwner()->isKnownTerminator();
return operand.getOwner()->hasTrait<OpTrait::IsTerminator>();
});
// Replace everything else with the second operand if the operation isn't
// dead.

View File

@ -72,7 +72,7 @@ public:
if (runOnNestedOp) {
llvm::errs() << "Run on nested op\n";
currentOp->walk([&](Operation *op) {
if (op == currentOp || !op->isKnownIsolatedFromAbove() ||
if (op == currentOp || !op->hasTrait<OpTrait::IsIsolatedFromAbove>() ||
op->getName() != currentOp->getName())
return;
llvm::errs() << "Run on " << *op << "\n";

View File

@ -44,7 +44,7 @@ struct TestOpaqueLoc
op->setLoc(
OpaqueLoc::get<MyLocation *>(myLocs.back().get(), &getContext()));
if (isa<FuncOp>(op) || op->isKnownTerminator())
if (isa<FuncOp>(op) || op->hasTrait<OpTrait::IsTerminator>())
return;
OpBuilder builder(op);