Rework inherentance hierarchy: Operation now derives from Statement, and

OperationInst derives from it.  This allows eliminating some forwarding
functions, other complex code handling multiple paths, and the 'isStatement'
bit tracked by Operation.

This is the last patch I think I can make before the big mechanical change
merging Operation into OperationInst, coming next.

This is step 15/n towards merging instructions and statements, NFC.

PiperOrigin-RevId: 227077411
This commit is contained in:
Chris Lattner 2018-12-27 17:02:02 -08:00 committed by jpienaar
parent 9b20a4ccdf
commit 471c976413
7 changed files with 14 additions and 163 deletions

View File

@ -20,7 +20,6 @@
#include "mlir/IR/OperationSupport.h"
#include "mlir/IR/Statement.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/Twine.h"
namespace mlir {
@ -40,16 +39,8 @@ using Instruction = Statement;
/// MLIR. This class is the common implementation details behind Instruction
/// and OperationStmt.
///
class Operation {
class Operation : public Statement {
public:
/// Return the context this operation is associated with.
MLIRContext *getContext() const;
/// The source location the operation was defined or derived from.
Location getLoc() const;
/// Set the source location the operation was defined or derived from.
void setLoc(Location loc);
/// Return the function this operation is defined in. This has a verbose
/// name to avoid name lookup ambiguities.
@ -60,16 +51,7 @@ public:
}
/// The name of an operation is the key identifier for it.
OperationName getName() const { return nameAndIsInstruction.getPointer(); }
/// Return the number of operands this operation has.
unsigned getNumOperands() const;
Value *getOperand(unsigned idx);
const Value *getOperand(unsigned idx) const {
return const_cast<Operation *>(this)->getOperand(idx);
}
void setOperand(unsigned idx, Value *value);
OperationName getName() const { return name; }
// Support non-const operand iteration.
using operand_iterator = OperandIterator<Operation, Value>;
@ -126,11 +108,6 @@ public:
/// Return true if there are no users of any results of this operation.
bool use_empty() const;
/// Unlink this operation from its current block and insert it right before
/// `existingOp` which may be in the same or another block of the same
/// function.
void moveBefore(Operation *existingOp);
// Attributes. Operations may optionally carry a list of attributes that
// associate constants to names. Attributes may be dynamically added and
// removed over the lifetime of an operation.
@ -252,14 +229,6 @@ public:
return OpClass::isClassFor(this);
}
enum class OperationKind { Instruction, Statement };
// This is used to implement the dynamic casting logic, but you shouldn't
// call it directly. Use something like isa<Instruction>(someOp) instead.
OperationKind getOperationKind() const {
return nameAndIsInstruction.getInt() ? OperationKind::Instruction
: OperationKind::Statement;
}
// Returns whether the operation is commutative.
bool isCommutative() const {
if (auto *absOp = getAbstractOperation())
@ -292,25 +261,21 @@ 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 Statement *stmt);
static bool classof(const IROperandOwner *ptr);
protected:
Operation(bool isInstruction, OperationName name,
ArrayRef<NamedAttribute> attrs, MLIRContext *context);
Operation(OperationName name, ArrayRef<NamedAttribute> attrs,
Location location, MLIRContext *context);
~Operation();
private:
Operation(const Operation&) = delete;
void operator=(const Operation&) = delete;
/// This holds the name of the operation, and a bool. The bool is true if
/// this operation is an Instruction, false if it is a OperationStmt.
llvm::PointerIntPair<OperationName, 1, bool> nameAndIsInstruction;
/// This holds the name of the operation.
OperationName name;
/// This holds general named attributes for the operation.
AttributeListStorage *attrs;
@ -431,28 +396,4 @@ inline auto Operation::getResultTypes() 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);
};
template <typename From>
struct cast_convert_val<mlir::Operation, From *, From *> {
template <typename FromImpl,
typename std::enable_if<std::is_base_of<
mlir::IROperandOwner, FromImpl>::value>::type * = nullptr>
static mlir::Operation *doit_impl(const FromImpl *value) {
return cast_convert_val<mlir::Operation, mlir::IROperandOwner *,
mlir::IROperandOwner *>::doit(value);
}
static mlir::Operation *doit(const From *value) { return doit_impl(value); }
};
} // namespace llvm
#endif

View File

@ -38,7 +38,6 @@ using OperationInst = OperationStmt;
/// Operation statements represent operations inside ML functions.
class OperationStmt final
: public Operation,
public Statement,
private llvm::TrailingObjects<OperationStmt, StmtResult, StmtBlockOperand,
unsigned, StmtOperand> {
public:
@ -51,16 +50,6 @@ public:
/// Return the context this operation is associated with.
MLIRContext *getContext() const;
using Operation::isTerminator;
using Statement::dump;
using Statement::emitError;
using Statement::emitNote;
using Statement::emitWarning;
using Statement::getLoc;
using Statement::moveBefore;
using Statement::print;
using Statement::setLoc;
/// Check if this statement is a return statement.
bool isReturn() const;
@ -259,9 +248,7 @@ public:
static bool classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::OperationStmt;
}
static bool classof(const Operation *op) {
return op->getOperationKind() == OperationKind::Statement;
}
static bool classof(const Operation *op) { return true; }
private:
unsigned numOperands;

View File

