// Builder, printer and verifier for LLVM::GlobalOp.
//===----------------------------------------------------------------------===//
+/// Returns the name used for the linkge attribute. This *must* correspond to
+/// the name of the attribute in ODS.
+static StringRef getLinkageAttrName() { return "linkage"; }
+
void GlobalOp::build(Builder *builder, OperationState &result, LLVMType type,
bool isConstant, Linkage linkage, StringRef name,
Attribute value, ArrayRef<NamedAttribute> attrs) {
result.addAttribute("constant", builder->getUnitAttr());
if (value)
result.addAttribute("value", value);
- result.addAttribute(
- "linkage", builder->getI64IntegerAttr(static_cast<int64_t>(linkage)));
+ result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr(
+ static_cast<int64_t>(linkage)));
result.attributes.append(attrs.begin(), attrs.end());
result.addRegion();
}
-// Prints the keyword for the linkage type using the printer.
-static void printLinkage(OpAsmPrinter &p, LLVM::Linkage linkage) {
+// Returns the textual representation of the given linkage.
+static StringRef linkageToStr(LLVM::Linkage linkage) {
switch (linkage) {
case LLVM::Linkage::Private:
- p << "private";
- return;
+ return "private";
case LLVM::Linkage::Internal:
- p << "internal";
- return;
+ return "internal";
case LLVM::Linkage::AvailableExternally:
- p << "available_externally";
- return;
+ return "available_externally";
case LLVM::Linkage::Linkonce:
- p << "linkonce";
- return;
+ return "linkonce";
case LLVM::Linkage::Weak:
- p << "weak";
- return;
+ return "weak";
case LLVM::Linkage::Common:
- p << "common";
- return;
+ return "common";
case LLVM::Linkage::Appending:
- p << "appending";
- return;
+ return "appending";
case LLVM::Linkage::ExternWeak:
- p << "extern_weak";
- return;
+ return "extern_weak";
case LLVM::Linkage::LinkonceODR:
- p << "linkonce_odr";
- return;
+ return "linkonce_odr";
case LLVM::Linkage::WeakODR:
- p << "weak_odr";
- return;
+ return "weak_odr";
case LLVM::Linkage::External:
- p << "external";
- return;
+ return "external";
}
llvm_unreachable("unknown linkage type");
}
+// Prints the keyword for the linkage type using the printer.
+static void printLinkage(OpAsmPrinter &p, LLVM::Linkage linkage) {
+ p << linkageToStr(linkage);
+}
+
static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
p << op.getOperationName() << ' ';
printLinkage(p, op.linkage());
p << ')';
p.printOptionalAttrDict(op.getAttrs(),
{SymbolTable::getSymbolAttrName(), "type", "constant",
- "value", "linkage"});
+ "value", getLinkageAttrName()});
// Print the trailing type unless it's a string global.
if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
"weak_odr", "external"});
if (index == -1)
return failure();
- result.addAttribute("linkage", parser.getBuilder().getI64IntegerAttr(index));
+ result.addAttribute(getLinkageAttrName(),
+ parser.getBuilder().getI64IntegerAttr(index));
return success();
}
//===----------------------------------------------------------------------===//
void LLVMFuncOp::build(Builder *builder, OperationState &result, StringRef name,
- LLVMType type, ArrayRef<NamedAttribute> attrs,
+ LLVMType type, LLVM::Linkage linkage,
+ ArrayRef<NamedAttribute> attrs,
ArrayRef<NamedAttributeList> argAttrs) {
result.addRegion();
result.addAttribute(SymbolTable::getSymbolAttrName(),
builder->getStringAttr(name));
result.addAttribute("type", TypeAttr::get(type));
+ result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr(
+ static_cast<int64_t>(linkage)));
result.attributes.append(attrs.begin(), attrs.end());
if (argAttrs.empty())
return;
result.addAttribute(getArgAttrName(i, argAttrName), argDict);
}
-// Build an LLVM function type from the given lists of input and output types.
+// Builds an LLVM function type from the given lists of input and output types.
// Returns a null type if any of the types provided are non-LLVM types, or if
// there is more than one output type.
-static Type buildLLVMFunctionType(Builder &b, ArrayRef<Type> inputs,
- ArrayRef<Type> outputs,
- impl::VariadicFlag variadicFlag,
- std::string &errorMessage) {
+static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc,
+ ArrayRef<Type> inputs, ArrayRef<Type> outputs,
+ impl::VariadicFlag variadicFlag) {
+ Builder &b = parser.getBuilder();
if (outputs.size() > 1) {
- errorMessage = "expected zero or one function result";
+ parser.emitError(loc, "failed to construct function type: expected zero or "
+ "one function result");
return {};
}
for (auto t : inputs) {
auto llvmTy = t.dyn_cast<LLVMType>();
if (!llvmTy) {
- errorMessage = "expected LLVM type for function arguments";
+ parser.emitError(loc, "failed to construct function type: expected LLVM "
+ "type for function arguments");
return {};
}
llvmInputs.push_back(llvmTy);
LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(dialect)
: outputs.front().dyn_cast<LLVMType>();
if (!llvmOutput) {
- errorMessage = "expected LLVM type for function results";
+ parser.emitError(loc, "failed to construct function type: expected LLVM "
+ "type for function results");
return {};
}
return LLVMType::getFunctionTy(llvmOutput, llvmInputs,
variadicFlag.isVariadic());
}
-// Print the LLVMFuncOp. Collects argument and result types and passes them
-// to the trait printer. Drops "void" result since it cannot be parsed back.
+// Parses an LLVM function.
+//
+// operation ::= `llvm.func` linkage? function-signature function-attributes?
+// function-body
+//
+static ParseResult parseLLVMFuncOp(OpAsmParser &parser,
+ OperationState &result) {
+ // Default to external linkage if no keyword is provided.
+ if (failed(parseOptionalLinkageKeyword(parser, result)))
+ result.addAttribute(getLinkageAttrName(),
+ parser.getBuilder().getI64IntegerAttr(
+ static_cast<int64_t>(LLVM::Linkage::External)));
+
+ StringAttr nameAttr;
+ SmallVector<OpAsmParser::OperandType, 8> entryArgs;
+ SmallVector<SmallVector<NamedAttribute, 2>, 1> argAttrs;
+ SmallVector<SmallVector<NamedAttribute, 2>, 1> resultAttrs;
+ SmallVector<Type, 8> argTypes;
+ SmallVector<Type, 4> resultTypes;
+ bool isVariadic;
+
+ auto signatureLocation = parser.getCurrentLocation();
+ if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
+ result.attributes) ||
+ impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs,
+ argTypes, argAttrs, isVariadic, resultTypes,
+ resultAttrs))
+ return failure();
+
+ auto type =
+ buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes,
+ impl::VariadicFlag(isVariadic));
+ if (!type)
+ return failure();
+ result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type));
+
+ if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
+ return failure();
+ impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs,
+ resultAttrs);
+
+ auto *body = result.addRegion();
+ return parser.parseOptionalRegion(
+ *body, entryArgs, entryArgs.empty() ? llvm::ArrayRef<Type>() : argTypes);
+}
+
+// Print the LLVMFuncOp. Collects argument and result types and passes them to
+// helper functions. Drops "void" result since it cannot be parsed back. Skips
+// the external linkage since it is the default value.
static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) {
+ p << op.getOperationName() << ' ';
+ if (op.linkage() != LLVM::Linkage::External) {
+ printLinkage(p, op.linkage());
+ p << ' ';
+ }
+ p.printSymbolName(op.getName());
+
LLVMType fnType = op.getType();
SmallVector<Type, 8> argTypes;
SmallVector<Type, 1> resTypes;
if (!returnType.getUnderlyingType()->isVoidTy())
resTypes.push_back(returnType);
- impl::printFunctionLikeOp(p, op, argTypes, op.isVarArg(), resTypes);
+ impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes);
+ impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(),
+ {getLinkageAttrName()});
+
+ // Print the body if this is not an external function.
+ Region &body = op.body();
+ if (!body.empty())
+ p.printRegion(body, /*printEntryBlockArgs=*/false,
+ /*printBlockTerminators=*/true);
}
// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
return 1;
}
+// Verifies LLVM- and implementation-specific properties of the LLVM func Op:
+// - functions don't have 'common' linkage
+// - external functions have 'external' or 'extern_weak' linkage;
+// - vararg is (currently) only supported for external functions;
+// - entry block arguments are of LLVM types and match the function signature.
static LogicalResult verify(LLVMFuncOp op) {
- if (op.isExternal())
+ if (op.linkage() == LLVM::Linkage::Common)
+ return op.emitOpError()
+ << "functions cannot have '" << linkageToStr(LLVM::Linkage::Common)
+ << "' linkage";
+
+ if (op.isExternal()) {
+ if (op.linkage() != LLVM::Linkage::External &&
+ op.linkage() != LLVM::Linkage::ExternWeak)
+ return op.emitOpError()
+ << "external functions must have '"
+ << linkageToStr(LLVM::Linkage::External) << "' or '"
+ << linkageToStr(LLVM::Linkage::ExternWeak) << "' linkage";
return success();
+ }
if (op.isVarArg())
return op.emitOpError("only external functions can be variadic");