Introduce Linkage attribute to the LLVM dialect
authorAlex Zinenko <zinenko@google.com>
Mon, 2 Dec 2019 11:27:38 +0000 (03:27 -0800)
committerA. Unique TensorFlower <gardener@tensorflow.org>
Mon, 2 Dec 2019 11:28:10 +0000 (03:28 -0800)
LLVM IR supports linkage on global objects such as global variables and
functions. Introduce the Linkage attribute into the LLVM dialect, backed by an
integer storage. Use this attribute on LLVM::GlobalOp and make it mandatory.
Implement parsing/printing of the attribute and conversion to LLVM IR.

See tensorflow/mlir#277.

PiperOrigin-RevId: 283309328

14 files changed:
mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp
mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp
mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/lib/Conversion/GPUToCUDA/ConvertLaunchFuncToCudaCalls.cpp
mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/test/Conversion/GPUToCUDA/lower-launch-func-to-cuda.mlir
mlir/test/Dialect/GPU/outlining.mlir
mlir/test/Dialect/LLVMIR/global.mlir
mlir/test/Target/import.ll
mlir/test/Target/llvmir.mlir

index ba79c34..d35cc5c 100644 (file)
@@ -141,8 +141,9 @@ private:
       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.
index ba79c34..d35cc5c 100644 (file)
@@ -141,8 +141,9 @@ private:
       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.
index eb39537..83c30e6 100644 (file)
@@ -195,7 +195,8 @@ private:
 /// 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
index 3d697b7..324937a 100644 (file)
@@ -467,8 +467,36 @@ def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable", []> {
   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)> {
@@ -501,6 +529,7 @@ def LLVM_GlobalOp
                         [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.";
@@ -522,8 +551,8 @@ def LLVM_GlobalOp
 
   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 = [{
index 9d8c894..f342083 100644 (file)
@@ -320,7 +320,7 @@ Value *GpuLaunchFuncToCudaCallsPass::generateKernelNameConstant(
   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
@@ -368,7 +368,8 @@ void GpuLaunchFuncToCudaCallsPass::translateGpuLaunchCalls(
   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.
index f56508d..54dd18e 100644 (file)
@@ -387,8 +387,8 @@ private:
         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);
   }
index 66a9bc0..a8c676f 100644 (file)
@@ -863,8 +863,8 @@ static ParseResult parseConstantOp(OpAsmParser &parser,
 //===----------------------------------------------------------------------===//
 
 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));
@@ -872,12 +872,56 @@ void GlobalOp::build(Builder *builder, OperationState &result, LLVMType 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());
@@ -885,8 +929,9 @@ static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
   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>())
@@ -899,12 +944,45 @@ static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) {
     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());
 
@@ -1489,6 +1567,7 @@ LLVMType LLVMType::getVoidTy(LLVMDialect *dialect) {
 
 Value *mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
                                       StringRef name, StringRef value,
+                                      LLVM::Linkage linkage,
                                       LLVM::LLVMDialect *llvmDialect) {
   assert(builder.getInsertionBlock() &&
          builder.getInsertionBlock()->getParentOp() &&
@@ -1502,7 +1581,8 @@ Value *mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder,
   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);
index fd4e413..6cf975b 100644 (file)
@@ -215,6 +215,37 @@ Attribute Importer::getConstantAsAttr(llvm::Constant *value) {
   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())
@@ -224,9 +255,10 @@ GlobalOp Importer::processGlobal(llvm::GlobalVariable *GV) {
   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);
index 7f3ce5a..f985fed 100644 (file)
@@ -279,6 +279,35 @@ LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments) {
   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() {
@@ -308,11 +337,15 @@ 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);
   }
index 2088606..d4c5c0f 100644 (file)
@@ -2,8 +2,8 @@
 
 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*">)
index 62c87df..6b69920 100644 (file)
@@ -111,7 +111,7 @@ func @extra_constants(%arg0 : memref<?xf32>) {
 
 // -----
 
-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
@@ -143,7 +143,7 @@ func @recursive_device_function() {
 // 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()
index ee3adfb..11f9b23 100644 (file)
@@ -1,29 +1,51 @@
 // 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*">
@@ -48,43 +70,43 @@ func @references() {
 // -----
 
 // 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 ':'}}
@@ -109,7 +131,7 @@ func @foo() {
 
 // -----
 
-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}}
@@ -120,14 +142,14 @@ func @bar() {
 
 // 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
 }
@@ -135,7 +157,7 @@ llvm.mlir.global @g() : !llvm.i32 {
 // -----
 
 // 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
 }
index cdc75b5..a8e0b44 100644 (file)
@@ -3,18 +3,18 @@
 %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)
 
@@ -152,4 +179,4 @@ define void @f6(void (i16) *%fn) {
 ; CHECK: llvm.call %arg0(%[[c]])
   call void %fn(i16 0)
   ret void
-}
\ No newline at end of file
+}
index a54b9f9..0ad0073 100644 (file)
@@ -1,31 +1,31 @@
 // 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*">
@@ -33,6 +33,34 @@ llvm.mlir.global constant @int_gep() : !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.
 //