@@ -130,6 +130,17 @@ static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser,
130
130
return static_cast <RetTy>(index);
131
131
}
132
132
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
+
133
144
// ===----------------------------------------------------------------------===//
134
145
// Operand bundle helpers.
135
146
// ===----------------------------------------------------------------------===//
@@ -1166,14 +1177,17 @@ LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1166
1177
return emitOpError ()
1167
1178
<< " '" << calleeName.getValue ()
1168
1179
<< " ' 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
+ }
1177
1191
}
1178
1192
1179
1193
LLVMFunctionType funcType = llvm::dyn_cast<LLVMFunctionType>(fnType);
@@ -2029,14 +2043,6 @@ LogicalResult ReturnOp::verify() {
2029
2043
// LLVM::AddressOfOp.
2030
2044
// ===----------------------------------------------------------------------===//
2031
2045
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
-
2040
2046
GlobalOp AddressOfOp::getGlobal (SymbolTableCollection &symbolTable) {
2041
2047
return dyn_cast_or_null<GlobalOp>(
2042
2048
symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
@@ -2052,6 +2058,11 @@ AliasOp AddressOfOp::getAlias(SymbolTableCollection &symbolTable) {
2052
2058
symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
2053
2059
}
2054
2060
2061
+ IFuncOp AddressOfOp::getIFunc (SymbolTableCollection &symbolTable) {
2062
+ return dyn_cast_or_null<IFuncOp>(
2063
+ symbolTable.lookupSymbolIn (parentLLVMModule (*this ), getGlobalNameAttr ()));
2064
+ }
2065
+
2055
2066
LogicalResult
2056
2067
AddressOfOp::verifySymbolUses (SymbolTableCollection &symbolTable) {
2057
2068
Operation *symbol =
@@ -2060,10 +2071,11 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2060
2071
auto global = dyn_cast_or_null<GlobalOp>(symbol);
2061
2072
auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
2062
2073
auto alias = dyn_cast_or_null<AliasOp>(symbol);
2074
+ auto ifunc = dyn_cast_or_null<IFuncOp>(symbol);
2063
2075
2064
- if (!global && !function && !alias)
2076
+ if (!global && !function && !alias && !ifunc )
2065
2077
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' " );
2067
2079
2068
2080
LLVMPointerType type = getType ();
2069
2081
if ((global && global.getAddrSpace () != type.getAddressSpace ()) ||
@@ -2673,6 +2685,69 @@ unsigned AliasOp::getAddrSpace() {
2673
2685
return ptrTy.getAddressSpace ();
2674
2686
}
2675
2687
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
+
2676
2751
// ===----------------------------------------------------------------------===//
2677
2752
// ShuffleVectorOp
2678
2753
// ===----------------------------------------------------------------------===//
@@ -4320,3 +4395,11 @@ bool mlir::LLVM::satisfiesLLVMModule(Operation *op) {
4320
4395
return op->hasTrait <OpTrait::SymbolTable>() &&
4321
4396
op->hasTrait <OpTrait::IsIsolatedFromAbove>();
4322
4397
}
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