}
//===----------------------------------------------------------------------===//
-// Printing/parsing for LLVM::BrOp.
-//===----------------------------------------------------------------------===//
-
-static void printBrOp(OpAsmPrinter &p, BrOp &op) {
- p << op.getOperationName() << ' ';
- p.printSuccessorAndUseList(op.getOperation(), 0);
- p.printOptionalAttrDict(op.getAttrs());
-}
-
-// <operation> ::= `llvm.br` bb-id (`[` ssa-use-and-type-list `]`)?
-// attribute-dict?
-static ParseResult parseBrOp(OpAsmParser &parser, OperationState &result) {
- Block *dest;
- SmallVector<Value, 4> operands;
- if (parser.parseSuccessorAndUseList(dest, operands) ||
- parser.parseOptionalAttrDict(result.attributes))
- return failure();
-
- result.addSuccessor(dest, operands);
- return success();
-}
-
-//===----------------------------------------------------------------------===//
-// Printing/parsing for LLVM::CondBrOp.
-//===----------------------------------------------------------------------===//
-
-static void printCondBrOp(OpAsmPrinter &p, CondBrOp &op) {
- p << op.getOperationName() << ' ' << op.getOperand(0) << ", ";
- p.printSuccessorAndUseList(op.getOperation(), 0);
- p << ", ";
- p.printSuccessorAndUseList(op.getOperation(), 1);
- p.printOptionalAttrDict(op.getAttrs());
-}
-
-// <operation> ::= `llvm.cond_br` ssa-use `,`
-// bb-id (`[` ssa-use-and-type-list `]`)? `,`
-// bb-id (`[` ssa-use-and-type-list `]`)? attribute-dict?
-static ParseResult parseCondBrOp(OpAsmParser &parser, OperationState &result) {
- Block *trueDest;
- Block *falseDest;
- SmallVector<Value, 4> trueOperands;
- SmallVector<Value, 4> falseOperands;
- OpAsmParser::OperandType condition;
-
- Builder &builder = parser.getBuilder();
- auto *llvmDialect =
- builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
- auto i1Type = LLVM::LLVMType::getInt1Ty(llvmDialect);
-
- if (parser.parseOperand(condition) || parser.parseComma() ||
- parser.parseSuccessorAndUseList(trueDest, trueOperands) ||
- parser.parseComma() ||
- parser.parseSuccessorAndUseList(falseDest, falseOperands) ||
- parser.parseOptionalAttrDict(result.attributes) ||
- parser.resolveOperand(condition, i1Type, result.operands))
- return failure();
-
- result.addSuccessor(trueDest, trueOperands);
- result.addSuccessor(falseDest, falseOperands);
- return success();
-}
-
-//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::ReturnOp.
//===----------------------------------------------------------------------===//
FunctionalTypeDirective,
OperandsDirective,
ResultsDirective,
+ SuccessorsDirective,
TypeDirective,
/// This element is a literal.
AttributeVariable,
OperandVariable,
ResultVariable,
+ SuccessorVariable,
/// This element is an optional element.
Optional,
/// This class represents a variable that refers to a result.
using ResultVariable =
VariableElement<NamedTypeConstraint, Element::Kind::ResultVariable>;
+
+/// This class represents a variable that refers to a successor.
+using SuccessorVariable =
+ VariableElement<NamedSuccessor, Element::Kind::SuccessorVariable>;
} // end anonymous namespace
//===----------------------------------------------------------------------===//
/// all of the results of an operation.
using ResultsDirective = DirectiveElement<Element::Kind::ResultsDirective>;
+/// This class represents the `successors` directive. This directive represents
+/// all of the successors of an operation.
+using SuccessorsDirective =
+ DirectiveElement<Element::Kind::SuccessorsDirective>;
+
/// This class represents the `attr-dict` directive. This directive represents
/// the attribute dictionary of the operation.
class AttrDictDirective
/// Generate the c++ to resolve the types of operands and results during
/// parsing.
void genParserTypeResolution(Operator &op, OpMethodBody &body);
+ /// Generate the c++ to resolve successors during parsing.
+ void genParserSuccessorResolution(Operator &op, OpMethodBody &body);
/// Generate the operation printer from this format.
void genPrinter(Operator &op, OpClass &opClass);
{1}Types = {0}__{1}_functionType.getResults();
)";
+/// The code snippet used to generate a parser call for a successor list.
+///
+/// {0}: The name for the successor list.
+const char *successorListParserCode = R"(
+ SmallVector<std::pair<Block *, SmallVector<Value, 4>>, 2> {0}Successors;
+ {
+ Block *succ;
+ SmallVector<Value, 4> succOperands;
+ // Parse the first successor.
+ auto firstSucc = parser.parseOptionalSuccessorAndUseList(succ,
+ succOperands);
+ if (firstSucc.hasValue()) {
+ if (failed(*firstSucc))
+ return failure();
+ {0}Successors.emplace_back(succ, succOperands);
+
+ // Parse any trailing successors.
+ while (succeeded(parser.parseOptionalComma())) {
+ succOperands.clear();
+ if (parser.parseSuccessorAndUseList(succ, succOperands))
+ return failure();
+ {0}Successors.emplace_back(succ, succOperands);
+ }
+ }
+ }
+)";
+
+/// The code snippet used to generate a parser call for a successor.
+///
+/// {0}: The name of the successor.
+const char *successorParserCode = R"(
+ Block *{0}Successor = nullptr;
+ SmallVector<Value, 4> {0}Operands;
+ if (parser.parseSuccessorAndUseList({0}Successor, {0}Operands))
+ return failure();
+)";
+
+/// The code snippet used to resolve a list of parsed successors.
+///
+/// {0}: The name of the successor list.
+const char *resolveSuccessorListParserCode = R"(
+ for (auto &succAndArgs : {0}Successors)
+ result.addSuccessor(succAndArgs.first, succAndArgs.second);
+)";
+
/// Get the name used for the type list for the given type directive operand.
/// 'isVariadic' is set to true if the operand has variadic types.
static StringRef getTypeListName(Element *arg, bool &isVariadic) {
bool isVariadic = operand->getVar()->isVariadic();
body << formatv(isVariadic ? variadicOperandParserCode : operandParserCode,
operand->getVar()->name);
+ } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) {
+ bool isVariadic = successor->getVar()->isVariadic();
+ body << formatv(isVariadic ? successorListParserCode : successorParserCode,
+ successor->getVar()->name);
/// Directives.
} else if (auto *attrDict = dyn_cast<AttrDictDirective>(element)) {
<< " SmallVector<OpAsmParser::OperandType, 4> allOperands;\n"
<< " if (parser.parseOperandList(allOperands))\n"
<< " return failure();\n";
+ } else if (isa<SuccessorsDirective>(element)) {
+ body << llvm::formatv(successorListParserCode, "full");
} else if (auto *dir = dyn_cast<TypeDirective>(element)) {
bool isVariadic = false;
StringRef listName = getTypeListName(dir->getOperand(), isVariadic);
for (auto &element : elements)
genElementParser(element.get(), body, attrTypeCtx);
- // Generate the code to resolve the operand and result types now that they
- // have been parsed.
+ // Generate the code to resolve the operand/result types and successors now
+ // that they have been parsed.
genParserTypeResolution(op, body);
+ genParserSuccessorResolution(op, body);
body << " return success();\n";
}
}
}
+void OperationFormat::genParserSuccessorResolution(Operator &op,
+ OpMethodBody &body) {
+ // Check for the case where all successors were parsed.
+ bool hasAllSuccessors = llvm::any_of(
+ elements, [](auto &elt) { return isa<SuccessorsDirective>(elt.get()); });
+ if (hasAllSuccessors) {
+ body << llvm::formatv(resolveSuccessorListParserCode, "full");
+ return;
+ }
+
+ // Otherwise, handle each successor individually.
+ for (const NamedSuccessor &successor : op.getSuccessors()) {
+ if (successor.isVariadic()) {
+ body << llvm::formatv(resolveSuccessorListParserCode, successor.name);
+ continue;
+ }
+
+ body << llvm::formatv(" result.addSuccessor({0}Successor, {0}Operands);\n",
+ successor.name);
+ }
+}
+
//===----------------------------------------------------------------------===//
// PrinterGen
/// Generate the code for printing the given element.
static void genElementPrinter(Element *element, OpMethodBody &body,
- OperationFormat &fmt, bool &shouldEmitSpace,
- bool &lastWasPunctuation) {
+ OperationFormat &fmt, Operator &op,
+ bool &shouldEmitSpace, bool &lastWasPunctuation) {
if (LiteralElement *literal = dyn_cast<LiteralElement>(element))
return genLiteralPrinter(literal->getLiteral(), body, shouldEmitSpace,
lastWasPunctuation);
// Emit each of the elements.
for (Element &childElement : optional->getElements())
- genElementPrinter(&childElement, body, fmt, shouldEmitSpace,
+ genElementPrinter(&childElement, body, fmt, op, shouldEmitSpace,
lastWasPunctuation);
body << " }\n";
return;
body << " p.printAttribute(" << var->name << "Attr());\n";
} else if (auto *operand = dyn_cast<OperandVariable>(element)) {
body << " p << " << operand->getVar()->name << "();\n";
+ } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) {
+ const NamedSuccessor *var = successor->getVar();
+ if (var->isVariadic()) {
+ body << " {\n"
+ << " auto succRange = " << var->name << "();\n"
+ << " auto opSuccBegin = getOperation()->successor_begin();\n"
+ << " int i = succRange.begin() - opSuccBegin;\n"
+ << " int e = i + succRange.size();\n"
+ << " interleaveComma(llvm::seq<int>(i, e), p, [&](int i) {\n"
+ << " p.printSuccessorAndUseList(*this, i);\n"
+ << " });\n"
+ << " }\n";
+ return;
+ }
+
+ unsigned index = successor->getVar() - op.successor_begin();
+ body << " p.printSuccessorAndUseList(*this, " << index << ");\n";
} else if (isa<OperandsDirective>(element)) {
body << " p << getOperation()->getOperands();\n";
+ } else if (isa<SuccessorsDirective>(element)) {
+ body << " interleaveComma(llvm::seq<int>(0, "
+ "getOperation()->getNumSuccessors()), p, [&](int i) {"
+ << " p.printSuccessorAndUseList(*this, i);"
+ << " });\n";
} else if (auto *dir = dyn_cast<TypeDirective>(element)) {
body << " p << ";
genTypeOperandPrinter(dir->getOperand(), body) << ";\n";
// punctuation.
bool shouldEmitSpace = true, lastWasPunctuation = false;
for (auto &element : elements)
- genElementPrinter(element.get(), body, *this, shouldEmitSpace,
+ genElementPrinter(element.get(), body, *this, op, shouldEmitSpace,
lastWasPunctuation);
}
kw_functional_type,
kw_operands,
kw_results,
+ kw_successors,
kw_type,
keyword_end,
.Case("functional-type", Token::kw_functional_type)
.Case("operands", Token::kw_operands)
.Case("results", Token::kw_results)
+ .Case("successors", Token::kw_successors)
.Case("type", Token::kw_type)
.Default(Token::identifier);
return Token(kind, str);
llvm::SMLoc loc, bool isTopLevel);
LogicalResult parseResultsDirective(std::unique_ptr<Element> &element,
llvm::SMLoc loc, bool isTopLevel);
+ LogicalResult parseSuccessorsDirective(std::unique_ptr<Element> &element,
+ llvm::SMLoc loc, bool isTopLevel);
LogicalResult parseTypeDirective(std::unique_ptr<Element> &element, Token tok,
bool isTopLevel);
LogicalResult parseTypeDirectiveOperand(std::unique_ptr<Element> &element);
// The following are various bits of format state used for verification
// during parsing.
bool hasAllOperands = false, hasAttrDict = false;
+ bool hasAllSuccessors = false;
llvm::SmallBitVector seenOperandTypes, seenResultTypes;
llvm::DenseSet<const NamedTypeConstraint *> seenOperands;
llvm::DenseSet<const NamedAttribute *> seenAttrs;
+ llvm::DenseSet<const NamedSuccessor *> seenSuccessors;
llvm::DenseSet<const NamedTypeConstraint *> optionalVariables;
};
} // end anonymous namespace
auto it = buildableTypes.insert({*builder, buildableTypes.size()});
fmt.operandTypes[i].setBuilderIdx(it.first->second);
}
+
+ // Check that all of the successors are within the format.
+ if (!hasAllSuccessors) {
+ for (unsigned i = 0, e = op.getNumSuccessors(); i != e; ++i) {
+ const NamedSuccessor &successor = op.getSuccessor(i);
+ if (!seenSuccessors.count(&successor)) {
+ return emitError(loc, "format missing instance of successor #" +
+ Twine(i) + "('" + successor.name + "')");
+ }
+ }
+ }
return success();
}
element = std::make_unique<ResultVariable>(result);
return success();
}
- return emitError(loc, "expected variable to refer to a argument or result");
+ /// Successors.
+ if (const auto *successor = findArg(op.getSuccessors(), name)) {
+ if (!isTopLevel)
+ return emitError(loc, "successors can only be used at the top level");
+ if (hasAllSuccessors || !seenSuccessors.insert(successor).second)
+ return emitError(loc, "successor '" + name + "' is already bound");
+ element = std::make_unique<SuccessorVariable>(successor);
+ return success();
+ }
+ return emitError(
+ loc, "expected variable to refer to a argument, result, or successor");
}
LogicalResult FormatParser::parseDirective(std::unique_ptr<Element> &element,
return parseOperandsDirective(element, dirTok.getLoc(), isTopLevel);
case Token::kw_results:
return parseResultsDirective(element, dirTok.getLoc(), isTopLevel);
+ case Token::kw_successors:
+ return parseSuccessorsDirective(element, dirTok.getLoc(), isTopLevel);
case Token::kw_type:
return parseTypeDirective(element, dirTok, isTopLevel);
}
LogicalResult
+FormatParser::parseSuccessorsDirective(std::unique_ptr<Element> &element,
+ llvm::SMLoc loc, bool isTopLevel) {
+ if (!isTopLevel)
+ return emitError(loc,
+ "'successors' is only valid as a top-level directive");
+ if (hasAllSuccessors || !seenSuccessors.empty())
+ return emitError(loc, "'successors' directive creates overlap in format");
+ hasAllSuccessors = true;
+ element = std::make_unique<SuccessorsDirective>();
+ return success();
+}
+
+LogicalResult
FormatParser::parseTypeDirective(std::unique_ptr<Element> &element, Token tok,
bool isTopLevel) {
llvm::SMLoc loc = tok.getLoc();