Add support for walking the use list of an SSAValue and converting owners to

Operation*'s, simplifying some code in GreedyPatternRewriteDriver.cpp.

Also add print/dump methods on Operation.

PiperOrigin-RevId: 219045764
This commit is contained in:
Chris Lattner 2018-10-28 10:03:19 -07:00 committed by jpienaar
parent f8dee9ee05
commit 085b687fbd
6 changed files with 91 additions and 69 deletions

View File

@ -206,11 +206,13 @@ public:
ArrayRef<NamedAttribute> attributes,
MLIRContext *context);
using Instruction::dump;
using Instruction::emitError;
using Instruction::emitNote;
using Instruction::emitWarning;
using Instruction::getContext;
using Instruction::getLoc;
using Instruction::print;
OperationInst *clone() const;
@ -341,8 +343,8 @@ public:
llvm::iplist<OperationInst>::iterator iterator);
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(const Instruction *inst) {
return inst->getKind() == Kind::Operation;
static bool classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::OperationInst;
}
static bool classof(const Operation *op) {
return op->getOperationKind() == OperationKind::Instruction;
@ -433,8 +435,8 @@ public:
ArrayRef<BasicBlockOperand> getBasicBlockOperands() const { return dest; }
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(const Instruction *inst) {
return inst->getKind() == Kind::Branch;
static bool classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::BranchInst;
}
private:
@ -479,10 +481,7 @@ public:
unsigned getNumOperands() const { return operands.size(); }
//
// Accessors for operands to the 'true' destination
//
// Accessors for operands to the 'true' destination.
CFGValue *getTrueOperand(unsigned idx) {
return getTrueInstOperand(idx).get();
}
@ -530,10 +529,7 @@ public:
/// Add a list of values to the operand list.
void addTrueOperands(ArrayRef<CFGValue *> values);
//
// Accessors for operands to the 'false' destination
//
// Accessors for operands to the 'false' destination.
CFGValue *getFalseOperand(unsigned idx) {
return getFalseInstOperand(idx).get();
}
@ -592,8 +588,8 @@ public:
ArrayRef<BasicBlockOperand> getBasicBlockOperands() const { return dests; }
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(const Instruction *inst) {
return inst->getKind() == Kind::CondBranch;
static bool classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::CondBranchInst;
}
private:
@ -631,8 +627,8 @@ public:
void destroy();
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(const Instruction *inst) {
return inst->getKind() == Kind::Return;
static bool classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::ReturnInst;
}
private:

View File

@ -29,6 +29,7 @@ template <typename OpType> class OpPointer;
template <typename ObjectType, typename ElementType> class OperandIterator;
template <typename ObjectType, typename ElementType> class ResultIterator;
class Function;
class IROperandOwner;
class Instruction;
class Statement;
@ -232,12 +233,16 @@ public:
// Returns whether the operation is commutative.
bool isCommutative() const {
return getAbstractOperation()->hasProperty(OperationProperty::Commutative);
if (auto *absOp = getAbstractOperation())
return absOp->hasProperty(OperationProperty::Commutative);
return false;
}
// Returns whether the operation has side-effects.
bool hasNoSideEffect() const {
return getAbstractOperation()->hasProperty(OperationProperty::NoSideEffect);
if (auto *absOp = getAbstractOperation())
return absOp->hasProperty(OperationProperty::NoSideEffect);
return false;
}
/// Remove this operation from its parent block and delete it.
@ -251,9 +256,13 @@ public:
bool constantFold(ArrayRef<Attribute> operands,
SmallVectorImpl<Attribute> &results) const;
void print(raw_ostream &os) const;
void dump() const;
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(const Instruction *inst);
static bool classof(const Statement *stmt);
static bool classof(const IROperandOwner *ptr);
protected:
Operation(bool isInstruction, OperationName name,
@ -410,4 +419,16 @@ inline auto Operation::getResults() const
}
} // end namespace mlir
/// We need to teach the LLVM cast/dyn_cast etc logic how to cast from an
/// IROperandOwner* to Operation*. This can't be done with a simple pointer to
/// pointer cast because the pointer adjustment depends on whether the Owner is
/// dynamically an Instruction or Statement, because of multiple inheritance.
namespace llvm {
template <>
struct cast_convert_val<mlir::Operation, mlir::IROperandOwner *,
mlir::IROperandOwner *> {
static mlir::Operation *doit(const mlir::IROperandOwner *value);
};
} // namespace llvm
#endif

View File

@ -51,10 +51,12 @@ public:
/// Return the context this operation is associated with.
MLIRContext *getContext() const;
using Statement::dump;
using Statement::emitError;
using Statement::emitNote;
using Statement::emitWarning;
using Statement::getLoc;
using Statement::print;
/// Check if this statement is a return statement.
bool isReturn() const;

View File

