Allow operations to hold a blocklist and add support for parsing/printing a block list for verbose printing.

PiperOrigin-RevId: 230951462
This commit is contained in:
River Riddle 2019-01-25 12:48:25 -08:00 committed by jpienaar
parent 6d37a255e2
commit c3424c3c75
17 changed files with 327 additions and 82 deletions

View File

@ -140,8 +140,18 @@ public:
static_cast<SubClass *>(this)->walkPostOrder(it->begin(), it->end());
}
RetTy walkOpInst(OperationInst *opInst) {
return static_cast<SubClass *>(this)->visitOperationInst(opInst);
void walkOpInst(OperationInst *opInst) {
static_cast<SubClass *>(this)->visitOperationInst(opInst);
for (auto &blockList : opInst->getBlockLists())
for (auto &block : blockList)
static_cast<SubClass *>(this)->walk(block.begin(), block.end());
}
void walkOpInstPostOrder(OperationInst *opInst) {
for (auto &blockList : opInst->getBlockLists())
for (auto &block : blockList)
static_cast<SubClass *>(this)->walk(block.begin(), block.end());
static_cast<SubClass *>(this)->visitOperationInst(opInst);
}
void walkForInst(ForInst *forInst) {
@ -204,7 +214,8 @@ public:
return static_cast<SubClass *>(this)->walkIfInstPostOrder(
cast<IfInst>(s));
case Instruction::Kind::OperationInst:
return static_cast<SubClass *>(this)->walkOpInst(cast<OperationInst>(s));
return static_cast<SubClass *>(this)->walkOpInstPostOrder(
cast<OperationInst>(s));
}
}

View File

@ -48,13 +48,15 @@ class Function;
class OperationInst final
: public Instruction,
private llvm::TrailingObjects<OperationInst, InstResult, BlockOperand,
unsigned, InstOperand> {
unsigned, InstOperand, BlockList> {
public:
/// Create a new OperationInst with the specific fields.
static OperationInst *
create(Location location, OperationName name, ArrayRef<Value *> operands,
ArrayRef<Type> resultTypes, ArrayRef<NamedAttribute> attributes,
ArrayRef<Block *> successors, MLIRContext *context);
static OperationInst *create(Location location, OperationName name,
ArrayRef<Value *> operands,
ArrayRef<Type> resultTypes,
ArrayRef<NamedAttribute> attributes,
ArrayRef<Block *> successors,
unsigned numBlockLists, MLIRContext *context);
/// Return the context this operation is associated with.
MLIRContext *getContext() const;
@ -226,6 +228,30 @@ public:
/// value indicates whether the attribute was present or not.
RemoveResult removeAttr(Identifier name);
//===--------------------------------------------------------------------===//
// Blocks
//===--------------------------------------------------------------------===//
/// Returns the number of block lists held by this operation.
unsigned getNumBlockLists() const { return numBlockLists; }
/// Returns the block lists held by this operation.
MutableArrayRef<BlockList> getBlockLists() {
return {getTrailingObjects<BlockList>(), numBlockLists};
}
ArrayRef<BlockList> getBlockLists() const {
return const_cast<OperationInst *>(this)->getBlockLists();
}
/// Returns the block list held by this operation at position 'index'.
BlockList &getBlockList(unsigned index) {
assert(index < numBlockLists && "invalid block list index");
return getBlockLists()[index];
}
const BlockList &getBlockList(unsigned index) const {
return const_cast<OperationInst *>(this)->getBlockList(index);
}
//===--------------------------------------------------------------------===//
// Terminators
//===--------------------------------------------------------------------===//
@ -404,7 +430,7 @@ public:
private:
unsigned numOperands;
const unsigned numResults, numSuccs;
const unsigned numResults, numSuccs, numBlockLists;
/// This holds the name of the operation.
OperationName name;
@ -414,7 +440,8 @@ private:
OperationInst(Location location, OperationName name, unsigned numOperands,
unsigned numResults, unsigned numSuccessors,
ArrayRef<NamedAttribute> attributes, MLIRContext *context);
unsigned numBlockLists, ArrayRef<NamedAttribute> attributes,
MLIRContext *context);
~OperationInst();
/// Erase the operand at 'index'.
@ -422,7 +449,7 @@ private:
// This stuff is used by the TrailingObjects template.
friend llvm::TrailingObjects<OperationInst, InstResult, BlockOperand,
unsigned, InstOperand>;
unsigned, InstOperand, BlockList>;
size_t numTrailingObjects(OverloadToken<InstOperand>) const {
return numOperands;
}
@ -432,6 +459,9 @@ private:
size_t numTrailingObjects(OverloadToken<BlockOperand>) const {
return numSuccs;
}
size_t numTrailingObjects(OverloadToken<BlockList>) const {
return numBlockLists;
}
size_t numTrailingObjects(OverloadToken<unsigned>) const { return numSuccs; }
};

