@@ -130,6 +130,17 @@ static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser,
130130 return static_cast <RetTy>(index);
131131}
132132
133+ static void printLLVMLinkage (OpAsmPrinter &p, Operation *, LinkageAttr val) {
134+ p << stringifyLinkage (val.getLinkage ());
135+ }
136+
137+ static ParseResult parseLLVMLinkage (OpAsmParser &p, LinkageAttr &val) {
138+ val = LinkageAttr::get (
139+ p.getContext (),
140+ parseOptionalLLVMKeyword<LLVM::Linkage>(p, LLVM::Linkage::External));
141+ return success ();
142+ }
143+
133144// ===----------------------------------------------------------------------===//
134145// Operand bundle helpers.
135146// ===----------------------------------------------------------------------===//
@@ -1166,14 +1177,17 @@ LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
11661177 return emitOpError ()
11671178 << " '" << calleeName.getValue ()
11681179 << " ' does not reference a symbol in the current scope" ;
1169- auto fn = dyn_cast<LLVMFuncOp>(callee);
1170- if (!fn)
1171- return emitOpError () << " '" << calleeName.getValue ()
1172- << " ' does not reference a valid LLVM function" ;
1173-
1174- if (failed (verifyCallOpDebugInfo (*this , fn)))
1175- return failure ();
1176- fnType = fn.getFunctionType ();
1180+ if (auto fn = dyn_cast<LLVMFuncOp>(callee)) {
1181+ if (failed (verifyCallOpDebugInfo (*this , fn)))
1182+ return failure ();
1183+ fnType = fn.getFunctionType ();
1184+ } else if (auto ifunc = dyn_cast<IFuncOp>(callee)) {
1185+ fnType = ifunc.getIFuncType ();
1186+ } else {
1187+ return emitOpError ()
1188+ << " '" << calleeName.getValue ()
1189+ << " ' does not reference a valid LLVM function or IFunc" ;
1190+ }
11771191 }
11781192
11791193 LLVMFunctionType funcType = llvm::dyn_cast<LLVMFunctionType>(fnType);
@@ -2029,14 +2043,6 @@ LogicalResult ReturnOp::verify() {
20292043// LLVM::AddressOfOp.
20302044// ===----------------------------------------------------------------------===//
20312045
2032- static Operation *parentLLVMModule (Operation *op) {
2033- Operation *module = op->getParentOp ();
2034- while (module && !satisfiesLLVMModule (module ))
2035- module = module ->getParentOp ();
2036- assert (module && " unexpected operation outside of a module" );
2037- return module ;
2038- }
2039-
20402046GlobalOp AddressOfOp::getGlobal (SymbolTableCollection &symbolTable) {
20412047 return dyn_cast_or_null<GlobalOp>(
20422048 symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
@@ -2052,6 +2058,11 @@ AliasOp AddressOfOp::getAlias(SymbolTableCollection &symbolTable) {
20522058 symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
20532059}
20542060
2061+ IFuncOp AddressOfOp::getIFunc (SymbolTableCollection &symbolTable) {
2062+ return dyn_cast_or_null<IFuncOp>(
2063+ symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
2064+ }
2065+
20552066LogicalResult
20562067AddressOfOp::verifySymbolUses (SymbolTableCollection &symbolTable) {
20572068 Operation *symbol =
@@ -2060,10 +2071,11 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
20602071 auto global = dyn_cast_or_null<GlobalOp>(symbol);
20612072 auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
20622073 auto alias = dyn_cast_or_null<AliasOp>(symbol);
2074+ auto ifunc = dyn_cast_or_null<IFuncOp>(symbol);
20632075
2064- if (!global && !function && !alias)
2076+ if (!global && !function && !alias && !ifunc )
20652077 return emitOpError (" must reference a global defined by 'llvm.mlir.global', "
2066- " 'llvm.mlir.alias' or 'llvm.func'" );
2078+ " 'llvm.mlir.alias' or 'llvm.func' or 'llvm.mlir.ifunc' " );
20672079
20682080 LLVMPointerType type = getType ();
20692081 if ((global && global.getAddrSpace () != type.getAddressSpace ()) ||
@@ -2673,6 +2685,69 @@ unsigned AliasOp::getAddrSpace() {
26732685 return ptrTy.getAddressSpace ();
26742686}
26752687
2688+ // ===----------------------------------------------------------------------===//
2689+ // IFuncOp
2690+ // ===----------------------------------------------------------------------===//
2691+
2692+ void IFuncOp::build (OpBuilder &builder, OperationState &result, StringRef name,
2693+ Type iFuncType, StringRef resolverName, Type resolverType,
2694+ Linkage linkage, LLVM::Visibility visibility) {
2695+ return build (builder, result, name, iFuncType, resolverName, resolverType,
2696+ linkage, /* dso_local=*/ false , /* address_space=*/ 0 ,
2697+ UnnamedAddr::None, visibility);
2698+ }
2699+
2700+ LogicalResult IFuncOp::verifySymbolUses (SymbolTableCollection &symbolTable) {
2701+ Operation *symbol =
2702+ symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getResolverAttr ());
2703+ // This matches LLVM IR verification logic, see llvm/lib/IR/Verifier.cpp
2704+ auto resolver = dyn_cast<LLVMFuncOp>(symbol);
2705+ auto alias = dyn_cast<AliasOp>(symbol);
2706+ while (alias) {
2707+ Block &initBlock = alias.getInitializerBlock ();
2708+ auto returnOp = cast<ReturnOp>(initBlock.getTerminator ());
2709+ auto addrOp = dyn_cast<AddressOfOp>(returnOp.getArg ().getDefiningOp ());
2710+ // FIXME: This is a best effort solution. The AliasOp body might be more
2711+ // complex and in that case we bail out with success. To completely match
2712+ // the LLVM IR logic it would be necessary to implement proper alias and
2713+ // cast stripping.
2714+ if (!addrOp)
2715+ return success ();
2716+ resolver = addrOp.getFunction (symbolTable);
2717+ alias = addrOp.getAlias (symbolTable);
2718+ }
2719+ if (!resolver)
2720+ return emitOpError (" must have a function resolver" );
2721+ Linkage linkage = resolver.getLinkage ();
2722+ if (resolver.isExternal () || linkage == Linkage::AvailableExternally)
2723+ return emitOpError (" resolver must be a definition" );
2724+ if (!isa<LLVMPointerType>(resolver.getFunctionType ().getReturnType ()))
2725+ return emitOpError (" resolver must return a pointer" );
2726+ auto resolverPtr = dyn_cast<LLVMPointerType>(getResolverType ());
2727+ if (!resolverPtr || resolverPtr.getAddressSpace () != getAddressSpace ())
2728+ return emitOpError (" resolver has incorrect type" );
2729+ return success ();
2730+ }
2731+
2732+ LogicalResult IFuncOp::verify () {
2733+ switch (getLinkage ()) {
2734+ case Linkage::External:
2735+ case Linkage::Internal:
2736+ case Linkage::Private:
2737+ case Linkage::Weak:
2738+ case Linkage::WeakODR:
2739+ case Linkage::Linkonce:
2740+ case Linkage::LinkonceODR:
2741+ break ;
2742+ default :
2743+ return emitOpError () << " '" << stringifyLinkage (getLinkage ())
2744+ << " ' linkage not supported in ifuncs, available "
2745+ " options: private, internal, linkonce, weak, "
2746+ " linkonce_odr, weak_odr, or external linkage" ;
2747+ }
2748+ return success ();
2749+ }
2750+
26762751// ===----------------------------------------------------------------------===//
26772752// ShuffleVectorOp
26782753// ===----------------------------------------------------------------------===//
@@ -4320,3 +4395,11 @@ bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
43204395 return op->hasTrait <OpTrait::SymbolTable>() &&
43214396 op->hasTrait <OpTrait::IsIsolatedFromAbove>();
43224397}
4398+
4399+ Operation *mlir::LLVM::parentLLVMModule (Operation *op) {
4400+ Operation *module = op->getParentOp ();
4401+ while (module && !satisfiesLLVMModule (module ))
4402+ module = module ->getParentOp ();
4403+ assert (module && " unexpected operation outside of a module" );
4404+ return module ;
4405+ }
0 commit comments