Skip to content

Commit b81e575

Browse files
author
git apple-llvm automerger
committed
Merge commit '46c059f925d1' from llvm.org/main into next
2 parents 4aad518 + 46c059f commit b81e575

File tree

12 files changed

+478
-31
lines changed

12 files changed

+478
-31
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ Value createGlobalString(Location loc, OpBuilder &builder, StringRef name,
223223
/// function confirms that the Operation has the desired properties.
224224
bool satisfiesLLVMModule(Operation *op);
225225

226+
/// Lookup parent Module satisfying LLVM conditions on the Module Operation.
227+
Operation *parentLLVMModule(Operation *op);
228+
226229
/// Convert an array of integer attributes to a vector of integers that can be
227230
/// used as indices in LLVM operations.
228231
template <typename IntT = int64_t>

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,10 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof",
12851285
/// Return the llvm.mlir.alias operation that defined the value referenced
12861286
/// here.
12871287
AliasOp getAlias(SymbolTableCollection &symbolTable);
1288+
1289+
/// Return the llvm.mlir.ifunc operation that defined the value referenced
1290+
/// here.
1291+
IFuncOp getIFunc(SymbolTableCollection &symbolTable);
12881292
}];
12891293

12901294
let assemblyFormat = "$global_name attr-dict `:` qualified(type($res))";
@@ -1601,6 +1605,67 @@ def LLVM_AliasOp : LLVM_Op<"mlir.alias",
16011605
let hasRegionVerifier = 1;
16021606
}
16031607