View File

@ -233,6 +233,7 @@ struct OperationState {
SmallVector<NamedAttribute, 4> attributes;
/// Successors of this operation and their respective operands.
SmallVector<Block *, 1> successors;
unsigned numBlockLists = 0;
public:
OperationState(MLIRContext *context, Location location, StringRef name)
@ -244,12 +245,13 @@ public:
OperationState(MLIRContext *context, Location location, StringRef name,
ArrayRef<Value *> operands, ArrayRef<Type> types,
ArrayRef<NamedAttribute> attributes,
ArrayRef<Block *> successors = {})
ArrayRef<Block *> successors = {}, unsigned numBlockLists = 0)
: context(context), location(location), name(name, context),
operands(operands.begin(), operands.end()),
types(types.begin(), types.end()),
attributes(attributes.begin(), attributes.end()),
successors(successors.begin(), successors.end()) {}
successors(successors.begin(), successors.end()),
numBlockLists(numBlockLists) {}
void addOperands(ArrayRef<Value *> newOperands) {
assert(successors.empty() &&
@ -277,6 +279,9 @@ public:
operands.push_back(nullptr);
operands.append(succOperands.begin(), succOperands.end());
}
/// Add a new block list with the specified blocks.
void reserveBlockLists(unsigned numReserved) { numBlockLists += numReserved; }
};
} // end namespace mlir

View File

@ -365,6 +365,14 @@ static Instruction *getInstAtPosition(ArrayRef<unsigned> positions,
if (auto *elseClause = ifInst->getElse())
return getInstAtPosition(positions, level + 1, elseClause);
}
if (auto *opInst = dyn_cast<OperationInst>(&inst)) {
for (auto &blockList : opInst->getBlockLists()) {
for (auto &b : blockList)
if (auto *ret = getInstAtPosition(positions, level + 1, &b))
return ret;
}
return nullptr;
}
}
return nullptr;
}

View File

