diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -364,6 +364,15 @@ return module->getRegion(0).front(); } +/// A helper method to decide if a constant must not be set as a global variable +/// initializer. +static bool dropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage, + llvm::Constant *cst) { + return (linkage == llvm::GlobalVariable::ExternalLinkage && + isa(cst)) || + linkage == llvm::GlobalVariable::ExternalWeakLinkage; +} + /// Create named global variables that correspond to llvm.mlir.global /// definitions. LogicalResult ModuleTranslation::convertGlobals() { @@ -381,31 +390,38 @@ *this))) { return failure(); } - } else if (Block *initializer = op.getInitializerBlock()) { - llvm::IRBuilder<> builder(llvmModule->getContext()); - for (auto &op : initializer->without_terminator()) { - if (failed(convertOperation(op, builder)) || - !isa(lookupValue(op.getResult(0)))) - return emitError(op.getLoc(), "unemittable constant value"); - } - ReturnOp ret = cast(initializer->getTerminator()); - cst = cast(lookupValue(ret.getOperand(0))); } auto linkage = convertLinkageToLLVM(op.linkage()); - bool anyExternalLinkage = - ((linkage == llvm::GlobalVariable::ExternalLinkage && - isa(cst)) || - linkage == llvm::GlobalVariable::ExternalWeakLinkage); auto addrSpace = op.addr_space(); auto *var = new llvm::GlobalVariable( *llvmModule, type, op.constant(), linkage, - anyExternalLinkage ? nullptr : cst, op.sym_name(), + dropGlobalInitializer(linkage, cst) ? nullptr : cst, op.sym_name(), /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, addrSpace); globalsMapping.try_emplace(op, var); } + // 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. + for (auto op : getModuleBody(mlirModule).getOps()) { + if (Block *initializer = op.getInitializerBlock()) { + llvm::IRBuilder<> builder(llvmModule->getContext()); + for (auto &op : initializer->without_terminator()) { + if (failed(convertOperation(op, builder)) || + !isa(lookupValue(op.getResult(0)))) + return emitError(op.getLoc(), "unemittable constant value"); + } + ReturnOp ret = cast(initializer->getTerminator()); + llvm::Constant *cst = + cast(lookupValue(ret.getOperand(0))); + auto *global = cast(lookupGlobal(op)); + if (!dropGlobalInitializer(global->getLinkage(), cst)) + global->setInitializer(cst); + } + } + return success(); } diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1265,6 +1265,29 @@ // ----- +// CHECK: @forward_use_of_address = linkonce global float* @address_declared_after_use +llvm.mlir.global linkonce @forward_use_of_address() : !llvm.ptr { + %0 = llvm.mlir.addressof @address_declared_after_use : !llvm.ptr + llvm.return %0 : !llvm.ptr +} + +llvm.mlir.global linkonce @address_declared_after_use() : f32 + +// ----- + +// CHECK: @take_self_address = linkonce global { i32, i32* } {{.*}} { i32, i32* }* @take_self_address +llvm.mlir.global linkonce @take_self_address() : !llvm.struct<(i32, !llvm.ptr)> { + %z32 = llvm.mlir.constant(0 : i32) : i32 + %0 = llvm.mlir.undef : !llvm.struct<(i32, !llvm.ptr)> + %1 = llvm.mlir.addressof @take_self_address : !llvm.ptr)>> + %2 = llvm.getelementptr %1[%z32, %z32] : (!llvm.ptr)>>, i32, i32) -> !llvm.ptr + %3 = llvm.insertvalue %z32, %0[0 : i32] : !llvm.struct<(i32, !llvm.ptr)> + %4 = llvm.insertvalue %2, %3[1 : i32] : !llvm.struct<(i32, !llvm.ptr)> + llvm.return %4 : !llvm.struct<(i32, !llvm.ptr)> +} + +// ----- + // Check that branch weight attributes are exported properly as metadata. llvm.func @cond_br_weights(%cond : i1, %arg0 : i32, %arg1 : i32) -> i32 { // CHECK: !prof ![[NODE:[0-9]+]]