builder.setInsertionPointToStart(module.getBody());
auto type = LLVM::LLVMType::getArrayTy(
LLVM::LLVMType::getInt8Ty(llvmDialect), value.size());
- global = builder.create<LLVM::GlobalOp>(
- loc, type, /*isConstant=*/true, name, builder.getStringAttr(value));
+ global = builder.create<LLVM::GlobalOp>(loc, type, /*isConstant=*/true,
+ LLVM::Linkage::Internal, name,
+ builder.getStringAttr(value));
}
// Get the pointer to the first character in the global string.
builder.setInsertionPointToStart(module.getBody());
auto type = LLVM::LLVMType::getArrayTy(
LLVM::LLVMType::getInt8Ty(llvmDialect), value.size());
- global = builder.create<LLVM::GlobalOp>(
- loc, type, /*isConstant=*/true, name, builder.getStringAttr(value));
+ global = builder.create<LLVM::GlobalOp>(loc, type, /*isConstant=*/true,
+ LLVM::Linkage::Internal, name,
+ builder.getStringAttr(value));
}
// Get the pointer to the first character in the global string.
/// global and use it to compute the address of the first character in the
/// string (operations inserted at the builder insertion point).
Value *createGlobalString(Location loc, OpBuilder &builder, StringRef name,
- StringRef value, LLVM::LLVMDialect *llvmDialect);
+ StringRef value, LLVM::Linkage linkage,
+ LLVM::LLVMDialect *llvmDialect);
} // end namespace LLVM
} // end namespace mlir
let printer = [{ p << getOperationName(); }];
}
+////////////////////////////////////////////////////////////////////////////////
// Auxiliary operations (do not appear in LLVM IR but necessary for the dialect
// to work correctly).
+////////////////////////////////////////////////////////////////////////////////
+
+// Linkage attribute is used on functions and globals. The order follows that of
+// https://llvm.org/docs/LangRef.html#linkage-types. The names are equivalent to
+// visible names in the IR rather than to enum values names in llvm::GlobalValue
+// since the latter is easier to change.
+def LinkagePrivate : I64EnumAttrCase<"Private", 0>;
+def LinkageInternal : I64EnumAttrCase<"Internal", 1>;
+def LinkageAvailableExternally : I64EnumAttrCase<"AvailableExternally", 2>;
+def LinkageLinkonce : I64EnumAttrCase<"Linkonce", 3>;
+def LinkageWeak : I64EnumAttrCase<"Weak", 4>;
+def LinkageCommon : I64EnumAttrCase<"Common", 5>;
+def LinkageAppending : I64EnumAttrCase<"Appending", 6>;
+def LinkageExternWeak : I64EnumAttrCase<"ExternWeak", 7>;
+def LinkageLinkonceODR : I64EnumAttrCase<"LinkonceODR", 8>;
+def LinkageWeakODR : I64EnumAttrCase<"WeakODR", 9>;
+def LinkageExternal : I64EnumAttrCase<"External", 10>;
+def Linkage : I64EnumAttr<
+ "Linkage",
+ "LLVM linkage types",
+ [LinkagePrivate, LinkageInternal, LinkageAvailableExternally,
+ LinkageLinkonce, LinkageWeak, LinkageCommon, LinkageAppending,
+ LinkageExternWeak, LinkageLinkonceODR, LinkageWeakODR, LinkageExternal]> {
+ let cppNamespace = "::mlir::LLVM";
+}
+
+
def LLVM_AddressOfOp
: LLVM_OneResultOp<"mlir.addressof">,
Arguments<(ins FlatSymbolRefAttr:$global_name)> {
[IsolatedFromAbove,
SingleBlockImplicitTerminator<"ReturnOp">, Symbol]>,
Arguments<(ins TypeAttr:$type, UnitAttr:$constant, StrAttr:$sym_name,
+ Linkage:$linkage,
OptionalAttr<AnyAttr>:$value,
DefaultValuedAttr<NonNegativeI32Attr, "0">:$addr_space)> {
let summary = "LLVM dialect global.";
let builders = [
OpBuilder<"Builder *builder, OperationState &result, LLVMType type, "
- "bool isConstant, StringRef name, Attribute value, "
- "ArrayRef<NamedAttribute> attrs = {}">
+ "bool isConstant, Linkage linkage, StringRef name, "
+ "Attribute value, ArrayRef<NamedAttribute> attrs = {}">
];
let extraClassDeclaration = [{
std::string globalName = llvm::formatv("{0}_kernel_name", name);
return LLVM::createGlobalString(
loc, builder, globalName, StringRef(kernelName.data(), kernelName.size()),
- llvmDialect);
+ LLVM::Linkage::Internal, llvmDialect);
}
// Emits LLVM IR to launch a kernel function. Expects the module that contains
SmallString<128> nameBuffer(*kernelModule.getName());
nameBuffer.append(kCubinStorageSuffix);
Value *data = LLVM::createGlobalString(
- loc, builder, nameBuffer.str(), cubinAttr.getValue(), getLLVMDialect());
+ loc, builder, nameBuffer.str(), cubinAttr.getValue(),
+ LLVM::Linkage::Internal, getLLVMDialect());
// Emit the load module call to load the module data. Error checking is done
// in the called helper function.
builder.getNamedAttr("addr_space", builder.getI32IntegerAttr(3));
auto globalOp = builder.create<LLVM::GlobalOp>(
loc, arrayType.cast<LLVM::LLVMType>(),
- /*isConstant=*/false, name, /*value=*/Attribute(),
- llvm::makeArrayRef(addrSpace));
+ /*isConstant=*/false, LLVM::Linkage::Internal, name,
+ /*value=*/Attribute(), llvm::makeArrayRef(addrSpace));
return rewriter.create<LLVM::AddressOfOp>(loc, globalOp);
}
//===----------------------------------------------------------------------===//
void GlobalOp::build(Builder *builder, OperationState &result, LLVMType type,
- bool isConstant, StringRef name, Attribute value,
- ArrayRef<NamedAttribute> attrs) {
+ bool isConstant, Linkage linkage, StringRef name,
+ Attribute value, ArrayRef<NamedAttribute> attrs) {
result.addAttribute(SymbolTable::getSymbolAttrName(),
builder->getStringAttr(name));
result.addAttribute("type", TypeAttr::get(type));
result.addAttribute("constant", builder->getUnitAttr());
if (value)
result.addAttribute("value", value);
+ result.addAttribute(
+ "linkage", builder->getI64IntegerAttr(static_cast<int64_t>(linkage)));
result.attributes.append(attrs.begin(), attrs.end());
result.addRegion();
}
+// Prints the keyword for the linkage type using the printer.
+static void printLinkage(OpAsmPrinter &p, LLVM::Linkage linkage) {
+ switch (linkage) {
+ case LLVM::Linkage::Private:
+ p << "private";
+ return;
+ case LLVM::Linkage::Internal:
+ p << "internal";
+ return;
+ case LLVM::Linkage::AvailableExternally:
+ p << "available_externally";
+ return;
+ case LLVM::Linkage::Linkonce:
+ p << "linkonce";
+ return;
+ case LLVM::Linkage::Weak:
+ p << "weak";
+ return;
+ case LLVM::Linkage::Common:
+ p << "common";
+ return;
+ case LLVM::Linkage::Appending:
+ p << "appending";
+ return;
+ case LLVM::Linkage::ExternWeak:
+ p << "extern_weak";
+ return;
+ case LLVM::Linkage::LinkonceODR:
+ p << "linkonce_odr";
+ return;
+ case LLVM::Linkage::WeakODR:
+ p << "weak_odr";
+ return;
+ case LLVM::Linkage::External:
+ p << "external";
+ return;
+ }
+ llvm_unreachable("unknown linkage type");
+}
+
static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
p << op.getOperationName() << ' ';
+ printLinkage(p, op.linkage());
+ p << ' ';
if (op.constant())
p << "constant ";
p.printSymbolName(op.sym_name());
if (auto value = op.getValueOrNull())
p.printAttribute(value);
p << ')';
- p.printOptionalAttrDict(op.getAttrs(), {SymbolTable::getSymbolAttrName(),
- "type", "constant", "value"});
+ p.printOptionalAttrDict(op.getAttrs(),
+ {SymbolTable::getSymbolAttrName(), "type", "constant",
+ "value", "linkage"});
// Print the trailing type unless it's a string global.
if (op.getValueOrNull().dyn_cast_or_null<StringAttr>())
p.printRegion(initializer, /*printEntryBlockArgs=*/false);
}
-// <operation> ::= `llvm.mlir.global` `constant`? `@` identifier
-// `(` attribute? `)` attribute-list? (`:` type)? region?
+// Parses one of the keywords provided in the list `keywords` and returns the
+// position of the parsed keyword in the list. If none of the keywords from the
+// list is parsed, returns -1.
+static int parseOptionalKeywordAlternative(OpAsmParser &parser,
+ ArrayRef<StringRef> keywords) {
+ for (auto en : llvm::enumerate(keywords)) {
+ if (succeeded(parser.parseOptionalKeyword(en.value())))
+ return en.index();
+ }
+ return -1;
+}
+
+// Parses one of the linkage keywords and, if succeeded, appends the "linkage"
+// integer attribute with the corresponding value to `result`.
+//
+// linkage ::= `private` | `internal` | `available_externally` | `linkonce`
+// | `weak` | `common` | `appending` | `extern_weak`
+// | `linkonce_odr` | `weak_odr` | `external
+static ParseResult parseOptionalLinkageKeyword(OpAsmParser &parser,
+ OperationState &result) {
+ int index = parseOptionalKeywordAlternative(
+ parser, {"private", "internal", "available_externally", "linkonce",
+ "weak", "common", "appending", "extern_weak", "linkonce_odr",
+ "weak_odr", "external"});
+ if (index == -1)
+ return failure();
+ result.addAttribute("linkage", parser.getBuilder().getI64IntegerAttr(index));
+ return success();
+}
+
+// operation ::= `llvm.mlir.global` linkage `constant`? `@` identifier
+// `(` attribute? `)` 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].
static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
+ if (failed(parseOptionalLinkageKeyword(parser, result)))
+ return parser.emitError(parser.getCurrentLocation(), "expected linkage");
+
if (succeeded(parser.parseOptionalKeyword("constant")))
result.addAttribute("constant", parser.getBuilder().getUnitAttr());
Value *mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
StringRef name, StringRef value,
+ LLVM::Linkage linkage,
LLVM::LLVMDialect *llvmDialect) {
assert(builder.getInsertionBlock() &&
builder.getInsertionBlock()->getParentOp() &&
auto type = LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(llvmDialect),
value.size());
auto global = moduleBuilder.create<LLVM::GlobalOp>(
- loc, type, /*isConstant=*/true, name, builder.getStringAttr(value));
+ loc, type, /*isConstant=*/true, linkage, name,
+ builder.getStringAttr(value));
// Get the pointer to the first character in the global string.
Value *globalPtr = builder.create<LLVM::AddressOfOp>(loc, global);
return Attribute();
}
+/// Converts LLVM global variable linkage type into the LLVM dialect predicate.
+static LLVM::Linkage
+processLinkage(llvm::GlobalVariable::LinkageTypes linkage) {
+ switch (linkage) {
+ case llvm::GlobalValue::PrivateLinkage:
+ return LLVM::Linkage::Private;
+ case llvm::GlobalValue::InternalLinkage:
+ return LLVM::Linkage::Internal;
+ case llvm::GlobalValue::AvailableExternallyLinkage:
+ return LLVM::Linkage::AvailableExternally;
+ case llvm::GlobalValue::LinkOnceAnyLinkage:
+ return LLVM::Linkage::Linkonce;
+ case llvm::GlobalValue::WeakAnyLinkage:
+ return LLVM::Linkage::Weak;
+ case llvm::GlobalValue::CommonLinkage:
+ return LLVM::Linkage::Common;
+ case llvm::GlobalValue::AppendingLinkage:
+ return LLVM::Linkage::Appending;
+ case llvm::GlobalValue::ExternalWeakLinkage:
+ return LLVM::Linkage::ExternWeak;
+ case llvm::GlobalValue::LinkOnceODRLinkage:
+ return LLVM::Linkage::LinkonceODR;
+ case llvm::GlobalValue::WeakODRLinkage:
+ return LLVM::Linkage::WeakODR;
+ case llvm::GlobalValue::ExternalLinkage:
+ return LLVM::Linkage::External;
+ }
+
+ llvm_unreachable("unhandled linkage type");
+}
+
GlobalOp Importer::processGlobal(llvm::GlobalVariable *GV) {
auto it = globals.find(GV);
if (it != globals.end())
Attribute valueAttr;
if (GV->hasInitializer())
valueAttr = getConstantAsAttr(GV->getInitializer());
- GlobalOp op = b.create<GlobalOp>(UnknownLoc::get(context),
- processType(GV->getValueType()),
- GV->isConstant(), GV->getName(), valueAttr);
+ GlobalOp op = b.create<GlobalOp>(
+ UnknownLoc::get(context), processType(GV->getValueType()),
+ GV->isConstant(), processLinkage(GV->getLinkage()), GV->getName(),
+ valueAttr);
if (GV->hasInitializer() && !valueAttr) {
Region &r = op.getInitializerRegion();
currentEntryBlock = b.createBlock(&r);
return success();
}
+// Convert the LLVM dialect linkage type to LLVM IR linkage type.
+llvm::GlobalVariable::LinkageTypes convertLinkageType(LLVM::Linkage linkage) {
+ switch (linkage) {
+ case LLVM::Linkage::Private:
+ return llvm::GlobalValue::PrivateLinkage;
+ case LLVM::Linkage::Internal:
+ return llvm::GlobalValue::InternalLinkage;
+ case LLVM::Linkage::AvailableExternally:
+ return llvm::GlobalValue::AvailableExternallyLinkage;
+ case LLVM::Linkage::Linkonce:
+ return llvm::GlobalValue::LinkOnceAnyLinkage;
+ case LLVM::Linkage::Weak:
+ return llvm::GlobalValue::WeakAnyLinkage;
+ case LLVM::Linkage::Common:
+ return llvm::GlobalValue::CommonLinkage;
+ case LLVM::Linkage::Appending:
+ return llvm::GlobalValue::AppendingLinkage;
+ case LLVM::Linkage::ExternWeak:
+ return llvm::GlobalValue::ExternalWeakLinkage;
+ case LLVM::Linkage::LinkonceODR:
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ case LLVM::Linkage::WeakODR:
+ return llvm::GlobalValue::WeakODRLinkage;
+ case LLVM::Linkage::External:
+ return llvm::GlobalValue::ExternalLinkage;
+ }
+ llvm_unreachable("unknown linkage type");
+}
+
// Create named global variables that correspond to llvm.mlir.global
// definitions.
void ModuleTranslation::convertGlobals() {
cst = cast<llvm::Constant>(valueMapping.lookup(ret.getOperand(0)));
}
+ auto linkage = convertLinkageType(op.linkage());
+ bool anyExternalLinkage =
+ (linkage == llvm::GlobalVariable::ExternalLinkage ||
+ linkage == llvm::GlobalVariable::ExternalWeakLinkage);
auto addrSpace = op.addr_space().getLimitedValue();
auto *var = new llvm::GlobalVariable(
- *llvmModule, type, op.constant(), llvm::GlobalValue::InternalLinkage,
- cst, op.sym_name(), /*InsertBefore=*/nullptr,
- llvm::GlobalValue::NotThreadLocal, addrSpace);
+ *llvmModule, type, op.constant(), linkage,
+ anyExternalLinkage ? nullptr : cst, op.sym_name(),
+ /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, addrSpace);
globalsMapping.try_emplace(op, var);
}
module attributes {gpu.container_module} {
- // CHECK: llvm.mlir.global constant @[[kernel_name:.*]]("kernel\00")
- // CHECK: llvm.mlir.global constant @[[global:.*]]("CUBIN")
+ // CHECK: llvm.mlir.global internal constant @[[kernel_name:.*]]("kernel\00")
+ // CHECK: llvm.mlir.global internal constant @[[global:.*]]("CUBIN")
module @kernel_module attributes {gpu.kernel_module, nvvm.cubin = "CUBIN"} {
func @kernel(!llvm.float, !llvm<"float*">)
// -----
-llvm.mlir.global @global(42 : i64) : !llvm.i64
+llvm.mlir.global internal @global(42 : i64) : !llvm.i64
func @function_call(%arg0 : memref<?xf32>) {
%cst = constant 8 : index
// CHECK: call @device_function() : () -> ()
// CHECK: llvm.mlir.addressof @global : !llvm<"i64*">
//
-// CHECK: llvm.mlir.global @global(42 : i64) : !llvm.i64
+// CHECK: llvm.mlir.global internal @global(42 : i64) : !llvm.i64
//
// CHECK: func @device_function()
// CHECK: func @recursive_device_function()
// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
-// CHECK: llvm.mlir.global @global(42 : i64) : !llvm.i64
-llvm.mlir.global @global(42 : i64) : !llvm.i64
+// CHECK: llvm.mlir.global internal @global(42 : i64) : !llvm.i64
+llvm.mlir.global internal @global(42 : i64) : !llvm.i64
-// CHECK: llvm.mlir.global constant @constant(3.700000e+01 : f64) : !llvm.float
-llvm.mlir.global constant @constant(37.0) : !llvm.float
+// CHECK: llvm.mlir.global internal constant @constant(3.700000e+01 : f64) : !llvm.float
+llvm.mlir.global internal constant @constant(37.0) : !llvm.float
-// CHECK: llvm.mlir.global constant @string("foobar")
-llvm.mlir.global constant @string("foobar") : !llvm<"[6 x i8]">
+// CHECK: llvm.mlir.global internal constant @string("foobar")
+llvm.mlir.global internal constant @string("foobar") : !llvm<"[6 x i8]">
-// CHECK: llvm.mlir.global @string_notype("1234567")
-llvm.mlir.global @string_notype("1234567")
+// CHECK: llvm.mlir.global internal @string_notype("1234567")
+llvm.mlir.global internal @string_notype("1234567")
-// CHECK: llvm.mlir.global @global_undef()
-llvm.mlir.global @global_undef() : !llvm.i64
+// CHECK: llvm.mlir.global internal @global_undef()
+llvm.mlir.global internal @global_undef() : !llvm.i64
-// CHECK: llvm.mlir.global @global_mega_initializer() : !llvm.i64 {
+// CHECK: llvm.mlir.global internal @global_mega_initializer() : !llvm.i64 {
// CHECK-NEXT: %[[c:[0-9]+]] = llvm.mlir.constant(42 : i64) : !llvm.i64
// CHECK-NEXT: llvm.return %[[c]] : !llvm.i64
// CHECK-NEXT: }
-llvm.mlir.global @global_mega_initializer() : !llvm.i64 {
+llvm.mlir.global internal @global_mega_initializer() : !llvm.i64 {
%c = llvm.mlir.constant(42 : i64) : !llvm.i64
llvm.return %c : !llvm.i64
}
+// Check different linkage types.
+// CHECK: llvm.mlir.global private
+llvm.mlir.global private @private() : !llvm.i64
+// CHECK: llvm.mlir.global internal
+llvm.mlir.global internal @internal() : !llvm.i64
+// CHECK: llvm.mlir.global available_externally
+llvm.mlir.global available_externally @available_externally() : !llvm.i64
+// CHECK: llvm.mlir.global linkonce
+llvm.mlir.global linkonce @linkonce() : !llvm.i64
+// CHECK: llvm.mlir.global weak
+llvm.mlir.global weak @weak() : !llvm.i64
+// CHECK: llvm.mlir.global common
+llvm.mlir.global common @common() : !llvm.i64
+// CHECK: llvm.mlir.global appending
+llvm.mlir.global appending @appending() : !llvm.i64
+// CHECK: llvm.mlir.global extern_weak
+llvm.mlir.global extern_weak @extern_weak() : !llvm.i64
+// CHECK: llvm.mlir.global linkonce_odr
+llvm.mlir.global linkonce_odr @linkonce_odr() : !llvm.i64
+// CHECK: llvm.mlir.global weak_odr
+llvm.mlir.global weak_odr @weak_odr() : !llvm.i64
+
// CHECK-LABEL: references
func @references() {
// CHECK: llvm.mlir.addressof @global : !llvm<"i64*">
// -----
// expected-error @+1 {{expects type to be a valid element type for an LLVM pointer}}
-llvm.mlir.global constant @constant(37.0) : !llvm<"label">
+llvm.mlir.global internal constant @constant(37.0) : !llvm<"label">
// -----
// expected-error @+1 {{'addr_space' failed to satisfy constraint: non-negative 32-bit integer}}
-"llvm.mlir.global"() {sym_name = "foo", type = !llvm.i64, value = 42 : i64, addr_space = -1 : i32} : () -> ()
+"llvm.mlir.global"() {sym_name = "foo", type = !llvm.i64, value = 42 : i64, addr_space = -1 : i32, linkage = 0} : () -> ()
// -----
// expected-error @+1 {{'addr_space' failed to satisfy constraint: non-negative 32-bit integer}}
-"llvm.mlir.global"() {sym_name = "foo", type = !llvm.i64, value = 42 : i64, addr_space = 1.0 : f32} : () -> ()
+"llvm.mlir.global"() {sym_name = "foo", type = !llvm.i64, value = 42 : i64, addr_space = 1.0 : f32, linkage = 0} : () -> ()
// -----
func @foo() {
// expected-error @+1 {{must appear at the module level}}
- llvm.mlir.global @bar(42) : !llvm.i32
+ llvm.mlir.global internal @bar(42) : !llvm.i32
}
// -----
// expected-error @+1 {{requires an i8 array type of the length equal to that of the string}}
-llvm.mlir.global constant @string("foobar") : !llvm<"[42 x i8]">
+llvm.mlir.global internal constant @string("foobar") : !llvm<"[42 x i8]">
// -----
// expected-error @+1 {{type can only be omitted for string globals}}
-llvm.mlir.global @i64_needs_type(0: i64)
+llvm.mlir.global internal @i64_needs_type(0: i64)
// -----
// expected-error @+1 {{expected zero or one type}}
-llvm.mlir.global @more_than_one_type(0) : !llvm.i64, !llvm.i32
+llvm.mlir.global internal @more_than_one_type(0) : !llvm.i64, !llvm.i32
// -----
-llvm.mlir.global @foo(0: i32) : !llvm.i32
+llvm.mlir.global internal @foo(0: i32) : !llvm.i32
func @bar() {
// expected-error @+2{{expected ':'}}
// -----
-llvm.mlir.global @foo(0: i32) : !llvm.i32
+llvm.mlir.global internal @foo(0: i32) : !llvm.i32
func @bar() {
// expected-error @+1 {{the type must be a pointer to the type of the referred global}}
// expected-error @+2 {{'llvm.mlir.global' op expects regions to end with 'llvm.return', found 'llvm.mlir.constant'}}
// expected-note @+1 {{in custom textual format, the absence of terminator implies 'llvm.return'}}
-llvm.mlir.global @g() : !llvm.i64 {
+llvm.mlir.global internal @g() : !llvm.i64 {
%c = llvm.mlir.constant(42 : i64) : !llvm.i64
}
// -----
// expected-error @+1 {{'llvm.mlir.global' op initializer region type '!llvm.i64' does not match global type '!llvm.i32'}}
-llvm.mlir.global @g() : !llvm.i32 {
+llvm.mlir.global internal @g() : !llvm.i32 {
%c = llvm.mlir.constant(42 : i64) : !llvm.i64
llvm.return %c : !llvm.i64
}
// -----
// expected-error @+1 {{'llvm.mlir.global' op cannot have both initializer value and region}}
-llvm.mlir.global @g(43 : i64) : !llvm.i64 {
+llvm.mlir.global internal @g(43 : i64) : !llvm.i64 {
%c = llvm.mlir.constant(42 : i64) : !llvm.i64
llvm.return %c : !llvm.i64
}
%struct.t = type {}
%struct.s = type { %struct.t, i64 }
-; CHECK: llvm.mlir.global @g1() : !llvm<"{ {}, i64 }">
+; CHECK: llvm.mlir.global external @g1() : !llvm<"{ {}, i64 }">
@g1 = external global %struct.s, align 8
-; CHECK: llvm.mlir.global @g2() : !llvm.double
+; CHECK: llvm.mlir.global external @g2() : !llvm.double
@g2 = external global double, align 8
-; CHECK: llvm.mlir.global @g3("string")
+; CHECK: llvm.mlir.global internal @g3("string")
@g3 = internal global [6 x i8] c"string"
-; CHECK: llvm.mlir.global @g5() : !llvm<"<8 x i32>">
+; CHECK: llvm.mlir.global external @g5() : !llvm<"<8 x i32>">
@g5 = external global <8 x i32>
@g4 = external global i32, align 8
-; CHECK: llvm.mlir.global constant @int_gep() : !llvm<"i32*"> {
+; CHECK: llvm.mlir.global internal constant @int_gep() : !llvm<"i32*"> {
; CHECK-DAG: %[[addr:[0-9]+]] = llvm.mlir.addressof @g4 : !llvm<"i32*">
; CHECK-DAG: %[[c2:[0-9]+]] = llvm.mlir.constant(2 : i32) : !llvm.i32
; CHECK-NEXT: %[[gepinit:[0-9]+]] = llvm.getelementptr %[[addr]][%[[c2]]] : (!llvm<"i32*">, !llvm.i32) -> !llvm<"i32*">
; CHECK-NEXT: }
@int_gep = internal constant i32* getelementptr (i32, i32* @g4, i32 2)
+;
+; Linkage attribute.
+;
+
+; CHECK: llvm.mlir.global private @private(42 : i32) : !llvm.i32
+@private = private global i32 42
+; CHECK: llvm.mlir.global internal @internal(42 : i32) : !llvm.i32
+@internal = internal global i32 42
+; CHECK: llvm.mlir.global available_externally @available_externally(42 : i32) : !llvm.i32
+@available_externally = available_externally global i32 42
+; CHECK: llvm.mlir.global linkonce @linkonce(42 : i32) : !llvm.i32
+@linkonce = linkonce global i32 42
+; CHECK: llvm.mlir.global weak @weak(42 : i32) : !llvm.i32
+@weak = weak global i32 42
+; CHECK: llvm.mlir.global common @common(42 : i32) : !llvm.i32
+@common = common global i32 42
+; CHECK: llvm.mlir.global appending @appending(42 : i32) : !llvm.i32
+@appending = appending global i32 42
+; CHECK: llvm.mlir.global extern_weak @extern_weak() : !llvm.i32
+@extern_weak = extern_weak global i32
+; CHECK: llvm.mlir.global linkonce_odr @linkonce_odr(42 : i32) : !llvm.i32
+@linkonce_odr = linkonce_odr global i32 42
+; CHECK: llvm.mlir.global weak_odr @weak_odr(42 : i32) : !llvm.i32
+@weak_odr = weak_odr global i32 42
+; CHECK: llvm.mlir.global external @external() : !llvm.i32
+@external = external global i32
+
; CHECK: llvm.func @fe(!llvm.i32) -> !llvm.float
declare float @fe(i32)
; CHECK: llvm.call %arg0(%[[c]])
call void %fn(i16 0)
ret void
-}
\ No newline at end of file
+}
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
// CHECK: @i32_global = internal global i32 42
-llvm.mlir.global @i32_global(42: i32) : !llvm.i32
+llvm.mlir.global internal @i32_global(42: i32) : !llvm.i32
// CHECK: @i32_const = internal constant i53 52
-llvm.mlir.global constant @i32_const(52: i53) : !llvm.i53
+llvm.mlir.global internal constant @i32_const(52: i53) : !llvm.i53
// CHECK: @int_global_array = internal global [3 x i32] [i32 62, i32 62, i32 62]
-llvm.mlir.global @int_global_array(dense<62> : vector<3xi32>) : !llvm<"[3 x i32]">
+llvm.mlir.global internal @int_global_array(dense<62> : vector<3xi32>) : !llvm<"[3 x i32]">
// CHECK: @i32_global_addr_space = internal addrspace(7) global i32 62
-llvm.mlir.global @i32_global_addr_space(62: i32) {addr_space = 7 : i32} : !llvm.i32
+llvm.mlir.global internal @i32_global_addr_space(62: i32) {addr_space = 7 : i32} : !llvm.i32
// CHECK: @float_global = internal global float 0.000000e+00
-llvm.mlir.global @float_global(0.0: f32) : !llvm.float
+llvm.mlir.global internal @float_global(0.0: f32) : !llvm.float
// CHECK: @float_global_array = internal global [1 x float] [float -5.000000e+00]
-llvm.mlir.global @float_global_array(dense<[-5.0]> : vector<1xf32>) : !llvm<"[1 x float]">
+llvm.mlir.global internal @float_global_array(dense<[-5.0]> : vector<1xf32>) : !llvm<"[1 x float]">
// CHECK: @string_const = internal constant [6 x i8] c"foobar"
-llvm.mlir.global constant @string_const("foobar") : !llvm<"[6 x i8]">
+llvm.mlir.global internal constant @string_const("foobar") : !llvm<"[6 x i8]">
// CHECK: @int_global_undef = internal global i64 undef
-llvm.mlir.global @int_global_undef() : !llvm.i64
+llvm.mlir.global internal @int_global_undef() : !llvm.i64
// CHECK: @int_gep = internal constant i32* getelementptr (i32, i32* @i32_global, i32 2)
-llvm.mlir.global constant @int_gep() : !llvm<"i32*"> {
+llvm.mlir.global internal constant @int_gep() : !llvm<"i32*"> {
%addr = llvm.mlir.addressof @i32_global : !llvm<"i32*">
%_c0 = llvm.mlir.constant(2: i32) :!llvm.i32
%gepinit = llvm.getelementptr %addr[%_c0] : (!llvm<"i32*">, !llvm.i32) -> !llvm<"i32*">
}
//
+// Linkage attribute.
+//
+
+// CHECK: @private = private global i32 42
+llvm.mlir.global private @private(42 : i32) : !llvm.i32
+// CHECK: @internal = internal global i32 42
+llvm.mlir.global internal @internal(42 : i32) : !llvm.i32
+// CHECK: @available_externally = available_externally global i32 42
+llvm.mlir.global available_externally @available_externally(42 : i32) : !llvm.i32
+// CHECK: @linkonce = linkonce global i32 42
+llvm.mlir.global linkonce @linkonce(42 : i32) : !llvm.i32
+// CHECK: @weak = weak global i32 42
+llvm.mlir.global weak @weak(42 : i32) : !llvm.i32
+// CHECK: @common = common global i32 42
+llvm.mlir.global common @common(42 : i32) : !llvm.i32
+// CHECK: @appending = appending global i32 42
+llvm.mlir.global appending @appending(42 : i32) : !llvm.i32
+// CHECK: @extern_weak = extern_weak global i32
+llvm.mlir.global extern_weak @extern_weak() : !llvm.i32
+// CHECK: @linkonce_odr = linkonce_odr global i32 42
+llvm.mlir.global linkonce_odr @linkonce_odr(42 : i32) : !llvm.i32
+// CHECK: @weak_odr = weak_odr global i32 42
+llvm.mlir.global weak_odr @weak_odr(42 : i32) : !llvm.i32
+// CHECK: @external = external global i32
+llvm.mlir.global external @external() : !llvm.i32
+
+
+//
// Declarations of the allocation functions to be linked against.
//