@ -165,11 +165,6 @@ bool FuncVerifier::verifyAttribute(Attribute attr, const OperationInst &op) {
}
bool FuncVerifier::verifyBlock(const Block &block, bool isTopLevel) {
// Blocks under IfInst/ForInst don't have terminators, but blocks at the top
// level of a function do.
if (isTopLevel && !block.getTerminator())
return failure("block with no terminator", block);
for (auto *arg : block.getArguments()) {
if (arg->getOwner() != &block)
return failure("block argument not owned by block", block);
@ -191,6 +186,25 @@ bool FuncVerifier::verifyBlock(const Block &block, bool isTopLevel) {
break;
}
}
// If this block is at the function level, then verify that it has a
// terminator.
if (isTopLevel) {
if (!block.getTerminator())
return failure("block with no terminator", block);
// Verify that this block is not branching to a block of a different
// region.
for (const Block *successor : block.getSuccessors())
if (successor->getParent() != block.getParent())
return failure("branching to a block of a different region",
*block.getTerminator());
} else if (block.getTerminator()) {
// TODO(riverriddle) Blocks in an IfInst/ForInst aren't allowed to have
// terminators.
return failure("non function block with terminator", block);
}
return false;
}
@ -222,6 +236,12 @@ bool FuncVerifier::verifyOperation(const OperationInst &op) {
return true;
}
// Verify that all child blocks are ok.
for (auto &blockList : op.getBlockLists())
for (auto &b : blockList)
if (verifyBlock(b, /*isTopLevel=*/false))
return true;
return false;
}
@ -249,10 +269,16 @@ bool FuncVerifier::verifyDominance(const Block &block) {
return true;
switch (inst.getKind()) {
case Instruction::Kind::OperationInst:
if (verifyOperation(cast<OperationInst>(inst)))
case Instruction::Kind::OperationInst: {
auto &opInst = cast<OperationInst>(inst);
if (verifyOperation(opInst))
return true;
for (auto &blockList : opInst.getBlockLists())
for (auto &block : blockList)
if (verifyDominance(block))
return true;
break;
}
case Instruction::Kind::For:
if (verifyDominance(*cast<ForInst>(inst).getBody()))
return true;

View File

@ -1095,6 +1095,14 @@ public:
void printSuccessorAndUseList(const OperationInst *term,
unsigned index) override;
/// Print a block list.
void printBlockList(const BlockList &blocks) {
os << " {\n";
for (auto &b : blocks)
print(&b);
os.indent(currentIndent) << "}";
}
// Print if and loop bounds.
void printDimAndSymbolList(ArrayRef<InstOperand> ops, unsigned numDims);
void printBound(AffineBound bound, const char *prefix);
@ -1163,6 +1171,9 @@ void FunctionPrinter::numberValuesInBlock(const Block &block) {
auto *opInst = cast<OperationInst>(&inst);
if (opInst->getNumResults() != 0)
numberValueID(opInst->getResult(0));
for (auto &blockList : opInst->getBlockLists())
for (const auto &block : blockList)
numberValuesInBlock(block);
break;
}
case Instruction::Kind::For: {
@ -1540,6 +1551,10 @@ void FunctionPrinter::printGenericOp(const OperationInst *op) {
[&](const Value *result) { printType(result->getType()); });
os << ')';
}
// Print any trailing block lists.
for (auto &blockList : op->getBlockLists())
printBlockList(blockList);
}
void FunctionPrinter::printSuccessorAndUseList(const OperationInst *term,

View File

@ -264,7 +264,7 @@ void BlockList::cloneInto(BlockList *dest, BlockAndValueMapping &mapper,
if (empty())
return;
Block *lastOldBlock = &dest->back();
iterator lastOldBlock = --dest->end();
for (const Block &block : *this) {
Block *newBlock = new Block();
mapper.map(&block, newBlock);
@ -306,8 +306,7 @@ void BlockList::cloneInto(BlockList *dest, BlockAndValueMapping &mapper,
};
Walker v(mapper);
for (auto it = std::next(lastOldBlock->getIterator()), e = dest->end();
it != e; ++it)
for (auto it = std::next(lastOldBlock), e = dest->end(); it != e; ++it)
v.walk(it->begin(), it->end());
}

View File

@ -305,9 +305,9 @@ Block *FuncBuilder::createBlock(Block *insertBefore) {
/// Create an operation given the fields represented as an OperationState.
OperationInst *FuncBuilder::createOperation(const OperationState &state) {
auto *op = OperationInst::create(state.location, state.name, state.operands,
state.types, state.attributes,
state.successors, context);
auto *op = OperationInst::create(
state.location, state.name, state.operands, state.types, state.attributes,
state.successors, state.numBlockLists, context);
block->getInstructions().insert(insertPoint, op);
return op;
}

View File

@ -296,12 +296,17 @@ void Instruction::dropAllReferences() {
elseBlock->dropAllReferences();
break;
}
case Kind::OperationInst:
case Kind::OperationInst: {
auto *opInst = cast<OperationInst>(this);
if (isTerminator())
for (auto &dest : cast<OperationInst>(this)->getBlockOperands())
for (auto &dest : opInst->getBlockOperands())
dest.drop();
for (auto &blockList : opInst->getBlockLists())
for (Block &block : blockList)
block.dropAllReferences();
break;
}
}
}
//===----------------------------------------------------------------------===//
@ -314,6 +319,7 @@ OperationInst *OperationInst::create(Location location, OperationName name,
ArrayRef<Type> resultTypes,
ArrayRef<NamedAttribute> attributes,
ArrayRef<Block *> successors,
unsigned numBlockLists,
MLIRContext *context) {
unsigned numSuccessors = successors.size();
@ -322,18 +328,23 @@ OperationInst *OperationInst::create(Location location, OperationName name,
unsigned numOperands = operands.size() - numSuccessors;
auto byteSize =
totalSizeToAlloc<InstResult, BlockOperand, unsigned, InstOperand>(
resultTypes.size(), numSuccessors, numSuccessors, numOperands);
totalSizeToAlloc<InstResult, BlockOperand, unsigned, InstOperand,
BlockList>(resultTypes.size(), numSuccessors,
numSuccessors, numOperands, numBlockLists);
void *rawMem = malloc(byteSize);
// Initialize the OperationInst part of the instruction.
auto inst = ::new (rawMem)
OperationInst(location, name, numOperands, resultTypes.size(),
numSuccessors, attributes, context);
numSuccessors, numBlockLists, attributes, context);
assert((numSuccessors == 0 || inst->isTerminator()) &&
"unexpected successors in a non-terminator operation");
// Initialize the block lists.
for (unsigned i = 0; i != numBlockLists; ++i)
new (&inst->getBlockList(i)) BlockList(inst);
// Initialize the results and operands.
auto instResults = inst->getInstResults();
for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
@ -401,11 +412,12 @@ OperationInst *OperationInst::create(Location location, OperationName name,
OperationInst::OperationInst(Location location, OperationName name,
unsigned numOperands, unsigned numResults,
unsigned numSuccessors,
unsigned numSuccessors, unsigned numBlockLists,
ArrayRef<NamedAttribute> attributes,
MLIRContext *context)
: Instruction(Kind::OperationInst, location), numOperands(numOperands),
numResults(numResults), numSuccs(numSuccessors), name(name) {
numResults(numResults), numSuccs(numSuccessors),
numBlockLists(numBlockLists), name(name) {
#ifndef NDEBUG
for (auto elt : attributes)
assert(elt.second != nullptr && "Attributes cannot have null entries");
@ -426,6 +438,10 @@ OperationInst::~OperationInst() {
if (isTerminator())
for (auto &successor : getBlockOperands())
successor.~BlockOperand();
// Explicitly destroy the block list.
for (auto &blockList : getBlockLists())
blockList.~BlockList();
}
/// Return true if there are no users of any results of this operation.
@ -860,9 +876,17 @@ Instruction *Instruction::clone(BlockAndValueMapping &mapper,
resultTypes.reserve(opInst->getNumResults());
for (auto *result : opInst->getResults())
resultTypes.push_back(result->getType());
unsigned numBlockLists = opInst->getNumBlockLists();
auto *newOp = OperationInst::create(getLoc(), opInst->getName(), operands,
resultTypes, opInst->getAttrs(),
successors, context);
successors, numBlockLists, context);
// Clone the block lists.
for (unsigned i = 0; i != numBlockLists; ++i)
opInst->getBlockList(i).cloneInto(&newOp->getBlockList(i), mapper,
context);
// Remember the mapping of any results.
for (unsigned i = 0, e = opInst->getNumResults(); i != e; ++i)
mapper.map(opInst->getResult(i), newOp->getResult(i));

View File

@ -2130,9 +2130,19 @@ public:
parseOptionalBlockArgList(SmallVectorImpl<BlockArgument *> &results,
Block *owner);
ParseResult parseBlock(Block *blockToUse);
ParseResult parseOperationBlockList(SmallVectorImpl<Block *> &results);
ParseResult parseBlockListBody(SmallVectorImpl<Block *> &results);
ParseResult parseBlock(Block *&block);
ParseResult parseBlockBody(Block *block);
/// Cleans up the memory for allocated blocks when a parser error occurs.
void cleanupInvalidBlocks(ArrayRef<Block *> invalidBlocks) {
// Add the referenced blocks to the function so that they can be properly
// cleaned up when the function is destroyed.
for (auto *block : invalidBlocks)
function->push_back(block);
}
/// After the function is finished parsing, this function checks to see if
/// there are any remaining issues.
ParseResult finalizeFunction(SMLoc loc);
@ -2243,21 +2253,24 @@ ParseResult FunctionParser::parseFunctionBody(bool hadNamedArguments) {
// The first block is already created and should be filled in.
auto firstBlock = &function->front();
// Parse the remaining list of blocks.
while (!consumeIf(Token::r_brace)) {
if (parseBlock(firstBlock))
return ParseFailure;
// Parse the first block.
if (parseBlock(firstBlock))
return ParseFailure;
// Create the second and subsequent block.
firstBlock = nullptr;
}
// Parse the remaining list of blocks.
SmallVector<Block *, 16> blocks;
if (parseBlockListBody(blocks))
return ParseFailure;
function->getBlocks().insert(function->end(), blocks.begin(), blocks.end());
// Verify that all referenced blocks were defined.
if (!forwardRef.empty()) {
SmallVector<std::pair<const char *, Block *>, 4> errors;
// Iteration over the map isn't deterministic, so sort by source location.
for (auto entry : forwardRef)
for (auto entry : forwardRef) {
errors.push_back({entry.second.getPointer(), entry.first});
cleanupInvalidBlocks(entry.first);
}
llvm::array_pod_sort(errors.begin(), errors.end());
for (auto entry : errors) {
@ -2270,6 +2283,55 @@ ParseResult FunctionParser::parseFunctionBody(bool hadNamedArguments) {
return finalizeFunction(braceLoc);
}
/// Block list.
///
/// block-list ::= '{' block-list-body
///
ParseResult
FunctionParser::parseOperationBlockList(SmallVectorImpl<Block *> &results) {
// Parse the '{'.
if (parseToken(Token::l_brace, "expected '{' to begin block list"))
return ParseFailure;
// Check for an empty block list.
if (consumeIf(Token::r_brace))
return ParseSuccess;
Block *currentBlock = builder.getInsertionBlock();
// Parse the first block directly to allow for it to be unnamed.
Block *block = new Block();
if (parseBlock(block)) {
cleanupInvalidBlocks(block);
return ParseFailure;
}
results.push_back(block);
// Parse the rest of the block list.
if (parseBlockListBody(results))
return ParseFailure;
// Reset insertion point to the current block.
builder.setInsertionPointToEnd(currentBlock);
return ParseSuccess;
}
/// Block list.
///
/// block-list-body ::= block* '}'
///
ParseResult
FunctionParser::parseBlockListBody(SmallVectorImpl<Block *> &results) {
// Parse the block list.
while (!consumeIf(Token::r_brace)) {
Block *newBlock = nullptr;
if (parseBlock(newBlock)) {
cleanupInvalidBlocks(results);
return ParseFailure;
}
results.push_back(newBlock);
}
return ParseSuccess;
}
/// Block declaration.
///
/// block ::= block-label? instruction* terminator-inst
@ -2277,9 +2339,7 @@ ParseResult FunctionParser::parseFunctionBody(bool hadNamedArguments) {
/// block-id ::= caret-id
/// block-arg-list ::= `(` ssa-id-and-type-list? `)`
///
ParseResult FunctionParser::parseBlock(Block *blockToUse) {
Block *block = blockToUse;
ParseResult FunctionParser::parseBlock(Block *&block) {
// The first block for a function is already created.
if (block) {
// The name for a first block is optional.
@ -2348,10 +2408,9 @@ Value *FunctionParser::createForwardReferencePlaceholder(SMLoc loc, Type type) {
// cannot be created through normal user input, allowing us to distinguish
// them.
auto name = OperationName("placeholder", getContext());
auto *inst = OperationInst::create(getEncodedSourceLocation(loc), name,
/*operands=*/{}, type,
/*attributes=*/{},
/*successors=*/{}, getContext());
auto *inst = OperationInst::create(
getEncodedSourceLocation(loc), name, /*operands=*/{}, type,
/*attributes=*/{}, /*successors=*/{}, /*numBlockLists=*/0, getContext());
forwardReferencePlaceholders[inst->getResult(0)] = loc;
return inst->getResult(0);
}
@ -2559,7 +2618,6 @@ Block *FunctionParser::getBlockNamed(StringRef name, SMLoc loc) {
if (!blockAndLoc.first) {
blockAndLoc.first = new Block();
forwardRef[blockAndLoc.first] = loc;
function->push_back(blockAndLoc.first);
blockAndLoc.second = loc;
}
@ -2574,7 +2632,7 @@ Block *FunctionParser::defineBlockNamed(StringRef name, SMLoc loc,
if (!blockAndLoc.first) {
// If the caller provided a block, use it. Otherwise create a new one.
if (!existing)
existing = builder.createBlock();
existing = new Block();
blockAndLoc.first = existing;
blockAndLoc.second = loc;
return blockAndLoc.first;
@ -2585,11 +2643,6 @@ Block *FunctionParser::defineBlockNamed(StringRef name, SMLoc loc,
// redeclaration.
if (!forwardRef.erase(blockAndLoc.first))
return nullptr;
// Move the block to the end of the function. Forward ref'd blocks are
// inserted wherever they happen to be referenced.
function->getBlocks().splice(function->end(), function->getBlocks(),
blockAndLoc.first);
return blockAndLoc.first;
}
@ -2706,17 +2759,6 @@ ParseResult FunctionParser::parseOperation() {
if (!op)
return ParseFailure;
// We just parsed an operation. If it is a recognized one, verify that it
// is structurally as we expect. If not, produce an error with a reasonable
// source location.
if (auto *opInfo = op->getAbstractOperation()) {
// We don't wan't to verify branching terminators at this time because
// the successors may not have been fully parsed yet.
if (!(op->isTerminator() && op->getNumSuccessors() != 0) &&
opInfo->verifyInvariants(op))
return ParseFailure;
}
// If the instruction had a name, register it.
if (!resultID.empty()) {
if (op->getNumResults() == 0)
@ -2813,7 +2855,27 @@ OperationInst *FunctionParser::parseGenericOperation() {
result.addSuccessor(successor, operands);
}
return builder.createOperation(result);
// Parse the optional block lists for this operation.
std::vector<SmallVector<Block *, 2>> blocks;
while (getToken().is(Token::l_brace)) {
SmallVector<Block *, 2> newBlocks;
if (parseOperationBlockList(newBlocks)) {
for (auto &blockList : blocks)
cleanupInvalidBlocks(blockList);
return nullptr;
}
blocks.emplace_back(newBlocks);
}
result.reserveBlockLists(blocks.size());
auto *opInst = builder.createOperation(result);
// Initialize the parsed block lists.
for (unsigned i = 0, e = blocks.size(); i != e; ++i) {
auto &blockList = opInst->getBlockList(i).getBlocks();
blockList.insert(blockList.end(), blocks[i].begin(), blocks[i].end());
}
return opInst;
}
namespace {
@ -3146,8 +3208,9 @@ ParseResult FunctionParser::parseForInst() {
// If parsing of the for instruction body fails,
// MLIR contains for instruction with those nested instructions that have been
// successfully parsed.
auto *forBody = forInst->getBody();
if (parseToken(Token::l_brace, "expected '{' before instruction list") ||
parseBlock(forInst->getBody()) ||
parseBlock(forBody) ||
parseToken(Token::r_brace, "expected '}' after instruction list"))
return ParseFailure;

View File

@ -109,8 +109,9 @@ struct CSE : public FunctionPass {
bool processed;
};
/// Attempt to eliminate a redundant operation.
void simplifyOperation(OperationInst *op);
/// Attempt to eliminate a redundant operation. Returns true if the operation
/// was marked for removal, false otherwise.
bool simplifyOperation(OperationInst *op);
void simplifyBlock(Block *bb);
@ -128,16 +129,16 @@ private:
char CSE::passID = 0;
/// Attempt to eliminate a redundant operation.
void CSE::simplifyOperation(OperationInst *op) {
bool CSE::simplifyOperation(OperationInst *op) {
// TODO(riverriddle) We currently only eliminate non side-effecting
// operations.
if (!op->hasNoSideEffect())
return;
return false;
// If the operation is already trivially dead just add it to the erase list.
if (op->use_empty()) {
opsToErase.push_back(op);
return;
return true;
}
// Look for an existing definition for the operation.
@ -155,18 +156,33 @@ void CSE::simplifyOperation(OperationInst *op) {
!op->getLoc().isa<UnknownLoc>()) {
existing->setLoc(op->getLoc());
}
} else {
// Otherwise, we add this operation to the known values map.
knownValues.insert(op, op);
return true;
}
// Otherwise, we add this operation to the known values map.
knownValues.insert(op, op);
return false;
}
void CSE::simplifyBlock(Block *bb) {
for (auto &i : *bb) {
switch (i.getKind()) {
case Instruction::Kind::OperationInst:
simplifyOperation(&cast<OperationInst>(i));
case Instruction::Kind::OperationInst: {
auto *opInst = cast<OperationInst>(&i);
// If the operation is simplified, we don't process any held block lists.
if (simplifyOperation(opInst))
continue;
// Simplify any held blocks.
for (auto &blockList : opInst->getBlockLists()) {
for (auto &b : blockList) {
ScopedMapTy::ScopeTy scope(knownValues);
simplifyBlock(&b);
}
}
break;
}
case Instruction::Kind::For: {
ScopedMapTy::ScopeTy scope(knownValues);
simplifyBlock(cast<ForInst>(i).getBody());

View File

@ -120,7 +120,13 @@ PassResult LoopUnroll::runOnFunction(Function *f) {
return hasInnerLoops;
}
bool visitOperationInst(OperationInst *opInst) { return false; }
bool walkOpInstPostOrder(OperationInst *opInst) {
for (auto &blockList : opInst->getBlockLists())
for (auto &block : blockList)
if (walkPostOrder(block.begin(), block.end()))
return true;
return false;
}
// FIXME: can't use base class method for this because that in turn would
// need to use the derived class method above. CRTP doesn't allow it, and

View File

@ -416,6 +416,9 @@ instantiate(FuncBuilder *b, OperationInst *opInst, VectorType hwVectorType,
"Should call the function specialized for VectorTransferReadOp");
assert(!opInst->isa<VectorTransferWriteOp>() &&
"Should call the function specialized for VectorTransferWriteOp");
if (opInst->getNumBlockLists() != 0)
return nullptr;
bool fail = false;
auto operands = map(
[hwVectorType, substitutionsMap, &fail](Value *v) -> Value * {

View File

@ -1097,6 +1097,8 @@ static OperationInst *vectorizeOneOperationInst(FuncBuilder *b,
opInst->erase();
return res;
}
if (opInst->getNumBlockLists() != 0)
return nullptr;
auto types = map([state](Value *v) { return getVectorType(v, *state); },
opInst->getResults());

View File

@ -186,7 +186,7 @@ func @func_with_ops(i32) {
func @func_with_ops(i32) {
^bb0(%a : i32):
// expected-error@+1 {{'predicate' attribute value out of range}}
%r = "cmpi"(%a, %b) {predicate: 42} : (i32, i32) -> i1
%r = "cmpi"(%a, %a) {predicate: 42} : (i32, i32) -> i1
}
// -----

View File

@ -488,6 +488,7 @@ func @return_inside_loop() -> i8 {
return %a : i8
// expected-error@-1 {{'return' op may only be at the top level of a function}}
}
return
}
// -----

View File

@ -747,3 +747,39 @@ func @type_alias() -> !i32_type_alias {
%0 = "foo"() : () -> i32
return %0 : i32
}
// CHECK-LABEL: func @verbose_if(
func @verbose_if(%N: index) {
%c = constant 200 : index
// CHECK: "if"(%c200, %arg0, %c200) {cond: #set0} : (index, index, index) -> () {
"if"(%c, %N, %c) { cond: #set0 } : (index, index, index) -> () {
// CHECK-NEXT: "add"
%y = "add"(%c, %N) : (index, index) -> index
// CHECK-NEXT: } {
} { // The else block list.
// CHECK-NEXT: "add"
%z = "add"(%c, %c) : (index, index) -> index
}
return
}
// CHECK-LABEL: func @verbose_for
func @verbose_for(%arg0 : index, %arg1 : index) {
// CHECK-NEXT: %0 = "for"() {lb: 1, ub: 10} : () -> index {
%a = "for"() {lb: 1, ub: 10 } : () -> index {
// CHECK-NEXT: %1 = "for"() {lb: 1, step: 2, ub: 100} : () -> index {
%b = "for"() {lb: 1, ub: 100, step: 2 } : () -> index {
// CHECK-NEXT: %2 = "for"(%arg0, %arg1) : (index, index) -> index {
%c = "for"(%arg0, %arg1) : (index, index) -> index {
// CHECK-NEXT: %3 = "for"(%arg0) {ub: 100} : (index) -> index {
%d = "for"(%arg0) {ub: 100 } : (index) -> index {
}
}
}
}
return
}