@ -29,6 +29,7 @@
namespace mlir {
class IROperand;
class IROperandOwner;
template <typename OperandType, typename OwnerType> class SSAValueUseIterator;
class IRObjectWithUseList {
@ -43,7 +44,7 @@ public:
/// Returns true if this value has exactly one use.
inline bool hasOneUse() const;
using use_iterator = SSAValueUseIterator<IROperand, void>;
using use_iterator = SSAValueUseIterator<IROperand, IROperandOwner>;
using use_range = llvm::iterator_range<use_iterator>;
inline use_iterator use_begin() const;

View File

@ -237,6 +237,18 @@ bool Operation::constantFold(ArrayRef<Attribute> operands,
return true;
}
void Operation::print(raw_ostream &os) const {
if (auto *inst = llvm::dyn_cast<OperationInst>(this))
return inst->print(os);
return llvm::cast<OperationStmt>(this)->print(os);
}
void Operation::dump() const {
if (auto *inst = llvm::dyn_cast<OperationInst>(this))
return inst->dump();
return llvm::cast<OperationStmt>(this)->dump();
}
/// Methods for support type inquiry through isa, cast, and dyn_cast.
bool Operation::classof(const Instruction *inst) {
return inst->getKind() == Instruction::Kind::Operation;
@ -244,6 +256,26 @@ bool Operation::classof(const Instruction *inst) {
bool Operation::classof(const Statement *stmt) {
return stmt->getKind() == Statement::Kind::Operation;
}
bool Operation::classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::OperationInst ||
ptr->getKind() == IROperandOwner::Kind::OperationStmt;
}
/// We need to teach the LLVM cast/dyn_cast etc logic how to cast from an
/// IROperandOwner* to Operation*. This can't be done with a simple pointer to
/// pointer cast because the pointer adjustment depends on whether the Owner is
/// dynamically an Instruction or Statement, because of multiple inheritance.
Operation *
llvm::cast_convert_val<mlir::Operation, mlir::IROperandOwner *,
mlir::IROperandOwner *>::doit(const mlir::IROperandOwner
*value) {
const Operation *op;
if (auto *ptr = dyn_cast<OperationStmt>(value))
op = ptr;
else
op = cast<OperationInst>(value);
return const_cast<Operation *>(op);
}
//===----------------------------------------------------------------------===//
// OpState trait class.

View File

@ -98,6 +98,22 @@ public:
driver.removeFromWorklist(op);
}
// When the root of a pattern is about to be replaced, it can trigger
// simplifications to its users - make sure to add them to the worklist
// before the root is changed.
void notifyRootReplaced(Operation *op) override {
for (auto *result : op->getResults())
// TODO: Add a result->getUsers() iterator.
for (auto &user : result->getUses()) {
if (auto *op = dyn_cast<Operation>(user.getOwner()))
driver.addToWorklist(op);
}
// TODO: Walk the operand list dropping them as we go. If any of them
// drop to zero uses, then add them to the worklist to allow them to be
// deleted as dead.
}
GreedyPatternRewriteDriver &driver;
};
@ -206,22 +222,10 @@ void GreedyPatternRewriteDriver::simplifyFunction(Function *currentFunction,
// Add all the users of the result to the worklist so we make sure to
// revisit them.
//
// TODO: This is super gross. SSAValue use iterators should have an
// "owner" that can be downcasted to operation and other things. This
// will require a rejiggering of the class hierarchies.
if (auto *stmt = dyn_cast<OperationStmt>(op)) {
// TODO: Add a result->getUsers() iterator.
for (auto &operand : stmt->getResult(i)->getUses()) {
if (auto *op = dyn_cast<OperationStmt>(operand.getOwner()))
addToWorklist(op);
}
} else {
auto *inst = cast<OperationInst>(op);
// TODO: Add a result->getUsers() iterator.
for (auto &operand : inst->getResult(i)->getUses()) {
if (auto *op = dyn_cast<OperationInst>(operand.getOwner()))
addToWorklist(op);
}
// TODO: Add a result->getUsers() iterator.
for (auto &operand : op->getResult(i)->getUses()) {
if (auto *op = dyn_cast<Operation>(operand.getOwner()))
addToWorklist(op);
}
res->replaceAllUsesWith(cstValue);
@ -268,23 +272,6 @@ static void processMLFunction(MLFunction *fn, OwningPatternList &&patterns) {
return result;
}
// When the root of a pattern is about to be replaced, it can trigger
// simplifications to its users - make sure to add them to the worklist
// before the root is changed.
void notifyRootReplaced(Operation *op) override {
auto *opStmt = cast<OperationStmt>(op);
for (auto *result : opStmt->getResults())
// TODO: Add a result->getUsers() iterator.
for (auto &user : result->getUses()) {
if (auto *op = dyn_cast<OperationStmt>(user.getOwner()))
driver.addToWorklist(op);
}
// TODO: Walk the operand list dropping them as we go. If any of them
// drop to zero uses, then add them to the worklist to allow them to be
// deleted as dead.
}
void setInsertionPoint(Operation *op) override {
// Any new operations should be added before this statement.
builder.setInsertionPoint(cast<OperationStmt>(op));
@ -316,23 +303,6 @@ static void processCFGFunction(CFGFunction *fn, OwningPatternList &&patterns) {
return result;
}
// When the root of a pattern is about to be replaced, it can trigger
// simplifications to its users - make sure to add them to the worklist
// before the root is changed.
void notifyRootReplaced(Operation *op) override {
auto *opStmt = cast<OperationInst>(op);
for (auto *result : opStmt->getResults())
// TODO: Add a result->getUsers() iterator.
for (auto &user : result->getUses()) {
if (auto *op = dyn_cast<OperationInst>(user.getOwner()))
driver.addToWorklist(op);
}
// TODO: Walk the operand list dropping them as we go. If any of them
// drop to zero uses, then add them to the worklist to allow them to be
// deleted as dead.
}
void setInsertionPoint(Operation *op) override {
// Any new operations should be added before this instruction.
builder.setInsertionPoint(cast<OperationInst>(op));