@ -79,7 +79,6 @@ public:
OperationStmt,
ForStmt,
IfStmt,
Instruction,
/// These enums define ranges used for classof implementations.
STMT_LAST = IfStmt,

View File

@ -56,9 +56,9 @@ OpAsmParser::~OpAsmParser() {}
// Operation class
//===----------------------------------------------------------------------===//
Operation::Operation(bool isInstruction, OperationName name,
ArrayRef<NamedAttribute> attrs, MLIRContext *context)
: nameAndIsInstruction(name, isInstruction) {
Operation::Operation(OperationName name, ArrayRef<NamedAttribute> attrs,
Location location, MLIRContext *context)
: Statement(Kind::Operation, location), name(name) {
this->attrs = AttributeListStorage::get(attrs, context);
#ifndef NDEBUG
@ -69,41 +69,12 @@ Operation::Operation(bool isInstruction, OperationName name,
Operation::~Operation() {}
/// Return the context this operation is associated with.
MLIRContext *Operation::getContext() const {
return llvm::cast<OperationStmt>(this)->getContext();
}
/// The source location the operation was defined or derived from. Note that
/// it is possible for this pointer to be null.
Location Operation::getLoc() const {
return llvm::cast<OperationStmt>(this)->getLoc();
}
/// Set the source location the operation was defined or derived from.
void Operation::setLoc(Location loc) {
llvm::cast<OperationStmt>(this)->setLoc(loc);
}
/// Return the function this operation is defined in.
Function *Operation::getOperationFunction() {
return llvm::cast<OperationStmt>(this)->getFunction();
}
/// Return the number of operands this operation has.
unsigned Operation::getNumOperands() const {
return llvm::cast<OperationStmt>(this)->getNumOperands();
}
Value *Operation::getOperand(unsigned idx) {
return llvm::cast<OperationStmt>(this)->getOperand(idx);
}
void Operation::setOperand(unsigned idx, Value *value) {
auto *stmt = llvm::cast<OperationStmt>(this);
stmt->setOperand(idx, value);
}
/// Return the number of results this operation has.
unsigned Operation::getNumResults() const {
return llvm::cast<OperationStmt>(this)->getNumResults();
@ -164,11 +135,6 @@ bool Operation::use_empty() const {
return true;
}
void Operation::moveBefore(Operation *existingOp) {
return llvm::cast<OperationStmt>(this)->moveBefore(
llvm::cast<OperationStmt>(existingOp));
}
ArrayRef<NamedAttribute> Operation::getAttrs() const {
if (!attrs)
return {};
@ -272,36 +238,12 @@ bool Operation::constantFold(ArrayRef<Attribute> operands,
return true;
}
void Operation::print(raw_ostream &os) const {
return llvm::cast<OperationStmt>(this)->print(os);
}
void Operation::dump() const {
return llvm::cast<OperationStmt>(this)->dump();
}
/// Methods for support type inquiry through isa, cast, and dyn_cast.
bool Operation::classof(const Statement *stmt) {
return stmt->getKind() == Statement::Kind::Operation;
}
bool Operation::classof(const IROperandOwner *ptr) {
return ptr->getKind() == IROperandOwner::Kind::Instruction ||
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) {
// TODO(clattner): obsolete this.
const Operation *op;
auto *ptr = cast<OperationStmt>(value);
op = ptr;
return const_cast<Operation *>(op);
return ptr->getKind() == IROperandOwner::Kind::OperationStmt;
}
//===----------------------------------------------------------------------===//

View File

@ -360,8 +360,7 @@ OperationStmt::OperationStmt(Location location, OperationName name,
unsigned numSuccessors,
ArrayRef<NamedAttribute> attributes,
MLIRContext *context)
: Operation(/*isInstruction=*/false, name, attributes, context),
Statement(Kind::Operation, location), numOperands(numOperands),
: Operation(name, attributes, location, context), numOperands(numOperands),
numResults(numResults), numSuccs(numSuccessors) {}
OperationStmt::~OperationStmt() {

View File

@ -79,12 +79,6 @@ MLIRContext *IROperandOwner::getContext() const {
return cast<ForStmt>(this)->getContext();
case Kind::IfStmt:
return cast<IfStmt>(this)->getContext();
case Kind::Instruction:
// If we have an instruction, we can efficiently get this from the function
// the instruction is in.
auto *fn = cast<Instruction>(this)->getFunction();
return fn ? fn->getContext() : nullptr;
}
}

View File

@ -169,19 +169,8 @@ void GreedyPatternRewriteDriver::simplifyFunction(Function *currentFunction,
// top of the function.
entry = op;
// TODO: If we make terminators into Operations then we could turn this
// into a nice Operation::moveBefore(Operation*) method. We just need the
// guarantee that a block is non-empty.
// TODO(clattner): This can all be simplified away now.
if (currentFunction->isCFG()) {
auto &entryBB = currentFunction->front();
cast<OperationInst>(op)->moveBefore(&entryBB, entryBB.begin());
} else {
auto *mlFunc = cast<MLFunction>(currentFunction);
cast<OperationStmt>(op)->moveBefore(mlFunc->getBody(),
mlFunc->getBody()->begin());
}
auto &entryBB = currentFunction->front();
op->moveBefore(&entryBB, entryBB.begin());
continue;
}