1608+
def LLVM_IFuncOp : LLVM_Op<"mlir.ifunc",
1609+
[IsolatedFromAbove, Symbol, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
1610+
let arguments = (ins
1611+
SymbolNameAttr:$sym_name,
1612+
TypeAttr:$i_func_type,
1613+
FlatSymbolRefAttr:$resolver,
1614+
TypeAttr:$resolver_type,
1615+
Linkage:$linkage,
1616+
UnitAttr:$dso_local,
1617+
DefaultValuedAttr<ConfinedAttr<I32Attr, [IntNonNegative]>, "0">:$address_space,
1618+
DefaultValuedAttr<UnnamedAddr, "mlir::LLVM::UnnamedAddr::None">:$unnamed_addr,
1619+
DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_
1620+
);
1621+
let summary = "LLVM dialect ifunc";
1622+
let description = [{
1623+
`llvm.mlir.ifunc` is a top level operation that defines a global ifunc.
1624+
It defines a new symbol and takes a symbol refering to a resolver function.
1625+
IFuncs can be called as regular functions. The function type is the same
1626+
as the IFuncType. The symbol is resolved at runtime by calling a resolver
1627+
function.
1628+
1629+
Examples:
1630+
1631+
```mlir
1632+
// IFuncs resolve a symbol at runtime using a resovler function.
1633+
llvm.mlir.ifunc external @foo: !llvm.func<f32 (i64)>, !llvm.ptr @resolver
1634+
1635+
llvm.func @foo_1(i64) -> f32
1636+
llvm.func @foo_2(i64) -> f32
1637+
1638+
llvm.func @resolve_foo() -> !llvm.ptr attributes {
1639+
%0 = llvm.mlir.addressof @foo_2 : !llvm.ptr
1640+
%1 = llvm.mlir.addressof @foo_1 : !llvm.ptr
1641+
1642+
// ... Logic selecting from foo_{1, 2}
1643+
1644+
// Return function pointer to the selected function
1645+
llvm.return %7 : !llvm.ptr
1646+
}
1647+
1648+
llvm.func @use_foo() {
1649+
// IFuncs are called as regular functions
1650+
%res = llvm.call @foo(%value) : i64 -> f32
1651+
}
1652+
```
1653+
}];
1654+
1655+
let builders = [
1656+
OpBuilder<(ins "StringRef":$name, "Type":$i_func_type,
1657+
"StringRef":$resolver, "Type":$resolver_type,
1658+
"Linkage":$linkage, "LLVM::Visibility":$visibility)>
1659+
];
1660+
1661+
let assemblyFormat = [{
1662+
custom<LLVMLinkage>($linkage) ($visibility_^)? ($unnamed_addr^)?
1663+
$sym_name `:` $i_func_type `,` $resolver_type $resolver attr-dict
1664+
}];
1665+
let hasVerifier = 1;
1666+
}
1667+
1668+
16041669
def LLVM_DSOLocalEquivalentOp : LLVM_Op<"dso_local_equivalent",
16051670
[Pure, ConstantLike, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
16061671
let arguments = (ins FlatSymbolRefAttr:$function_name);

mlir/include/mlir/Target/LLVMIR/ModuleImport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class ModuleImport {
7171
/// Converts all aliases of the LLVM module to MLIR variables.
7272
LogicalResult convertAliases();
7373

74+
/// Converts all ifuncs of the LLVM module to MLIR variables.
75+
LogicalResult convertIFuncs();
76+
7477
/// Converts the data layout of the LLVM module to an MLIR data layout
7578
/// specification.
7679
LogicalResult convertDataLayout();
@@ -320,6 +323,8 @@ class ModuleImport {
320323
/// Converts an LLVM global alias variable into an MLIR LLVM dialect alias
321324
/// operation if a conversion exists. Otherwise, returns failure.
322325
LogicalResult convertAlias(llvm::GlobalAlias *alias);
326+
// Converts an LLVM global ifunc into an MLIR LLVM dialect ifunc operation.
327+
LogicalResult convertIFunc(llvm::GlobalIFunc *ifunc);
323328
/// Returns personality of `func` as a FlatSymbolRefAttr.
324329
FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *func);
325330
/// Imports `bb` into `block`, which must be initially empty.

mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ class ModuleTranslation {
260260
return aliasesMapping.lookup(op);
261261
}
262262

263+
/// Finds an LLVM IR global value that corresponds to the given MLIR operation
264+
/// defining an IFunc.
265+
llvm::GlobalValue *lookupIFunc(Operation *op) {
266+
return ifuncMapping.lookup(op);
267+
}
268+
263269
/// Returns the OpenMP IR builder associated with the LLVM IR module being
264270
/// constructed.
265271
llvm::OpenMPIRBuilder *getOpenMPBuilder();
@@ -345,6 +351,7 @@ class ModuleTranslation {
345351
bool recordInsertions = false);
346352
LogicalResult convertFunctionSignatures();
347353
LogicalResult convertFunctions();
354+
LogicalResult convertIFuncs();
348355
LogicalResult convertComdats();
349356

350357
LogicalResult convertUnresolvedBlockAddress();
@@ -406,6 +413,10 @@ class ModuleTranslation {
406413
/// aliases.
407414
DenseMap<Operation *, llvm::GlobalValue *> aliasesMapping;
408415

416+
/// Mappings between llvm.mlir.ifunc definitions and corresponding global
417+
/// ifuncs.
418+
DenseMap<Operation *, llvm::GlobalValue *> ifuncMapping;
419+
409420
/// A stateful object used to translate types.
410421
TypeToLLVMIRTranslator typeTranslator;
411422

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
20402046
GlobalOp 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+
20552066
LogicalResult
20562067
AddressOfOp::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+
}

mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,18 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
422422
ArrayRef<llvm::Value *> operandsRef(operands);
423423
llvm::CallInst *call;
424424
if (auto attr = callOp.getCalleeAttr()) {
425-
call =
426-
builder.CreateCall(moduleTranslation.lookupFunction(attr.getValue()),
427-
operandsRef, opBundles);
425+
if (llvm::Function *function =
426+
moduleTranslation.lookupFunction(attr.getValue())) {
427+
call = builder.CreateCall(function, operandsRef, opBundles);
428+
} else {
429+
Operation *moduleOp = parentLLVMModule(&opInst);
430+
Operation *ifuncOp =
431+
moduleTranslation.symbolTable().lookupSymbolIn(moduleOp, attr);
432+
llvm::GlobalValue *ifunc = moduleTranslation.lookupIFunc(ifuncOp);
433+
llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
434+
moduleTranslation.convertType(callOp.getCalleeFunctionType()));
435+
call = builder.CreateCall(calleeType, ifunc, operandsRef, opBundles);
436+
}
428437
} else {
429438
llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
430439
moduleTranslation.convertType(callOp.getCalleeFunctionType()));
@@ -648,18 +657,21 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
648657
LLVM::LLVMFuncOp function =
649658
addressOfOp.getFunction(moduleTranslation.symbolTable());
650659
LLVM::AliasOp alias = addressOfOp.getAlias(moduleTranslation.symbolTable());
660+
LLVM::IFuncOp ifunc = addressOfOp.getIFunc(moduleTranslation.symbolTable());
651661

652662
// The verifier should not have allowed this.
653-
assert((global || function || alias) &&
654-
"referencing an undefined global, function, or alias");
663+
assert((global || function || alias || ifunc) &&
664+
"referencing an undefined global, function, alias, or ifunc");
655665

656666
llvm::Value *llvmValue = nullptr;
657667
if (global)
658668
llvmValue = moduleTranslation.lookupGlobal(global);
659669
else if (alias)
660670
llvmValue = moduleTranslation.lookupAlias(alias);
661-
else
671+
else if (function)
662672
llvmValue = moduleTranslation.lookupFunction(function.getName());
673+
else
674+
llvmValue = moduleTranslation.lookupIFunc(ifunc);
663675

664676
moduleTranslation.mapValue(addressOfOp.getResult(), llvmValue);
665677
return success();

0 commit comments

Comments
 (0)