[Mlir-commits] [mlir] 4fb96f2 - [MLIR][LLVM] Implement LLVM dialect support for global aliases (#125295)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Feb 5 18:19:39 PST 2025
Author: Bruno Cardoso Lopes
Date: 2025-02-05T18:19:36-08:00
New Revision: 4fb96f203e8badc8065d6773bf8780c2e65cc142
URL: https://github.com/llvm/llvm-project/commit/4fb96f203e8badc8065d6773bf8780c2e65cc142
DIFF: https://github.com/llvm/llvm-project/commit/4fb96f203e8badc8065d6773bf8780c2e65cc142.diff
LOG: [MLIR][LLVM] Implement LLVM dialect support for global aliases (#125295)
This includes support for module translation, module import and add tests for both.
Fix https://github.com/llvm/llvm-project/issues/115390
ClangIR cannot currently lower global aliases to LLVM because of missing support for this.
Added:
mlir/test/Dialect/LLVMIR/alias.mlir
mlir/test/Target/LLVMIR/Import/alias.ll
mlir/test/Target/LLVMIR/alias.mlir
Modified:
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/include/mlir/Target/LLVMIR/ModuleImport.h
mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/test/Dialect/LLVMIR/invalid.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index ee6e10efed4f16b..eed3b2cdb91ea13 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1167,12 +1167,12 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof",
let arguments = (ins FlatSymbolRefAttr:$global_name);
let results = (outs LLVM_AnyPointer:$res);
- let summary = "Creates a pointer pointing to a global or a function";
+ let summary = "Creates a pointer pointing to a global, alias or a function";
let description = [{
- Creates an SSA value containing a pointer to a global variable or constant
- defined by `llvm.mlir.global`. The global value can be defined after its
- first referenced. If the global value is a constant, storing into it is not
+ Creates an SSA value containing a pointer to a global value (function,
+ variable or alias). The global value can be defined after its first
+ referenced. If the global value is a constant, storing into it is not
allowed.
Examples:
@@ -1190,10 +1190,19 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof",
// The function address can be used for indirect calls.
llvm.call %2() : !llvm.ptr, () -> ()
+
+ // Get the address of an aliased global.
+ %3 = llvm.mlir.addressof @const_alias : !llvm.ptr
}
// Define the global.
llvm.mlir.global @const(42 : i32) : i32
+
+ // Define an alias.
+ llvm.mlir.alias @const_alias : i32 {
+ %0 = llvm.mlir.addressof @const : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+ }
```
}];
@@ -1212,6 +1221,14 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof",
build($_builder, $_state,
LLVM::LLVMPointerType::get($_builder.getContext()), func.getName());
$_state.addAttributes(attrs);
+ }]>,
+ OpBuilder<(ins "AliasOp":$alias,
+ CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
+ [{
+ build($_builder, $_state,
+ LLVM::LLVMPointerType::get($_builder.getContext(), alias.getAddrSpace()),
+ alias.getSymName());
+ $_state.addAttributes(attrs);
}]>
];
@@ -1222,6 +1239,10 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof",
/// Return the llvm.func operation that is referenced here.
LLVMFuncOp getFunction(SymbolTableCollection &symbolTable);
+
+ /// Return the llvm.mlir.alias operation that defined the value referenced
+ /// here.
+ AliasOp getAlias(SymbolTableCollection &symbolTable);
}];
let assemblyFormat = "$global_name attr-dict `:` qualified(type($res))";
@@ -1447,6 +1468,85 @@ def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [
let hasVerifier = 1;
}
+def LLVM_AliasOp : LLVM_Op<"mlir.alias",
+ [IsolatedFromAbove, SingleBlockImplicitTerminator<"ReturnOp">, Symbol]> {
+ let arguments = (ins
+ TypeAttr:$alias_type,
+ StrAttr:$sym_name,
+ Linkage:$linkage,
+ UnitAttr:$dso_local,
+ UnitAttr:$thread_local_,
+ OptionalAttr<UnnamedAddr>:$unnamed_addr,
+ DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_
+ );
+ let summary = "LLVM dialect alias.";
+ let description = [{
+ `llvm.mlir.alias` is a top level operation that defines a global alias for
+ global variables and functions. The operation is always initialized by
+ using a initializer region which could be a direct map to another global
+ value or contain some address computation on top of it.
+
+ It uses a symbol for its value, which will be uniqued by the module
+ with respect to other symbols in it.
+
+ Similarly to functions and globals, they can also have a linkage attribute.
+ This attribute is placed between `llvm.mlir.alias` and the symbol name. If
+ the attribute is omitted, `external` linkage is assumed by default.
+
+ Examples:
+
+ ```mlir
+ // Global alias use @-identifiers.
+ llvm.mlir.alias external @foo_alias {addr_space = 0 : i32} : !llvm.ptr {
+ %0 = llvm.mlir.addressof @some_function : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+ }
+
+ // More complex initialization.
+ llvm.mlir.alias linkonce_odr hidden @glob
+ {addr_space = 0 : i32, dso_local} : !llvm.array<32 x i32> {
+ %0 = llvm.mlir.constant(1234 : i64) : i64
+ %1 = llvm.mlir.addressof @glob.private : !llvm.ptr
+ %2 = llvm.ptrtoint %1 : !llvm.ptr to i64
+ %3 = llvm.add %2, %0 : i64
+ %4 = llvm.inttoptr %3 : i64 to !llvm.ptr
+ llvm.return %4 : !llvm.ptr
+ }
+ ```
+ }];
+ let regions = (region SizedRegion<1>:$initializer);
+
+ let builders = [
+ OpBuilder<(ins "Type":$type, "Linkage":$linkage,
+ "StringRef":$name,
+ CArg<"bool", "false">:$dsoLocal,
+ CArg<"bool", "false">:$thread_local_,
+ CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
+ ];
+
+ let extraClassDeclaration = [{
+ /// Return the LLVM type of the global alias.
+ Type getType() {
+ return getAliasType();
+ }
+ /// Return the initializer region. It's always present and terminates
+ /// with an `llvm.return` op with the initializer value.
+ Region &getInitializerRegion() {
+ return getOperation()->getRegion(0);
+ }
+ Block &getInitializerBlock() {
+ return getInitializerRegion().front();
+ }
+ // Retrieve address space information from the initializer block
+ // result.
+ unsigned getAddrSpace();
+ }];
+
+ let hasCustomAssemblyFormat = 1;
+ let hasVerifier = 1;
+ let hasRegionVerifier = 1;
+}
+
def LLVM_ComdatSelectorOp : LLVM_Op<"comdat_selector", [Symbol]> {
let arguments = (ins
SymbolNameAttr:$sym_name,
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index 80ae4d679624c25..d4032c6bc4356b5 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -67,6 +67,9 @@ class ModuleImport {
/// Converts all global variables of the LLVM module to MLIR global variables.
LogicalResult convertGlobals();
+ /// Converts all aliases of the LLVM module to MLIR variables.
+ LogicalResult convertAliases();
+
/// Converts the data layout of the LLVM module to an MLIR data layout
/// specification.
LogicalResult convertDataLayout();
@@ -288,6 +291,9 @@ class ModuleImport {
LogicalResult convertGlobal(llvm::GlobalVariable *globalVar);
/// Imports the magic globals "global_ctors" and "global_dtors".
LogicalResult convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar);
+ /// Converts an LLVM global alias variable into an MLIR LLVM dialect alias
+ /// operation if a conversion exists. Otherwise, returns failure.
+ LogicalResult convertAlias(llvm::GlobalAlias *alias);
/// Returns personality of `func` as a FlatSymbolRefAttr.
FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *func);
/// Imports `bb` into `block`, which must be initially empty.
@@ -406,6 +412,8 @@ class ModuleImport {
Operation *constantInsertionOp = nullptr;
/// Operation to insert the next global after.
Operation *globalInsertionOp = nullptr;
+ /// Operation to insert the next alias after.
+ Operation *aliasInsertionOp = nullptr;
/// Operation to insert comdat selector operations into.
ComdatOp globalComdatOp = nullptr;
/// The current context.
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 1b62437761ed9d2..ec6182fb34413fb 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -188,6 +188,12 @@ class ModuleTranslation {
return globalsMapping.lookup(op);
}
+ /// Finds an LLVM IR global value that corresponds to the given MLIR operation
+ /// defining a global alias value.
+ llvm::GlobalValue *lookupAlias(Operation *op) {
+ return aliasesMapping.lookup(op);
+ }
+
/// Returns the OpenMP IR builder associated with the LLVM IR module being
/// constructed.
llvm::OpenMPIRBuilder *getOpenMPBuilder();
@@ -321,7 +327,13 @@ class ModuleTranslation {
LogicalResult convertFunctionSignatures();
LogicalResult convertFunctions();
LogicalResult convertComdats();
- LogicalResult convertGlobals();
+
+ /// Handle conversion for both globals and global aliases.
+ ///
+ /// - Create named global variables that correspond to llvm.mlir.global
+ /// definitions, similarly Convert llvm.global_ctors and global_dtors ops.
+ /// - Create global alias that correspond to llvm.mlir.alias.
+ LogicalResult convertGlobalsAndAliases();
LogicalResult convertOneFunction(LLVMFuncOp func);
LogicalResult convertBlockImpl(Block &bb, bool ignoreArguments,
llvm::IRBuilderBase &builder,
@@ -366,6 +378,10 @@ class ModuleTranslation {
/// Mappings between llvm.mlir.global definitions and corresponding globals.
DenseMap<Operation *, llvm::GlobalValue *> globalsMapping;
+ /// Mappings between llvm.mlir.alias definitions and corresponding global
+ /// aliases.
+ DenseMap<Operation *, llvm::GlobalValue *> aliasesMapping;
+
/// A stateful object used to translate types.
TypeToLLVMIRTranslator typeTranslator;
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index a6e996f3fb810db..1d1d4a1daf13bd0 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -2043,6 +2043,11 @@ LLVMFuncOp AddressOfOp::getFunction(SymbolTableCollection &symbolTable) {
symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
}
+AliasOp AddressOfOp::getAlias(SymbolTableCollection &symbolTable) {
+ return dyn_cast_or_null<AliasOp>(
+ symbolTable.lookupSymbolIn(parentLLVMModule(*this), getGlobalNameAttr()));
+}
+
LogicalResult
AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
Operation *symbol =
@@ -2050,15 +2055,17 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
auto global = dyn_cast_or_null<GlobalOp>(symbol);
auto function = dyn_cast_or_null<LLVMFuncOp>(symbol);
+ auto alias = dyn_cast_or_null<AliasOp>(symbol);
- if (!global && !function)
- return emitOpError(
- "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'");
+ if (!global && !function && !alias)
+ return emitOpError("must reference a global defined by 'llvm.mlir.global', "
+ "'llvm.mlir.alias' or 'llvm.func'");
LLVMPointerType type = getType();
- if (global && global.getAddrSpace() != type.getAddressSpace())
+ if ((global && global.getAddrSpace() != type.getAddressSpace()) ||
+ (alias && alias.getAddrSpace() != type.getAddressSpace()))
return emitOpError("pointer address space must match address space of the "
- "referenced global");
+ "referenced global or alias");
return success();
}
@@ -2195,38 +2202,50 @@ static LogicalResult verifyComdat(Operation *op,
return success();
}
-// operation ::= `llvm.mlir.global` linkage? visibility?
-// (`unnamed_addr` | `local_unnamed_addr`)?
-// `thread_local`? `constant`? `@` identifier
-// `(` attribute? `)` (`comdat(` symbol-ref-id `)`)?
-// attribute-list? (`:` type)? region?
-//
-// The type can be omitted for string attributes, in which case it will be
-// inferred from the value of the string as [strlen(value) x i8].
-ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
+/// Parse common attributes that might show up in the same order in both
+/// GlobalOp and AliasOp.
+template <typename OpType>
+static ParseResult parseCommonGlobalAndAlias(OpAsmParser &parser,
+ OperationState &result) {
MLIRContext *ctx = parser.getContext();
// Parse optional linkage, default to External.
- result.addAttribute(getLinkageAttrName(result.name),
+ result.addAttribute(OpType::getLinkageAttrName(result.name),
LLVM::LinkageAttr::get(
ctx, parseOptionalLLVMKeyword<Linkage>(
parser, result, LLVM::Linkage::External)));
// Parse optional visibility, default to Default.
- result.addAttribute(getVisibility_AttrName(result.name),
+ result.addAttribute(OpType::getVisibility_AttrName(result.name),
parser.getBuilder().getI64IntegerAttr(
parseOptionalLLVMKeyword<LLVM::Visibility, int64_t>(
parser, result, LLVM::Visibility::Default)));
// Parse optional UnnamedAddr, default to None.
- result.addAttribute(getUnnamedAddrAttrName(result.name),
+ result.addAttribute(OpType::getUnnamedAddrAttrName(result.name),
parser.getBuilder().getI64IntegerAttr(
parseOptionalLLVMKeyword<UnnamedAddr, int64_t>(
parser, result, LLVM::UnnamedAddr::None)));
if (succeeded(parser.parseOptionalKeyword("thread_local")))
- result.addAttribute(getThreadLocal_AttrName(result.name),
+ result.addAttribute(OpType::getThreadLocal_AttrName(result.name),
parser.getBuilder().getUnitAttr());
+ return success();
+}
+
+// operation ::= `llvm.mlir.global` linkage? visibility?
+// (`unnamed_addr` | `local_unnamed_addr`)?
+// `thread_local`? `constant`? `@` identifier
+// `(` attribute? `)` (`comdat(` symbol-ref-id `)`)?
+// attribute-list? (`:` type)? region?
+//
+// The type can be omitted for string attributes, in which case it will be
+// inferred from the value of the string as [strlen(value) x i8].
+ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
+ // Call into common parsing between GlobalOp and AliasOp.
+ if (parseCommonGlobalAndAlias<GlobalOp>(parser, result).failed())
+ return failure();
+
if (succeeded(parser.parseOptionalKeyword("constant")))
result.addAttribute(getConstantAttrName(result.name),
parser.getBuilder().getUnitAttr());
@@ -2429,6 +2448,145 @@ LogicalResult GlobalDtorsOp::verify() {
return success();
}
+//===----------------------------------------------------------------------===//
+// Builder, printer and verifier for LLVM::AliasOp.
+//===----------------------------------------------------------------------===//
+
+void AliasOp::build(OpBuilder &builder, OperationState &result, Type type,
+ Linkage linkage, StringRef name, bool dsoLocal,
+ bool threadLocal, ArrayRef<NamedAttribute> attrs) {
+ result.addAttribute(getSymNameAttrName(result.name),
+ builder.getStringAttr(name));
+ result.addAttribute(getAliasTypeAttrName(result.name), TypeAttr::get(type));
+ if (dsoLocal)
+ result.addAttribute(getDsoLocalAttrName(result.name),
+ builder.getUnitAttr());
+ if (threadLocal)
+ result.addAttribute(getThreadLocal_AttrName(result.name),
+ builder.getUnitAttr());
+
+ result.addAttribute(getLinkageAttrName(result.name),
+ LinkageAttr::get(builder.getContext(), linkage));
+ result.attributes.append(attrs.begin(), attrs.end());
+
+ result.addRegion();
+}
+
+void AliasOp::print(OpAsmPrinter &p) {
+ p << ' ' << stringifyLinkage(getLinkage()) << ' ';
+ StringRef visibility = stringifyVisibility(getVisibility_());
+ if (!visibility.empty())
+ p << visibility << ' ';
+
+ if (std::optional<mlir::LLVM::UnnamedAddr> unnamedAddr = getUnnamedAddr()) {
+ StringRef str = stringifyUnnamedAddr(*unnamedAddr);
+ if (!str.empty())
+ p << str << ' ';
+ }
+
+ if (getThreadLocal_())
+ p << "thread_local ";
+
+ p.printSymbolName(getSymName());
+ p.printOptionalAttrDict((*this)->getAttrs(),
+ {SymbolTable::getSymbolAttrName(),
+ getAliasTypeAttrName(), getLinkageAttrName(),
+ getUnnamedAddrAttrName(), getThreadLocal_AttrName(),
+ getVisibility_AttrName(), getUnnamedAddrAttrName()});
+
+ // Print the trailing type.
+ p << " : " << getType() << ' ';
+ // Print the initializer region.
+ p.printRegion(getInitializerRegion(), /*printEntryBlockArgs=*/false);
+}
+
+// operation ::= `llvm.mlir.alias` linkage? visibility?
+// (`unnamed_addr` | `local_unnamed_addr`)?
+// `thread_local`? `@` identifier
+// `(` attribute? `)`
+// attribute-list? `:` type region
+//
+ParseResult AliasOp::parse(OpAsmParser &parser, OperationState &result) {
+ // Call into common parsing between GlobalOp and AliasOp.
+ if (parseCommonGlobalAndAlias<AliasOp>(parser, result).failed())
+ return failure();
+
+ StringAttr name;
+ if (parser.parseSymbolName(name, getSymNameAttrName(result.name),
+ result.attributes))
+ return failure();
+
+ SmallVector<Type, 1> types;
+ if (parser.parseOptionalAttrDict(result.attributes) ||
+ parser.parseOptionalColonTypeList(types))
+ return failure();
+
+ if (types.size() > 1)
+ return parser.emitError(parser.getNameLoc(), "expected zero or one type");
+
+ Region &initRegion = *result.addRegion();
+ if (parser.parseRegion(initRegion).failed())
+ return failure();
+
+ result.addAttribute(getAliasTypeAttrName(result.name),
+ TypeAttr::get(types[0]));
+ return success();
+}
+
+LogicalResult AliasOp::verify() {
+ bool validType = isCompatibleOuterType(getType())
+ ? !llvm::isa<LLVMVoidType, LLVMTokenType,
+ LLVMMetadataType, LLVMLabelType>(getType())
+ : llvm::isa<PointerElementTypeInterface>(getType());
+ if (!validType)
+ return emitOpError(
+ "expects type to be a valid element type for an LLVM global alias");
+
+ // This matches LLVM IR verification logic, see llvm/lib/IR/Verifier.cpp
+ switch (getLinkage()) {
+ case Linkage::External:
+ case Linkage::Internal:
+ case Linkage::Private:
+ case Linkage::Weak:
+ case Linkage::Linkonce:
+ case Linkage::LinkonceODR:
+ case Linkage::AvailableExternally:
+ break;
+ default:
+ return emitOpError()
+ << "'" << stringifyLinkage(getLinkage())
+ << "' linkage not supported in aliases, available options: private, "
+ "internal, linkonce, weak, linkonce_odr, weak_odr, external or "
+ "available_externally";
+ }
+
+ return success();
+}
+
+LogicalResult AliasOp::verifyRegions() {
+ Block &b = getInitializerBlock();
+ auto ret = cast<ReturnOp>(b.getTerminator());
+ if (ret.getNumOperands() == 0 ||
+ !isa<LLVM::LLVMPointerType>(ret.getOperand(0).getType()))
+ return emitOpError("initializer region must always return a pointer");
+
+ for (Operation &op : b) {
+ auto iface = dyn_cast<MemoryEffectOpInterface>(op);
+ if (!iface || !iface.hasNoEffect())
+ return op.emitError()
+ << "ops with side effects are not allowed in alias initializers";
+ }
+
+ return success();
+}
+
+unsigned AliasOp::getAddrSpace() {
+ Block &initializer = getInitializerBlock();
+ auto ret = cast<ReturnOp>(initializer.getTerminator());
+ auto ptrTy = cast<LLVMPointerType>(ret.getOperand(0).getType());
+ return ptrTy.getAddressSpace();
+}
+
//===----------------------------------------------------------------------===//
// ShuffleVectorOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 2084e527773ca82..3afea87ca92c12f 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -447,15 +447,21 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
addressOfOp.getGlobal(moduleTranslation.symbolTable());
LLVM::LLVMFuncOp function =
addressOfOp.getFunction(moduleTranslation.symbolTable());
+ LLVM::AliasOp alias = addressOfOp.getAlias(moduleTranslation.symbolTable());
// The verifier should not have allowed this.
- assert((global || function) &&
- "referencing an undefined global or function");
-
- moduleTranslation.mapValue(
- addressOfOp.getResult(),
- global ? moduleTranslation.lookupGlobal(global)
- : moduleTranslation.lookupFunction(function.getName()));
+ assert((global || function || alias) &&
+ "referencing an undefined global, function, or alias");
+
+ llvm::Value *llvmValue = nullptr;
+ if (global)
+ llvmValue = moduleTranslation.lookupGlobal(global);
+ else if (alias)
+ llvmValue = moduleTranslation.lookupAlias(alias);
+ else
+ llvmValue = moduleTranslation.lookupFunction(function.getName());
+
+ moduleTranslation.mapValue(addressOfOp.getResult(), llvmValue);
return success();
}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 5ebde22cccbdf3e..5c61ecaeeefed7b 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -647,6 +647,16 @@ LogicalResult ModuleImport::convertGlobals() {
return success();
}
+LogicalResult ModuleImport::convertAliases() {
+ for (llvm::GlobalAlias &alias : llvmModule->aliases()) {
+ if (failed(convertAlias(&alias))) {
+ return emitError(UnknownLoc::get(context))
+ << "unhandled global alias: " << diag(alias);
+ }
+ }
+ return success();
+}
+
LogicalResult ModuleImport::convertDataLayout() {
Location loc = mlirModule.getLoc();
DataLayoutImporter dataLayoutImporter(context, llvmModule->getDataLayout());
@@ -952,6 +962,38 @@ ModuleImport::getOrCreateNamelessSymbolName(llvm::GlobalVariable *globalVar) {
return symbolRef;
}
+LogicalResult ModuleImport::convertAlias(llvm::GlobalAlias *alias) {
+ // Insert the global after the last one or at the start of the module.
+ OpBuilder::InsertionGuard guard(builder);
+ if (!aliasInsertionOp)
+ builder.setInsertionPointToStart(mlirModule.getBody());
+ else
+ builder.setInsertionPointAfter(aliasInsertionOp);
+
+ Type type = convertType(alias->getValueType());
+ AliasOp aliasOp = builder.create<AliasOp>(
+ mlirModule.getLoc(), type, convertLinkageFromLLVM(alias->getLinkage()),
+ alias->getName(),
+ /*dso_local=*/alias->isDSOLocal(),
+ /*thread_local=*/alias->isThreadLocal(),
+ /*attrs=*/ArrayRef<NamedAttribute>());
+ aliasInsertionOp = aliasOp;
+
+ clearRegionState();
+ Block *block = builder.createBlock(&aliasOp.getInitializerRegion());
+ setConstantInsertionPointToStart(block);
+ FailureOr<Value> initializer = convertConstantExpr(alias->getAliasee());
+ if (failed(initializer))
+ return failure();
+ builder.create<ReturnOp>(aliasOp.getLoc(), *initializer);
+
+ if (alias->hasAtLeastLocalUnnamedAddr())
+ aliasOp.setUnnamedAddr(convertUnnamedAddrFromLLVM(alias->getUnnamedAddr()));
+ aliasOp.setVisibility_(convertVisibilityFromLLVM(alias->getVisibility()));
+
+ return success();
+}
+
LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
// Insert the global after the last one or at the start of the module.
OpBuilder::InsertionGuard guard(builder);
@@ -1089,7 +1131,7 @@ ModuleImport::getConstantsToConvert(llvm::Constant *constant) {
llvm::Constant *current = workList.back();
// References of global objects are just pointers to the object. Avoid
// walking the elements of these here.
- if (isa<llvm::GlobalObject>(current)) {
+ if (isa<llvm::GlobalObject>(current) || isa<llvm::GlobalAlias>(current)) {
orderedSet.insert(current);
workList.pop_back();
continue;
@@ -1185,6 +1227,14 @@ FailureOr<Value> ModuleImport::convertConstant(llvm::Constant *constant) {
return builder.create<AddressOfOp>(loc, type, symbolRef).getResult();
}
+ // Convert global alias accesses.
+ if (auto *globalAliasObj = dyn_cast<llvm::GlobalAlias>(constant)) {
+ Type type = convertType(globalAliasObj->getType());
+ StringRef aliaseeName = globalAliasObj->getName();
+ FlatSymbolRefAttr symbolRef = FlatSymbolRefAttr::get(context, aliaseeName);
+ return builder.create<AddressOfOp>(loc, type, symbolRef).getResult();
+ }
+
// Convert constant expressions.
if (auto *constExpr = dyn_cast<llvm::ConstantExpr>(constant)) {
// Convert the constant expression to a temporary LLVM instruction and
@@ -2456,6 +2506,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
return {};
if (failed(moduleImport.convertFunctions()))
return {};
+ if (failed(moduleImport.convertAliases()))
+ return {};
moduleImport.convertTargetTriple();
return module;
}
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 4367100e3aca682..ed61cb255be8fa7 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -746,6 +746,8 @@ void ModuleTranslation::forgetMapping(Region ®ion) {
branchMapping.erase(&op);
if (isa<LLVM::GlobalOp>(op))
globalsMapping.erase(&op);
+ if (isa<LLVM::AliasOp>(op))
+ aliasesMapping.erase(&op);
if (isa<LLVM::CallOp>(op))
callMapping.erase(&op);
llvm::append_range(
@@ -1026,12 +1028,15 @@ static void addRuntimePreemptionSpecifier(bool dsoLocalRequested,
gv->setDSOLocal(true);
}
-/// Create named global variables that correspond to llvm.mlir.global
-/// definitions. Convert llvm.global_ctors and global_dtors ops.
-LogicalResult ModuleTranslation::convertGlobals() {
+LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
// Mapping from compile unit to its respective set of global variables.
DenseMap<llvm::DICompileUnit *, SmallVector<llvm::Metadata *>> allGVars;
+ // First, create all global variables and global aliases in LLVM IR. A global
+ // or alias body may refer to another global/alias or itself, so all the
+ // mapping needs to happen prior to body conversion.
+
+ // Create all llvm::GlobalVariable
for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
llvm::Type *type = convertType(op.getType());
llvm::Constant *cst = nullptr;
@@ -1135,9 +1140,35 @@ LogicalResult ModuleTranslation::convertGlobals() {
}
}
- // Convert global variable bodies. This is done after all global variables
- // have been created in LLVM IR because a global body may refer to another
- // global or itself. So all global variables need to be mapped first.
+ // Create all llvm::GlobalAlias
+ for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
+ llvm::Type *type = convertType(op.getType());
+ llvm::Constant *cst = nullptr;
+ llvm::GlobalValue::LinkageTypes linkage =
+ convertLinkageToLLVM(op.getLinkage());
+ llvm::Module &llvmMod = *llvmModule;
+
+ // Note address space and aliasee info isn't set just yet.
+ llvm::GlobalAlias *var = llvm::GlobalAlias::create(
+ type, op.getAddrSpace(), linkage, op.getSymName(), /*placeholder*/ cst,
+ &llvmMod);
+
+ var->setThreadLocalMode(op.getThreadLocal_()
+ ? llvm::GlobalAlias::GeneralDynamicTLSModel
+ : llvm::GlobalAlias::NotThreadLocal);
+
+ // Note there is no need to setup the comdat because GlobalAlias calls into
+ // the aliasee comdat information automatically.
+
+ if (op.getUnnamedAddr().has_value())
+ var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
+
+ var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
+
+ aliasesMapping.try_emplace(op, var);
+ }
+
+ // Convert global variable bodies.
for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
if (Block *initializer = op.getInitializerBlock()) {
llvm::IRBuilder<> builder(llvmModule->getContext());
@@ -1248,6 +1279,29 @@ LogicalResult ModuleTranslation::convertGlobals() {
llvm::MDTuple::get(getLLVMContext(), globals));
}
+ // Convert global alias bodies.
+ for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
+ Block &initializer = op.getInitializerBlock();
+ llvm::IRBuilder<> builder(llvmModule->getContext());
+
+ for (mlir::Operation &op : initializer.without_terminator()) {
+ if (failed(convertOperation(op, builder)))
+ return emitError(op.getLoc(), "fail to convert alias initializer");
+ if (!isa<llvm::Constant>(lookupValue(op.getResult(0))))
+ return emitError(op.getLoc(), "unemittable constant value");
+ }
+
+ auto ret = cast<ReturnOp>(initializer.getTerminator());
+ auto *cst = cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
+ assert(aliasesMapping.count(op));
+ auto *alias = cast<llvm::GlobalAlias>(aliasesMapping[op]);
+ alias->setAliasee(cst);
+ }
+
+ for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>())
+ if (failed(convertDialectAttributes(op, {})))
+ return failure();
+
return success();
}
@@ -2055,7 +2109,7 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
return nullptr;
if (failed(translator.convertFunctionSignatures()))
return nullptr;
- if (failed(translator.convertGlobals()))
+ if (failed(translator.convertGlobalsAndAliases()))
return nullptr;
if (failed(translator.createTBAAMetadata()))
return nullptr;
@@ -2066,8 +2120,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
// Convert other top-level operations if possible.
for (Operation &o : getModuleBody(module).getOperations()) {
- if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp, LLVM::GlobalCtorsOp,
- LLVM::GlobalDtorsOp, LLVM::ComdatOp>(&o) &&
+ if (!isa<LLVM::LLVMFuncOp, LLVM::AliasOp, LLVM::GlobalOp,
+ LLVM::GlobalCtorsOp, LLVM::GlobalDtorsOp, LLVM::ComdatOp>(&o) &&
!o.hasTrait<OpTrait::IsTerminator>() &&
failed(translator.convertOperation(o, llvmBuilder))) {
return nullptr;
diff --git a/mlir/test/Dialect/LLVMIR/alias.mlir b/mlir/test/Dialect/LLVMIR/alias.mlir
new file mode 100644
index 000000000000000..807843a27e6fa87
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/alias.mlir
@@ -0,0 +1,141 @@
+// RUN: mlir-opt %s -split-input-file --verify-roundtrip | FileCheck %s
+
+llvm.func internal @callee() -> !llvm.ptr attributes {dso_local} {
+ %0 = llvm.mlir.zero : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @foo_alias : !llvm.ptr {
+ %0 = llvm.mlir.addressof @callee : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @_ZTV1D : !llvm.struct<(array<3 x ptr>)> {
+ %0 = llvm.mlir.addressof @callee : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: llvm.mlir.alias external @foo_alias : !llvm.ptr {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @callee : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+// CHECK: llvm.mlir.alias external @_ZTV1D : !llvm.struct<(array<3 x ptr>)> {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @callee : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+
+// -----
+
+llvm.mlir.global external @zed(42 : i32) : i32
+
+llvm.mlir.alias external @foo : i32 {
+ %0 = llvm.mlir.addressof @zed : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @foo2 : i16 {
+ %0 = llvm.mlir.addressof @zed : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: llvm.mlir.alias external @foo : i32 {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+// CHECK: llvm.mlir.alias external @foo2 : i16 {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+
+// -----
+
+llvm.mlir.global private constant @glob.private(dense<0> : tensor<32xi32>) : !llvm.array<32 x i32>
+
+llvm.mlir.alias linkonce_odr hidden @glob {dso_local} : !llvm.array<32 x i32> {
+ %0 = llvm.mlir.constant(1234 : i64) : i64
+ %1 = llvm.mlir.addressof @glob.private : !llvm.ptr
+ %2 = llvm.ptrtoint %1 : !llvm.ptr to i64
+ %3 = llvm.add %2, %0 : i64
+ %4 = llvm.inttoptr %3 : i64 to !llvm.ptr
+ llvm.return %4 : !llvm.ptr
+}
+
+// CHECK: llvm.mlir.global private constant @glob.private(dense<0> : tensor<32xi32>)
+// CHECK: llvm.mlir.alias linkonce_odr hidden @glob {dso_local} : !llvm.array<32 x i32> {
+// CHECK: %[[CST:.*]] = llvm.mlir.constant(1234 : i64) : i64
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @glob.private : !llvm.ptr
+// CHECK: %[[INTADDR:.*]] = llvm.ptrtoint %[[ADDR]] : !llvm.ptr to i64
+// CHECK: %[[BACKTOPTR:.*]] = llvm.add %[[INTADDR]], %[[CST]] : i64
+// CHECK: %[[RET_ADDR:.*]] = llvm.inttoptr %[[BACKTOPTR]] : i64 to !llvm.ptr
+// CHECK: llvm.return %[[RET_ADDR]] : !llvm.ptr
+// CHECK: }
+
+// -----
+
+llvm.mlir.global external @v1(0 : i32) : i32
+llvm.mlir.alias external @a3 : i32 {
+ %0 = llvm.mlir.addressof @v1 : !llvm.ptr
+ %1 = llvm.addrspacecast %0 : !llvm.ptr to !llvm.ptr<2>
+ llvm.return %1 : !llvm.ptr<2>
+}
+
+// CHECK: llvm.mlir.alias external @a3 : i32 {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @v1 : !llvm.ptr
+// CHECK: %1 = llvm.addrspacecast %[[ADDR]] : !llvm.ptr to !llvm.ptr<2>
+// CHECK: llvm.return %1 : !llvm.ptr<2>
+// CHECK: }
+
+// -----
+
+llvm.mlir.global private @g1(0 : i32) {dso_local} : i32
+
+llvm.mlir.alias private @a1 {dso_local} : i32 {
+ %0 = llvm.mlir.addressof @g1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.global internal constant @g2() : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias private @a2 {dso_local} : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.global internal constant @g3() : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a2 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: llvm.mlir.alias private @a1 {dso_local} : i32 {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @g1 : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+// CHECK: llvm.mlir.global internal constant @g2()
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @a1 : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+// CHECK: llvm.mlir.alias private @a2 {dso_local} : !llvm.ptr {
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @a1 : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+// CHECK: llvm.mlir.global internal constant @g3()
+// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @a2 : !llvm.ptr
+// CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+// CHECK: }
+
+// -----
+
+llvm.mlir.global private @g30(0 : i32) {dso_local} : i32
+
+llvm.mlir.alias private unnamed_addr thread_local @a30 {dso_local} : i32 {
+ %0 = llvm.mlir.addressof @g30 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: llvm.mlir.alias private unnamed_addr thread_local @a30 {dso_local} : i32 {
+// CHECK: %0 = llvm.mlir.addressof @g30 : !llvm.ptr
+// CHECK: llvm.return %0 : !llvm.ptr
+// CHECK: }
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 5c939318fe3ed67..08bc5a2d65a8aab 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1703,3 +1703,53 @@ llvm.func @wrong_number_of_bundle_tags() {
} : (i32, i32) -> ()
llvm.return
}
+
+// -----
+
+llvm.mlir.global external @x(42 : i32) : i32
+
+// expected-error at +1 {{expects type to be a valid element type for an LLVM global alias}}
+llvm.mlir.alias external @y : !llvm.label {
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// -----
+
+llvm.mlir.global external @x(42 : i32) : i32
+
+// expected-error at +1 {{linkage not supported in aliases, available options}}
+llvm.mlir.alias appending @y2 : i32 {
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// -----
+
+// expected-error at +1 {{initializer region must always return a pointer}}
+llvm.mlir.alias external @y3 : i32 {
+ %c = llvm.mlir.constant(42 : i64) : i64
+ llvm.return %c : i64
+}
+
+// -----
+
+llvm.mlir.global external @x(42 : i32) : i32
+
+llvm.mlir.alias external @y4 : i32 {
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ // expected-error at +1 {{ops with side effects are not allowed in alias initializers}}
+ %2 = llvm.load %0 : !llvm.ptr -> i32
+ llvm.return %0 : !llvm.ptr
+}
+
+// -----
+
+llvm.mlir.global external @x(42 : i32) : i32
+
+llvm.mlir.alias external @y5 : i32 {
+ // expected-error at +1 {{pointer address space must match address space}}
+ %0 = llvm.mlir.addressof @x : !llvm.ptr<4>
+ llvm.return %0 : !llvm.ptr<4>
+}
+
diff --git a/mlir/test/Target/LLVMIR/Import/alias.ll b/mlir/test/Target/LLVMIR/Import/alias.ll
new file mode 100644
index 000000000000000..9f86da3ecc71c98
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/alias.ll
@@ -0,0 +1,88 @@
+; RUN: mlir-translate --import-llvm %s -split-input-file | FileCheck %s
+
+ at foo_alias = alias ptr, ptr @callee
+
+; CHECK: llvm.mlir.alias external @foo_alias : !llvm.ptr {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @callee : !llvm.ptr
+; CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK: }
+
+define internal ptr @callee() {
+entry:
+ ret ptr null
+}
+
+; -----
+
+ at zed = global i32 42
+ at foo = alias i32, ptr @zed
+ at foo2 = alias i16, ptr @zed
+
+; CHECK: llvm.mlir.alias external @foo : i32 {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr
+; CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK: }
+; CHECK: llvm.mlir.alias external @foo2 : i16 {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr
+; CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK: }
+
+; -----
+
+ at v1 = global i32 0
+ at a3 = alias i32, addrspacecast (ptr @v1 to ptr addrspace(2))
+; CHECK: llvm.mlir.alias external @a3 : i32 {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @v1 : !llvm.ptr
+; CHECK: %[[CASTED_ADDR:.*]] = llvm.addrspacecast %[[ADDR]] : !llvm.ptr to !llvm.ptr<2>
+; CHECK: llvm.return %[[CASTED_ADDR]] : !llvm.ptr<2>
+; CHECK: }
+
+; -----
+
+ at some_name = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr null] }
+ at vtable = alias { [3 x ptr] }, ptr @some_name
+
+; CHECK: llvm.mlir.alias external @vtable : !llvm.struct<(array<3 x ptr>)> {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @some_name : !llvm.ptr
+; CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK: }
+
+; -----
+
+ at glob.private = private constant [32 x i32] zeroinitializer
+ at glob = linkonce_odr hidden alias [32 x i32], inttoptr (i64 add (i64 ptrtoint (ptr @glob.private to i64), i64 1234) to ptr)
+
+; CHECK: llvm.mlir.alias linkonce_odr hidden @glob {dso_local} : !llvm.array<32 x i32> {
+; CHECK: %[[CST:.*]] = llvm.mlir.constant(1234 : i64) : i64
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @glob.private : !llvm.ptr
+; CHECK: %[[PTRTOINT:.*]] = llvm.ptrtoint %[[ADDR]] : !llvm.ptr to i64
+; CHECK: %[[INTTOPTR:.*]] = llvm.add %[[PTRTOINT]], %[[CST]] : i64
+; CHECK: %[[RET:.*]] = llvm.inttoptr %[[INTTOPTR]] : i64 to !llvm.ptr
+; CHECK: llvm.return %[[RET]] : !llvm.ptr
+
+; -----
+
+ at g1 = private global i32 0
+ at g2 = internal constant ptr @a1
+ at g3 = internal constant ptr @a2
+ at a1 = private alias i32, ptr @g1
+ at a2 = private alias ptr, ptr @a1
+
+; CHECK: llvm.mlir.alias private @a1 {dso_local} : i32 {
+; CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @g1 : !llvm.ptr
+; CHECK: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK: }
+; CHECK: llvm.mlir.alias private @a2 {dso_local} : !llvm.ptr {
+; CHECK-NEXT: %[[ADDR:.*]] = llvm.mlir.addressof @a1 : !llvm.ptr
+; CHECK-NEXT: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK-NEXT: }
+
+; CHECK: llvm.mlir.global internal constant @g2() {addr_space = 0 : i32, dso_local} : !llvm.ptr {
+; CHECK-NEXT: %[[ADDR:.*]] = llvm.mlir.addressof @a1 : !llvm.ptr
+; CHECK-NEXT: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK-NEXT: }
+
+; CHECK: llvm.mlir.global internal constant @g3() {addr_space = 0 : i32, dso_local} : !llvm.ptr {
+; CHECK-NEXT: %[[ADDR:.*]] = llvm.mlir.addressof @a2 : !llvm.ptr
+; CHECK-NEXT: llvm.return %[[ADDR]] : !llvm.ptr
+; CHECK-NEXT: }
diff --git a/mlir/test/Target/LLVMIR/alias.mlir b/mlir/test/Target/LLVMIR/alias.mlir
new file mode 100644
index 000000000000000..56832a4900746bc
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/alias.mlir
@@ -0,0 +1,92 @@
+// RUN: mlir-translate -mlir-to-llvmir %s -split-input-file | FileCheck %s
+
+llvm.func internal @callee() -> !llvm.ptr attributes {dso_local} {
+ %0 = llvm.mlir.zero : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @foo_alias : !llvm.ptr {
+ %0 = llvm.mlir.addressof @callee : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @_ZTV1D : !llvm.struct<(array<3 x ptr>)> {
+ %0 = llvm.mlir.addressof @callee : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: @foo_alias = alias ptr, ptr @callee
+// CHECK: @_ZTV1D = alias { [3 x ptr] }, ptr @callee
+
+// -----
+
+llvm.mlir.global external @zed(42 : i32) : i32
+
+llvm.mlir.alias external @foo : i32 {
+ %0 = llvm.mlir.addressof @zed : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias external @foo2 : i16 {
+ %0 = llvm.mlir.addressof @zed : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: @foo = alias i32, ptr @zed
+// CHECK: @foo2 = alias i16, ptr @zed
+
+// -----
+
+llvm.mlir.global private constant @glob.private(dense<0> : tensor<32xi32>) {dso_local} : !llvm.array<32 x i32>
+
+llvm.mlir.alias linkonce_odr hidden @glob {dso_local} : !llvm.array<32 x i32> {
+ %0 = llvm.mlir.constant(1234 : i64) : i64
+ %1 = llvm.mlir.addressof @glob.private : !llvm.ptr
+ %2 = llvm.ptrtoint %1 : !llvm.ptr to i64
+ %3 = llvm.add %2, %0 : i64
+ %4 = llvm.inttoptr %3 : i64 to !llvm.ptr
+ llvm.return %4 : !llvm.ptr
+}
+
+// CHECK: @glob = linkonce_odr hidden alias [32 x i32], inttoptr (i64 add (i64 ptrtoint (ptr @glob.private to i64), i64 1234) to ptr)
+
+// -----
+
+llvm.mlir.global external @v1(0 : i32) : i32
+llvm.mlir.alias external @a3 : i32 {
+ %0 = llvm.mlir.addressof @v1 : !llvm.ptr
+ %1 = llvm.addrspacecast %0 : !llvm.ptr to !llvm.ptr<2>
+ llvm.return %1 : !llvm.ptr<2>
+}
+
+// CHECK: @a3 = alias i32, addrspacecast (ptr @v1 to ptr addrspace(2))
+
+// -----
+
+llvm.mlir.global private @g1(0 : i32) {dso_local} : i32
+
+llvm.mlir.alias private @a1 {dso_local} : i32 {
+ %0 = llvm.mlir.addressof @g1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.global internal constant @g2() {dso_local} : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.alias private @a2 {dso_local} : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a1 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+llvm.mlir.global internal constant @g3() {dso_local} : !llvm.ptr {
+ %0 = llvm.mlir.addressof @a2 : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// CHECK: @g1 = private global i32 0
+// CHECK: @g2 = internal constant ptr @a1
+// CHECK: @g3 = internal constant ptr @a2
+// CHECK: @a1 = private alias i32, ptr @g1
+// CHECK: @a2 = private alias ptr, ptr @a1
More information about the Mlir-commits
mailing list