[clang] [CIR] Upstream global variable linkage types (PR #129072)

Morris Hafner via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 5 07:54:03 PST 2025


https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/129072

>From f19e6f6c5da44bd47c71a1b3d047aa1a0df96568 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 5 Mar 2025 16:36:21 +0100
Subject: [PATCH 1/7] [CIR] Upstream global variable linkage types

This change implements variable linkage types in ClangIR except for common linkage which requires Comdat support.
---
 .../include/clang/CIR/Dialect/IR/CIRDialect.h |   2 +
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  83 ++++++-
 .../clang/CIR/Dialect/IR/CIROpsEnums.h        | 119 +++++++++++
 .../clang/CIR/Dialect/IR/CMakeLists.txt       |   4 +-
 .../clang/CIR/Interfaces/CIROpInterfaces.h    |  29 +++
 .../clang/CIR/Interfaces/CIROpInterfaces.td   |  63 ++++++
 .../clang/CIR/Interfaces/CMakeLists.txt       |   9 +
 clang/include/clang/CIR/MissingFeatures.h     |   4 +
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 202 +++++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  12 ++
 clang/lib/CIR/CodeGen/CMakeLists.txt          |   1 +
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |   8 +-
 clang/lib/CIR/Dialect/IR/CMakeLists.txt       |   3 +-
 clang/lib/CIR/FrontendAction/CMakeLists.txt   |   4 +
 clang/lib/CIR/Interfaces/CIROpInterfaces.cpp  |  22 ++
 clang/lib/CIR/Interfaces/CMakeLists.txt       |   4 +-
 .../CIR/Lowering/DirectToLLVM/CMakeLists.txt  |   5 +
 clang/test/CIR/global-var-simple.cpp          |  64 +++---
 clang/test/CIR/global_var_linkage.cpp         |  11 +
 19 files changed, 608 insertions(+), 41 deletions(-)
 create mode 100644 clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
 create mode 100644 clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
 create mode 100644 clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
 create mode 100644 clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
 create mode 100644 clang/test/CIR/global_var_linkage.cpp

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index 683176b139ca4..0684cf5034f5d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -28,6 +28,8 @@
 
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
+#include "clang/CIR/Interfaces/CIROpInterfaces.h"
 
 // TableGen'erated files for MLIR dialects require that a macro be defined when
 // they are included.  GET_OP_CLASSES tells the file to define the classes for
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 48178b0ff247d..2cef98099fdbb 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -18,6 +18,8 @@ include "clang/CIR/Dialect/IR/CIRDialect.td"
 include "clang/CIR/Dialect/IR/CIRTypes.td"
 include "clang/CIR/Dialect/IR/CIRAttrs.td"
 
+include "clang/CIR/Interfaces/CIROpInterfaces.td"
+
 include "mlir/IR/BuiltinAttributeInterfaces.td"
 include "mlir/IR/EnumAttr.td"
 include "mlir/IR/SymbolInterfaces.td"
@@ -430,6 +432,59 @@ def ScopeOp : CIR_Op<"scope", [
 // GlobalOp
 //===----------------------------------------------------------------------===//
 
+// Linkage types. This is currently a replay of llvm/IR/GlobalValue.h, this is
+// currently handy as part of forwarding appropriate linkage types for LLVM
+// lowering, specially useful for C++ support.
+
+// Externally visible function
+def Global_ExternalLinkage :
+  I32EnumAttrCase<"ExternalLinkage", 0, "external">;
+// Available for inspection, not emission.
+def Global_AvailableExternallyLinkage :
+  I32EnumAttrCase<"AvailableExternallyLinkage", 1, "available_externally">;
+// Keep one copy of function when linking (inline)
+def Global_LinkOnceAnyLinkage :
+  I32EnumAttrCase<"LinkOnceAnyLinkage", 2, "linkonce">;
+// Same, but only replaced by something equivalent.
+def Global_LinkOnceODRLinkage :
+  I32EnumAttrCase<"LinkOnceODRLinkage", 3, "linkonce_odr">;
+// Keep one copy of named function when linking (weak)
+def Global_WeakAnyLinkage :
+  I32EnumAttrCase<"WeakAnyLinkage", 4, "weak">;
+// Same, but only replaced by something equivalent.
+def Global_WeakODRLinkage :
+  I32EnumAttrCase<"WeakODRLinkage", 5, "weak_odr">;
+// TODO: should we add something like appending linkage too?
+// Special purpose, only applies to global arrays
+// def Global_AppendingLinkage :
+//   I32EnumAttrCase<"AppendingLinkage", 6, "appending">;
+// Rename collisions when linking (static functions).
+def Global_InternalLinkage :
+  I32EnumAttrCase<"InternalLinkage", 7, "internal">;
+// Like Internal, but omit from symbol table, prefix it with
+// "cir_" to prevent clash with MLIR's symbol "private".
+def Global_PrivateLinkage :
+  I32EnumAttrCase<"PrivateLinkage", 8, "cir_private">;
+// ExternalWeak linkage description.
+def Global_ExternalWeakLinkage :
+  I32EnumAttrCase<"ExternalWeakLinkage", 9, "extern_weak">;
+// Tentative definitions.
+def Global_CommonLinkage :
+  I32EnumAttrCase<"CommonLinkage", 10, "common">;
+
+/// An enumeration for the kinds of linkage for global values.
+def GlobalLinkageKind : I32EnumAttr<
+    "GlobalLinkageKind",
+    "Linkage type/kind",
+    [Global_ExternalLinkage, Global_AvailableExternallyLinkage,
+     Global_LinkOnceAnyLinkage, Global_LinkOnceODRLinkage,
+     Global_WeakAnyLinkage, Global_WeakODRLinkage,
+     Global_InternalLinkage, Global_PrivateLinkage,
+     Global_ExternalWeakLinkage, Global_CommonLinkage
+     ]> {
+  let cppNamespace = "::cir";
+}
+
 // TODO(CIR): For starters, cir.global has only name and type.  The other
 // properties of a global variable will be added over time as more of ClangIR
 // is upstreamed.
@@ -441,12 +496,19 @@ def GlobalOp : CIR_Op<"global"> {
 
     The backing memory for the variable is allocated statically and is
     described by the type of the variable.
+
+    The `linkage` tracks C/C++ linkage types, currently very similar to LLVM's.
   }];
 
-  let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type,
-                       OptionalAttr<AnyAttr>:$initial_value);
+  let arguments = (ins SymbolNameAttr:$sym_name,
+                       TypeAttr:$sym_type,
+                       Arg<GlobalLinkageKind, "linkage type">:$linkage,
+                       OptionalAttr<AnyAttr>:$initial_value,
+                       UnitAttr:$dsolocal);
 
   let assemblyFormat = [{
+    $linkage
+    (`dsolocal` $dsolocal^)?
     $sym_name
     custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
     attr-dict
@@ -455,12 +517,25 @@ def GlobalOp : CIR_Op<"global"> {
   let extraClassDeclaration = [{
     bool isDeclaration() { return !getInitialValue(); }
     bool hasInitializer() { return !isDeclaration(); }
+    bool hasAvailableExternallyLinkage() {
+      return cir::isAvailableExternallyLinkage(getLinkage());
+    }
+    bool hasInternalLinkage() {
+      return cir::isInternalLinkage(getLinkage());
+    }
+    /// Whether the definition of this global may be replaced at link time.
+    bool isWeakForLinker() { return cir::isWeakForLinker(getLinkage()); }
+    bool isDSOLocal() { return getDsolocal(); }
   }];
 
   let skipDefaultBuilders = 1;
 
-  let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name,
-                                 "mlir::Type":$sym_type)>];
+  let builders = [OpBuilder<(ins
+    "llvm::StringRef":$sym_name,
+    "mlir::Type":$sym_type,
+    // CIR defaults to external linkage.
+    CArg<"cir::GlobalLinkageKind",
+    "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
 
   let hasVerifier = 1;
 }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
new file mode 100644
index 0000000000000..a1e32209555f3
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
@@ -0,0 +1,119 @@
+//===- CIROpsEnumsDialect.h - MLIR Dialect for CIR ----------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Target dialect for CIR in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_CIR_CIROPSENUMS_H_
+#define MLIR_DIALECT_CIR_CIROPSENUMS_H_
+
+#include "mlir/IR/BuiltinAttributes.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h.inc"
+
+namespace cir {
+
+static bool isExternalLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::ExternalLinkage;
+}
+static bool isAvailableExternallyLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::AvailableExternallyLinkage;
+}
+static bool isLinkOnceAnyLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::LinkOnceAnyLinkage;
+}
+static bool isLinkOnceODRLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::LinkOnceODRLinkage;
+}
+static bool isLinkOnceLinkage(GlobalLinkageKind linkage) {
+  return isLinkOnceAnyLinkage(linkage) || isLinkOnceODRLinkage(linkage);
+}
+static bool isWeakAnyLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::WeakAnyLinkage;
+}
+static bool isWeakODRLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::WeakODRLinkage;
+}
+static bool isWeakLinkage(GlobalLinkageKind linkage) {
+  return isWeakAnyLinkage(linkage) || isWeakODRLinkage(linkage);
+}
+static bool isInternalLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::InternalLinkage;
+}
+static bool isPrivateLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::PrivateLinkage;
+}
+static bool isLocalLinkage(GlobalLinkageKind linkage) {
+  return isInternalLinkage(linkage) || isPrivateLinkage(linkage);
+}
+static bool isExternalWeakLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::ExternalWeakLinkage;
+}
+LLVM_ATTRIBUTE_UNUSED static bool isCommonLinkage(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::CommonLinkage;
+}
+LLVM_ATTRIBUTE_UNUSED static bool
+isValidDeclarationLinkage(GlobalLinkageKind linkage) {
+  return isExternalWeakLinkage(linkage) || isExternalLinkage(linkage);
+}
+
+/// Whether the definition of this global may be replaced by something
+/// non-equivalent at link time. For example, if a function has weak linkage
+/// then the code defining it may be replaced by different code.
+LLVM_ATTRIBUTE_UNUSED static bool
+isInterposableLinkage(GlobalLinkageKind linkage) {
+  switch (linkage) {
+  case GlobalLinkageKind::WeakAnyLinkage:
+  case GlobalLinkageKind::LinkOnceAnyLinkage:
+  case GlobalLinkageKind::CommonLinkage:
+  case GlobalLinkageKind::ExternalWeakLinkage:
+    return true;
+
+  case GlobalLinkageKind::AvailableExternallyLinkage:
+  case GlobalLinkageKind::LinkOnceODRLinkage:
+  case GlobalLinkageKind::WeakODRLinkage:
+    // The above three cannot be overridden but can be de-refined.
+
+  case GlobalLinkageKind::ExternalLinkage:
+  case GlobalLinkageKind::InternalLinkage:
+  case GlobalLinkageKind::PrivateLinkage:
+    return false;
+  }
+  llvm_unreachable("Fully covered switch above!");
+}
+
+/// Whether the definition of this global may be discarded if it is not used
+/// in its compilation unit.
+LLVM_ATTRIBUTE_UNUSED static bool
+isDiscardableIfUnused(GlobalLinkageKind linkage) {
+  return isLinkOnceLinkage(linkage) || isLocalLinkage(linkage) ||
+         isAvailableExternallyLinkage(linkage);
+}
+
+/// Whether the definition of this global may be replaced at link time.  NB:
+/// Using this method outside of the code generators is almost always a
+/// mistake: when working at the IR level use isInterposable instead as it
+/// knows about ODR semantics.
+LLVM_ATTRIBUTE_UNUSED static bool isWeakForLinker(GlobalLinkageKind linkage) {
+  return linkage == GlobalLinkageKind::WeakAnyLinkage ||
+         linkage == GlobalLinkageKind::WeakODRLinkage ||
+         linkage == GlobalLinkageKind::LinkOnceAnyLinkage ||
+         linkage == GlobalLinkageKind::LinkOnceODRLinkage ||
+         linkage == GlobalLinkageKind::CommonLinkage ||
+         linkage == GlobalLinkageKind::ExternalWeakLinkage;
+}
+
+LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind gl) {
+  return isExternalLinkage(gl) || isLocalLinkage(gl) || isWeakLinkage(gl) ||
+         isLinkOnceLinkage(gl);
+}
+
+} // namespace cir
+
+#endif // MLIR_DIALECT_CIR_CIROPSENUMS_H_
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 1fdbc24ba6b4a..39292fb541daa 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -16,4 +16,6 @@ add_dependencies(mlir-headers MLIRCIROpsIncGen)
 
 mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
 mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
-add_public_tablegen_target(MLIRCIRAttrsEnumsGen)
+mlir_tablegen(CIROpsEnums.h.inc -gen-enum-decls)
+mlir_tablegen(CIROpsEnums.cpp.inc -gen-enum-defs)
+add_public_tablegen_target(MLIRCIREnumsGen)
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
new file mode 100644
index 0000000000000..86064619af7db
--- /dev/null
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
@@ -0,0 +1,29 @@
+//===- CIROpInterfaces.h - CIR Op Interfaces --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_INTERFACES_CIR_OP_H_
+#define MLIR_INTERFACES_CIR_OP_H_
+
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/IR/Value.h"
+#include "mlir/Interfaces/CallInterfaces.h"
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Mangle.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
+
+namespace cir {} // namespace cir
+
+/// Include the generated interface declarations.
+#include "clang/CIR/Interfaces/CIROpInterfaces.h.inc"
+
+namespace cir {} // namespace cir
+
+#endif // MLIR_INTERFACES_CIR_OP_H_
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
new file mode 100644
index 0000000000000..b765a3e65f70b
--- /dev/null
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -0,0 +1,63 @@
+//===- CIROpInterfaces.td - CIR Op Interface Definitions --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CIR_OP_INTERFACES
+#define MLIR_CIR_OP_INTERFACES
+
+include "mlir/IR/OpBase.td"
+
+let cppNamespace = "::cir" in {
+  def CIRGlobalValueInterface
+      : OpInterface<"CIRGlobalValueInterface"> {
+
+    let methods = [
+      InterfaceMethod<"",
+      "bool", "hasAvailableExternallyLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{ return false; }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasLocalLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
+        return cir::isLocalLinkage($_op.getLinkage());
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasExternalWeakLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
+        return cir::isExternalWeakLinkage($_op.getLinkage());
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "isExternalLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
+        return cir::isExternalLinkage($_op.getLinkage());
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "isDeclarationForLinker", (ins), [{}],
+      /*defaultImplementation=*/[{
+        if ($_op.hasAvailableExternallyLinkage())
+          return true;
+        return $_op.isDeclaration();
+      }]
+      >,
+      InterfaceMethod<"",
+      "void", "setDSOLocal", (ins "bool":$val), [{}],
+      /*defaultImplementation=*/[{
+        $_op.setDsolocal(val);
+      }]
+      >,
+    ];
+    let extraClassDeclaration = [{
+    bool canBenefitFromLocalAlias();
+  }];
+  }
+
+} // namespace cir
+
+#endif // MLIR_CIR_OP_INTERFACES
diff --git a/clang/include/clang/CIR/Interfaces/CMakeLists.txt b/clang/include/clang/CIR/Interfaces/CMakeLists.txt
index 1c90b6b5a23cb..e9929f6964605 100644
--- a/clang/include/clang/CIR/Interfaces/CMakeLists.txt
+++ b/clang/include/clang/CIR/Interfaces/CMakeLists.txt
@@ -3,6 +3,14 @@
 # directory which is not the case for CIR (and also FIR, both have similar
 # workarounds).
 
+function(add_clang_mlir_op_interface interface)
+  set(LLVM_TARGET_DEFINITIONS ${interface}.td)
+  mlir_tablegen(${interface}.h.inc -gen-op-interface-decls)
+  mlir_tablegen(${interface}.cpp.inc -gen-op-interface-defs)
+  add_public_tablegen_target(MLIR${interface}IncGen)
+  add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
+endfunction()
+
 function(add_clang_mlir_type_interface interface)
   set(LLVM_TARGET_DEFINITIONS ${interface}.td)
   mlir_tablegen(${interface}.h.inc -gen-type-interface-decls)
@@ -11,4 +19,5 @@ function(add_clang_mlir_type_interface interface)
   add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
 endfunction()
 
+add_clang_mlir_op_interface(CIROpInterfaces)
 add_clang_mlir_type_interface(CIRFPTypeInterface)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 6fbaa27bc7073..83177a004e80b 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -37,6 +37,10 @@ struct MissingFeatures {
   static bool opGlobalAlignment() { return false; }
   static bool opGlobalLinkage() { return false; }
 
+  static bool supportIFuncAttr() { return false; }
+  static bool supportVisibility() { return false; }
+  static bool supportComdat() { return false; }
+
   // Load/store attributes
   static bool opLoadThreadLocal() { return false; }
   static bool opLoadEmitScalarRangeCheck() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index d8acc99e550ad..8eb08228075ef 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/GlobalDecl.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/MissingFeatures.h"
 
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Location.h"
@@ -31,7 +32,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
                            const clang::CodeGenOptions &cgo,
                            DiagnosticsEngine &diags)
     : builder(mlirContext, *this), astContext(astContext),
-      langOpts(astContext.getLangOpts()),
+      langOpts(astContext.getLangOpts()), codeGenOpts(cgo),
       theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))},
       diags(diags), target(astContext.getTargetInfo()), genTypes(*this) {
 
@@ -176,6 +177,18 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
       }
       varOp.setInitialValueAttr(initializer);
     }
+
+    // Set CIR's linkage type as appropriate.
+    cir::GlobalLinkageKind linkage =
+        getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);
+
+    // Set CIR linkage and DLL storage class.
+    varOp.setLinkage(linkage);
+
+    if (linkage == cir::GlobalLinkageKind::CommonLinkage) {
+      errorNYI(initExpr->getSourceRange(), "common linkage");
+    }
+
     theModule.push_back(varOp);
   } else {
     errorNYI(vd->getSourceRange().getBegin(),
@@ -210,6 +223,193 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
   llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
 }
 
+static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) {
+  assert(!cir::MissingFeatures::supportComdat());
+
+  if (d.hasAttr<SelectAnyAttr>())
+    return true;
+
+  GVALinkage linkage;
+  if (auto *vd = dyn_cast<VarDecl>(&d))
+    linkage = cgm.getASTContext().GetGVALinkageForVariable(vd);
+  else
+    linkage =
+        cgm.getASTContext().GetGVALinkageForFunction(cast<FunctionDecl>(&d));
+
+  switch (linkage) {
+  case clang::GVA_Internal:
+  case clang::GVA_AvailableExternally:
+  case clang::GVA_StrongExternal:
+    return false;
+  case clang::GVA_DiscardableODR:
+  case clang::GVA_StrongODR:
+    return true;
+  }
+  llvm_unreachable("No such linkage");
+}
+
+// TODO(CIR): this could be a common method between LLVM codegen.
+static bool isVarDeclStrongDefinition(const ASTContext &astContext,
+                                      CIRGenModule &cgm, const VarDecl *vd,
+                                      bool noCommon) {
+  // Don't give variables common linkage if -fno-common was specified unless it
+  // was overridden by a NoCommon attribute.
+  if ((noCommon || vd->hasAttr<NoCommonAttr>()) && !vd->hasAttr<CommonAttr>())
+    return true;
+
+  // C11 6.9.2/2:
+  //   A declaration of an identifier for an object that has file scope without
+  //   an initializer, and without a storage-class specifier or with the
+  //   storage-class specifier static, constitutes a tentative definition.
+  if (vd->getInit() || vd->hasExternalStorage())
+    return true;
+
+  // A variable cannot be both common and exist in a section.
+  if (vd->hasAttr<SectionAttr>())
+    return true;
+
+  // A variable cannot be both common and exist in a section.
+  // We don't try to determine which is the right section in the front-end.
+  // If no specialized section name is applicable, it will resort to default.
+  if (vd->hasAttr<PragmaClangBSSSectionAttr>() ||
+      vd->hasAttr<PragmaClangDataSectionAttr>() ||
+      vd->hasAttr<PragmaClangRelroSectionAttr>() ||
+      vd->hasAttr<PragmaClangRodataSectionAttr>())
+    return true;
+
+  // Thread local vars aren't considered common linkage.
+  if (vd->getTLSKind())
+    return true;
+
+  // Tentative definitions marked with WeakImportAttr are true definitions.
+  if (vd->hasAttr<WeakImportAttr>())
+    return true;
+
+  // A variable cannot be both common and exist in a comdat.
+  if (shouldBeInCOMDAT(cgm, *vd))
+    return true;
+
+  // Declarations with a required alignment do not have common linkage in MSVC
+  // mode.
+  if (astContext.getTargetInfo().getCXXABI().isMicrosoft()) {
+    if (vd->hasAttr<AlignedAttr>())
+      return true;
+    QualType varType = vd->getType();
+    if (astContext.isAlignmentRequired(varType))
+      return true;
+
+    if (const auto *rt = varType->getAs<RecordType>()) {
+      const RecordDecl *rd = rt->getDecl();
+      for (const FieldDecl *fd : rd->fields()) {
+        if (fd->isBitField())
+          continue;
+        if (fd->hasAttr<AlignedAttr>())
+          return true;
+        if (astContext.isAlignmentRequired(fd->getType()))
+          return true;
+      }
+    }
+  }
+
+  // Microsoft's link.exe doesn't support alignments greater than 32 bytes for
+  // common symbols, so symbols with greater alignment requirements cannot be
+  // common.
+  // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two
+  // alignments for common symbols via the aligncomm directive, so this
+  // restriction only applies to MSVC environments.
+  if (astContext.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&
+      astContext.getTypeAlignIfKnown(vd->getType()) >
+          astContext.toBits(CharUnits::fromQuantity(32)))
+    return true;
+
+  return false;
+}
+
+cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator(
+    const DeclaratorDecl *dd, GVALinkage linkage, bool isConstantVariable) {
+  if (linkage == GVA_Internal)
+    return cir::GlobalLinkageKind::InternalLinkage;
+
+  if (dd->hasAttr<WeakAttr>()) {
+    if (isConstantVariable)
+      return cir::GlobalLinkageKind::WeakODRLinkage;
+    return cir::GlobalLinkageKind::WeakAnyLinkage;
+  }
+
+  if (const auto *fd = dd->getAsFunction())
+    if (fd->isMultiVersion() && linkage == GVA_AvailableExternally)
+      return cir::GlobalLinkageKind::LinkOnceAnyLinkage;
+
+  // We are guaranteed to have a strong definition somewhere else,
+  // so we can use available_externally linkage.
+  if (linkage == GVA_AvailableExternally)
+    return cir::GlobalLinkageKind::AvailableExternallyLinkage;
+
+  // Note that Apple's kernel linker doesn't support symbol
+  // coalescing, so we need to avoid linkonce and weak linkages there.
+  // Normally, this means we just map to internal, but for explicit
+  // instantiations we'll map to external.
+
+  // In C++, the compiler has to emit a definition in every translation unit
+  // that references the function.  We should use linkonce_odr because
+  // a) if all references in this translation unit are optimized away, we
+  // don't need to codegen it.  b) if the function persists, it needs to be
+  // merged with other definitions. c) C++ has the ODR, so we know the
+  // definition is dependable.
+  if (linkage == GVA_DiscardableODR)
+    return !astContext.getLangOpts().AppleKext
+               ? cir::GlobalLinkageKind::LinkOnceODRLinkage
+               : cir::GlobalLinkageKind::InternalLinkage;
+
+  // An explicit instantiation of a template has weak linkage, since
+  // explicit instantiations can occur in multiple translation units
+  // and must all be equivalent. However, we are not allowed to
+  // throw away these explicit instantiations.
+  //
+  // CUDA/HIP: For -fno-gpu-rdc case, device code is limited to one TU,
+  // so say that CUDA templates are either external (for kernels) or internal.
+  // This lets llvm perform aggressive inter-procedural optimizations. For
+  // -fgpu-rdc case, device function calls across multiple TU's are allowed,
+  // therefore we need to follow the normal linkage paradigm.
+  if (linkage == GVA_StrongODR) {
+    if (getLangOpts().AppleKext)
+      return cir::GlobalLinkageKind::ExternalLinkage;
+    if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
+        !getLangOpts().GPURelocatableDeviceCode)
+      return dd->hasAttr<CUDAGlobalAttr>()
+                 ? cir::GlobalLinkageKind::ExternalLinkage
+                 : cir::GlobalLinkageKind::InternalLinkage;
+    return cir::GlobalLinkageKind::WeakODRLinkage;
+  }
+
+  // C++ doesn't have tentative definitions and thus cannot have common
+  // linkage.
+  if (!getLangOpts().CPlusPlus && isa<VarDecl>(dd) &&
+      !isVarDeclStrongDefinition(astContext, *this, cast<VarDecl>(dd),
+                                 getCodeGenOpts().NoCommon)) {
+    errorNYI(dd->getBeginLoc(), "common linkage", dd->getDeclKindName());
+    return cir::GlobalLinkageKind::CommonLinkage;
+  }
+
+  // selectany symbols are externally visible, so use weak instead of
+  // linkonce.  MSVC optimizes away references to const selectany globals, so
+  // all definitions should be the same and ODR linkage should be used.
+  // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
+  if (dd->hasAttr<SelectAnyAttr>())
+    return cir::GlobalLinkageKind::WeakODRLinkage;
+
+  // Otherwise, we have strong external linkage.
+  assert(linkage == GVA_StrongExternal);
+  return cir::GlobalLinkageKind::ExternalLinkage;
+}
+
+cir::GlobalLinkageKind
+CIRGenModule::getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant) {
+  assert(!isConstant && "constant variables NYI");
+  GVALinkage linkage = astContext.GetGVALinkageForVariable(vd);
+  return getCIRLinkageForDeclarator(vd, linkage, isConstant);
+}
+
 // Emit code for a single top level declaration.
 void CIRGenModule::emitTopLevelDecl(Decl *decl) {
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 71a37b8c9a2ea..5fb5ef505a8c1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -23,8 +23,10 @@
 #include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/MLIRContext.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/TargetParser/Triple.h"
 
@@ -62,6 +64,8 @@ class CIRGenModule : public CIRGenTypeCache {
 
   const clang::LangOptions &langOpts;
 
+  const clang::CodeGenOptions &codeGenOpts;
+
   /// A "module" matches a c/cpp source file: containing a list of functions.
   mlir::ModuleOp theModule;
 
@@ -75,6 +79,7 @@ class CIRGenModule : public CIRGenTypeCache {
   mlir::ModuleOp getModule() const { return theModule; }
   CIRGenBuilderTy &getBuilder() { return builder; }
   clang::ASTContext &getASTContext() const { return astContext; }
+  const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; }
   CIRGenTypes &getTypes() { return genTypes; }
   const clang::LangOptions &getLangOpts() const { return langOpts; }
   mlir::MLIRContext &getMLIRContext() { return *builder.getContext(); }
@@ -123,6 +128,13 @@ class CIRGenModule : public CIRGenTypeCache {
 
   const llvm::Triple &getTriple() const { return target.getTriple(); }
 
+  cir::GlobalLinkageKind getCIRLinkageForDeclarator(const DeclaratorDecl *dd,
+                                                    GVALinkage linkage,
+                                                    bool isConstantVariable);
+
+  cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *vd,
+                                                    bool isConstant);
+
   /// Helpers to emit "not yet implemented" error diagnostics
   DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
 
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index dbb6d9e7b3807..e6d3cbabd853b 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -18,6 +18,7 @@ add_clang_library(clangCIR
 
   DEPENDS
   MLIRCIR
+  MLIRCIROpInterfacesIncGen
   ${dialect_libs}
 
   LINK_LIBS
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index aa21edcb5e99d..5ad369b40cda1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -18,6 +18,7 @@
 #include "mlir/Support/LogicalResult.h"
 
 #include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc"
 
 using namespace mlir;
 using namespace cir;
@@ -297,11 +298,16 @@ mlir::LogicalResult cir::GlobalOp::verify() {
 }
 
 void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
-                          llvm::StringRef sym_name, mlir::Type sym_type) {
+                          llvm::StringRef sym_name, mlir::Type sym_type,
+                          cir::GlobalLinkageKind linkage) {
   odsState.addAttribute(getSymNameAttrName(odsState.name),
                         odsBuilder.getStringAttr(sym_name));
   odsState.addAttribute(getSymTypeAttrName(odsState.name),
                         mlir::TypeAttr::get(sym_type));
+
+  cir::GlobalLinkageKindAttr linkageAttr =
+      cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage);
+  odsState.addAttribute(getLinkageAttrName(odsState.name), linkageAttr);
 }
 
 static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op,
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index 925af0d61c984..e3a6fc6e80ecc 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -6,7 +6,8 @@ add_clang_library(MLIRCIR
 
   DEPENDS
   MLIRCIROpsIncGen
-  MLIRCIRAttrsEnumsGen
+  MLIRCIREnumsGen
+  MLIRCIROpInterfacesIncGen
 
   LINK_LIBS PUBLIC
   MLIRIR
diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt
index ac2b857239d07..6d5a8758468f6 100644
--- a/clang/lib/CIR/FrontendAction/CMakeLists.txt
+++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt
@@ -8,6 +8,10 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 add_clang_library(clangCIRFrontendAction
   CIRGenAction.cpp
 
+  DEPENDS
+  MLIRCIROpsIncGen
+  MLIRCIROpInterfacesIncGen
+
   LINK_LIBS
   clangAST
   clangFrontend
diff --git a/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp b/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
new file mode 100644
index 0000000000000..dfbbdc2fd2382
--- /dev/null
+++ b/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
@@ -0,0 +1,22 @@
+//====- CIROpInterfaces.cpp - Interface to AST Attributes ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "clang/CIR/Interfaces/CIROpInterfaces.h"
+
+using namespace cir;
+
+/// Include the generated type qualifiers interfaces.
+#include "clang/CIR/Interfaces/CIROpInterfaces.cpp.inc"
+
+#include "clang/CIR/MissingFeatures.h"
+
+bool CIRGlobalValueInterface::canBenefitFromLocalAlias() {
+  assert(!cir::MissingFeatures::supportIFuncAttr());
+  assert(!cir::MissingFeatures::supportVisibility());
+  assert(!cir::MissingFeatures::supportComdat());
+  return false;
+}
diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt
index b826bf612cc35..2fe5714520b74 100644
--- a/clang/lib/CIR/Interfaces/CMakeLists.txt
+++ b/clang/lib/CIR/Interfaces/CMakeLists.txt
@@ -1,12 +1,14 @@
 add_clang_library(MLIRCIRInterfaces
+  CIROpInterfaces.cpp
   CIRFPTypeInterface.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces
 
   DEPENDS
-  MLIRCIRAttrsEnumsGen
+  MLIRCIREnumsGen
   MLIRCIRFPTypeInterfaceIncGen
+  MLIRCIROpInterfacesIncGen
 
   LINK_LIBS
   ${dialect_libs}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
index 3f74c79249a27..c11ecb82183d0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
@@ -8,6 +8,11 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 add_clang_library(clangCIRLoweringDirectToLLVM
   LowerToLLVM.cpp
 
+  DEPENDS
+  MLIRCIREnumsGen
+  MLIRCIROpsIncGen
+  MLIRCIROpInterfacesIncGen
+
   LINK_LIBS
   MLIRIR
   ${dialect_libs}
diff --git a/clang/test/CIR/global-var-simple.cpp b/clang/test/CIR/global-var-simple.cpp
index f8e233cd5fe33..585f1ed38390f 100644
--- a/clang/test/CIR/global-var-simple.cpp
+++ b/clang/test/CIR/global-var-simple.cpp
@@ -2,100 +2,100 @@
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o -  | FileCheck %s
 
 char c;
-// CHECK: cir.global @c : !cir.int<s, 8>
+// CHECK: cir.global external @c : !cir.int<s, 8>
 
 signed char sc;
-// CHECK: cir.global @sc : !cir.int<s, 8>
+// CHECK: cir.global external @sc : !cir.int<s, 8>
 
 unsigned char uc;
-// CHECK: cir.global @uc : !cir.int<u, 8>
+// CHECK: cir.global external @uc : !cir.int<u, 8>
 
 short ss;
-// CHECK: cir.global @ss : !cir.int<s, 16>
+// CHECK: cir.global external @ss : !cir.int<s, 16>
 
 unsigned short us = 100;
-// CHECK: cir.global @us = #cir.int<100> : !cir.int<u, 16>
+// CHECK: cir.global external @us = #cir.int<100> : !cir.int<u, 16>
 
 int si = 42;
-// CHECK: cir.global @si = #cir.int<42> : !cir.int<s, 32>
+// CHECK: cir.global external @si = #cir.int<42> : !cir.int<s, 32>
 
 unsigned ui;
-// CHECK: cir.global @ui : !cir.int<u, 32>
+// CHECK: cir.global external @ui : !cir.int<u, 32>
 
 long sl;
-// CHECK: cir.global @sl : !cir.int<s, 64>
+// CHECK: cir.global external @sl : !cir.int<s, 64>
 
 unsigned long ul;
-// CHECK: cir.global @ul : !cir.int<u, 64>
+// CHECK: cir.global external @ul : !cir.int<u, 64>
 
 long long sll;
-// CHECK: cir.global @sll : !cir.int<s, 64>
+// CHECK: cir.global external @sll : !cir.int<s, 64>
 
 unsigned long long ull = 123456;
-// CHECK: cir.global @ull = #cir.int<123456> : !cir.int<u, 64>
+// CHECK: cir.global external @ull = #cir.int<123456> : !cir.int<u, 64>
 
 __int128 s128;
-// CHECK: cir.global @s128 : !cir.int<s, 128>
+// CHECK: cir.global external @s128 : !cir.int<s, 128>
 
 unsigned __int128 u128;
-// CHECK: cir.global @u128 : !cir.int<u, 128>
+// CHECK: cir.global external @u128 : !cir.int<u, 128>
 
 wchar_t wc;
-// CHECK: cir.global @wc : !cir.int<s, 32>
+// CHECK: cir.global external @wc : !cir.int<s, 32>
 
 char8_t c8;
-// CHECK: cir.global @c8 : !cir.int<u, 8>
+// CHECK: cir.global external @c8 : !cir.int<u, 8>
 
 char16_t c16;
-// CHECK: cir.global @c16 : !cir.int<u, 16>
+// CHECK: cir.global external @c16 : !cir.int<u, 16>
 
 char32_t c32;
-// CHECK: cir.global @c32 : !cir.int<u, 32>
+// CHECK: cir.global external @c32 : !cir.int<u, 32>
 
 _BitInt(20) sb20;
-// CHECK: cir.global @sb20 : !cir.int<s, 20>
+// CHECK: cir.global external @sb20 : !cir.int<s, 20>
 
 unsigned _BitInt(48) ub48;
-// CHECK: cir.global @ub48 : !cir.int<u, 48>
+// CHECK: cir.global external @ub48 : !cir.int<u, 48>
 
 bool boolfalse = false;
 // CHECK: cir.global @boolfalse = #false
 
 _Float16 f16;
-// CHECK: cir.global @f16 : !cir.f16
+// CHECK: cir.global external @f16 : !cir.f16
 
 __bf16 bf16;
-// CHECK: cir.global @bf16 : !cir.bf16
+// CHECK: cir.global external @bf16 : !cir.bf16
 
 float f;
-// CHECK: cir.global @f : !cir.float
+// CHECK: cir.global external @f : !cir.float
 
 double d = 1.25;
-// CHECK: cir.global @d = #cir.fp<1.250000e+00> : !cir.double
+// CHECK: cir.global external @d = #cir.fp<1.250000e+00> : !cir.double
 
 long double ld;
-// CHECK: cir.global @ld : !cir.long_double<!cir.f80>
+// CHECK: cir.global external @ld : !cir.long_double<!cir.f80>
 
 __float128 f128;
-// CHECK: cir.global @f128 : !cir.f128
+// CHECK: cir.global external @f128 : !cir.f128
 
 void *vp;
-// CHECK: cir.global @vp : !cir.ptr<!cir.void>
+// CHECK: cir.global external @vp : !cir.ptr<!cir.void>
 
 int *ip = 0;
-// CHECK: cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
+// CHECK: cir.global external @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
 
 double *dp;
-// CHECK: cir.global @dp : !cir.ptr<!cir.double>
+// CHECK: cir.global external @dp : !cir.ptr<!cir.double>
 
 char **cpp;
-// CHECK: cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
+// CHECK: cir.global external @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
 
 void (*fp)();
-// CHECK: cir.global @fp : !cir.ptr<!cir.func<()>>
+// CHECK: cir.global external @fp : !cir.ptr<!cir.func<()>>
 
 int (*fpii)(int) = 0;
-// CHECK: cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
+// CHECK: cir.global external @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
 
 void (*fpvar)(int, ...);
-// CHECK: cir.global @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>
+// CHECK: cir.global external @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>
diff --git a/clang/test/CIR/global_var_linkage.cpp b/clang/test/CIR/global_var_linkage.cpp
new file mode 100644
index 0000000000000..18f17a3c2eb61
--- /dev/null
+++ b/clang/test/CIR/global_var_linkage.cpp
@@ -0,0 +1,11 @@
+// Linkage types of global variables
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o -  | FileCheck %s
+
+int aaaa;
+// CHECK: cir.global external @aaaa
+static int bbbb;
+// CHECK: cir.global internal @bbbb
+inline int cccc;
+// CHECK: cir.global linkonce_odr @cccc
+[[gnu::selectany]] int dddd;
+// CHECK: cir.global weak_odr @dddd

>From a7f29ff3fdd2b8cf244e76d78f76d21b97d281d0 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 5 Mar 2025 16:38:24 +0100
Subject: [PATCH 2/7] Addressed some review feedback

- Various formatting changes
- Changed file header comments
- Changed include guards
- Added global linkage to LLVM lowering
---
 .../clang/CIR/Dialect/IR/CIROpsEnums.h        | 10 ++--
 .../clang/CIR/Interfaces/CIROpInterfaces.h    | 12 ++--
 .../clang/CIR/Interfaces/CIROpInterfaces.td   | 58 ++++++++-----------
 clang/include/clang/CIR/MissingFeatures.h     |  1 -
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |  3 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 34 +++++++++--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   |  3 +
 ...var_linkage.cpp => global-var-linkage.cpp} |  0
 clang/test/CIR/global-var-simple.cpp          |  2 +-
 9 files changed, 67 insertions(+), 56 deletions(-)
 rename clang/test/CIR/{global_var_linkage.cpp => global-var-linkage.cpp} (100%)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
index a1e32209555f3..2b7270c42d343 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
@@ -1,4 +1,4 @@
-//===- CIROpsEnumsDialect.h - MLIR Dialect for CIR ----------------------*- C++
+//===----------------------------------------------------------------------===//
 //-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -7,12 +7,12 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file declares the Target dialect for CIR in MLIR.
+// This file declares the CIR enumerations.
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_DIALECT_CIR_CIROPSENUMS_H_
-#define MLIR_DIALECT_CIR_CIROPSENUMS_H_
+#ifndef CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
+#define CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
 
 #include "mlir/IR/BuiltinAttributes.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h.inc"
@@ -116,4 +116,4 @@ LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind gl) {
 
 } // namespace cir
 
-#endif // MLIR_DIALECT_CIR_CIROPSENUMS_H_
+#endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
index 86064619af7db..4c171c309ae29 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
@@ -1,4 +1,4 @@
-//===- CIROpInterfaces.h - CIR Op Interfaces --------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_INTERFACES_CIR_OP_H_
-#define MLIR_INTERFACES_CIR_OP_H_
+#ifndef CLANG_CIR_INTERFACES_CIR_OP_H
+#define CLANG_CIR_INTERFACES_CIR_OP_H
 
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/Operation.h"
@@ -19,11 +19,7 @@
 #include "clang/AST/Mangle.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 
-namespace cir {} // namespace cir
-
 /// Include the generated interface declarations.
 #include "clang/CIR/Interfaces/CIROpInterfaces.h.inc"
 
-namespace cir {} // namespace cir
-
-#endif // MLIR_INTERFACES_CIR_OP_H_
+#endif // CLANG_CIR_INTERFACES_CIR_OP_H
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index b765a3e65f70b..235b5a05c5ba8 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -6,52 +6,40 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_CIR_OP_INTERFACES
-#define MLIR_CIR_OP_INTERFACES
+#ifndef CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
+#define CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
 
 include "mlir/IR/OpBase.td"
 
 let cppNamespace = "::cir" in {
-  def CIRGlobalValueInterface
-      : OpInterface<"CIRGlobalValueInterface"> {
+  def CIRGlobalValueInterface : OpInterface<"CIRGlobalValueInterface"> {
 
-    let methods = [
-      InterfaceMethod<"",
-      "bool", "hasAvailableExternallyLinkage", (ins), [{}],
-      /*defaultImplementation=*/[{ return false; }]
-      >,
-      InterfaceMethod<"",
-      "bool", "hasLocalLinkage", (ins), [{}],
-      /*defaultImplementation=*/[{
+    let methods =
+        [InterfaceMethod<"", "bool", "hasAvailableExternallyLinkage", (ins),
+                         [{}],
+                         /*defaultImplementation=*/[{ return false; }]>,
+         InterfaceMethod<"", "bool", "hasLocalLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
         return cir::isLocalLinkage($_op.getLinkage());
-      }]
-      >,
-      InterfaceMethod<"",
-      "bool", "hasExternalWeakLinkage", (ins), [{}],
-      /*defaultImplementation=*/[{
+      }]>,
+         InterfaceMethod<"", "bool", "hasExternalWeakLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
         return cir::isExternalWeakLinkage($_op.getLinkage());
-      }]
-      >,
-      InterfaceMethod<"",
-      "bool", "isExternalLinkage", (ins), [{}],
-      /*defaultImplementation=*/[{
+      }]>,
+         InterfaceMethod<"", "bool", "isExternalLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
         return cir::isExternalLinkage($_op.getLinkage());
-      }]
-      >,
-      InterfaceMethod<"",
-      "bool", "isDeclarationForLinker", (ins), [{}],
-      /*defaultImplementation=*/[{
+      }]>,
+         InterfaceMethod<"", "bool", "isDeclarationForLinker", (ins), [{}],
+                         /*defaultImplementation=*/[{
         if ($_op.hasAvailableExternallyLinkage())
           return true;
         return $_op.isDeclaration();
-      }]
-      >,
-      InterfaceMethod<"",
-      "void", "setDSOLocal", (ins "bool":$val), [{}],
-      /*defaultImplementation=*/[{
+      }]>,
+         InterfaceMethod<"", "void", "setDSOLocal", (ins "bool":$val), [{}],
+                         /*defaultImplementation=*/[{
         $_op.setDsolocal(val);
-      }]
-      >,
+      }]>,
     ];
     let extraClassDeclaration = [{
     bool canBenefitFromLocalAlias();
@@ -60,4 +48,4 @@ let cppNamespace = "::cir" in {
 
 } // namespace cir
 
-#endif // MLIR_CIR_OP_INTERFACES
+#endif // CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 83177a004e80b..6f845b7689e51 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -35,7 +35,6 @@ struct MissingFeatures {
   static bool opGlobalThreadLocal() { return false; }
   static bool opGlobalConstant() { return false; }
   static bool opGlobalAlignment() { return false; }
-  static bool opGlobalLinkage() { return false; }
 
   static bool supportIFuncAttr() { return false; }
   static bool supportVisibility() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 8eb08228075ef..0e3e15ca2cadc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -185,9 +185,8 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
     // Set CIR linkage and DLL storage class.
     varOp.setLinkage(linkage);
 
-    if (linkage == cir::GlobalLinkageKind::CommonLinkage) {
+    if (linkage == cir::GlobalLinkageKind::CommonLinkage)
       errorNYI(initExpr->getSourceRange(), "common linkage");
-    }
 
     theModule.push_back(varOp);
   } else {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index f614c5d1db0c0..3200527bd03af 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -109,6 +109,34 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,
   return value;
 }
 
+mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {
+  using CIR = cir::GlobalLinkageKind;
+  using LLVM = mlir::LLVM::Linkage;
+
+  switch (linkage) {
+  case CIR::AvailableExternallyLinkage:
+    return LLVM::AvailableExternally;
+  case CIR::CommonLinkage:
+    return LLVM::Common;
+  case CIR::ExternalLinkage:
+    return LLVM::External;
+  case CIR::ExternalWeakLinkage:
+    return LLVM::ExternWeak;
+  case CIR::InternalLinkage:
+    return LLVM::Internal;
+  case CIR::LinkOnceAnyLinkage:
+    return LLVM::Linkonce;
+  case CIR::LinkOnceODRLinkage:
+    return LLVM::LinkonceODR;
+  case CIR::PrivateLinkage:
+    return LLVM::Private;
+  case CIR::WeakAnyLinkage:
+    return LLVM::Weak;
+  case CIR::WeakODRLinkage:
+    return LLVM::WeakODR;
+  };
+}
+
 class CIRAttrToValue {
 public:
   CIRAttrToValue(mlir::Operation *parentOp,
@@ -442,8 +470,7 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
   const bool isThreadLocal = false;
   assert(!cir::MissingFeatures::opGlobalAlignment());
   const uint64_t alignment = 0;
-  assert(!cir::MissingFeatures::opGlobalLinkage());
-  const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
+  const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
   const StringRef symbol = op.getSymName();
 
   SmallVector<mlir::NamedAttribute> attributes;
@@ -498,8 +525,7 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
   const bool isThreadLocal = false;
   assert(!cir::MissingFeatures::opGlobalAlignment());
   const uint64_t alignment = 0;
-  assert(!cir::MissingFeatures::opGlobalLinkage());
-  const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
+  const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
   const StringRef symbol = op.getSymName();
   SmallVector<mlir::NamedAttribute> attributes;
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index ccb4065c3019e..a694047e3616b 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -12,6 +12,7 @@
 #ifndef CLANG_CIR_LOWERTOLLVM_H
 #define CLANG_CIR_LOWERTOLLVM_H
 
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Transforms/DialectConversion.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 
@@ -19,6 +20,8 @@ namespace cir {
 
 namespace direct {
 
+mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
+
 class CIRToLLVMReturnOpLowering
     : public mlir::OpConversionPattern<cir::ReturnOp> {
 public:
diff --git a/clang/test/CIR/global_var_linkage.cpp b/clang/test/CIR/global-var-linkage.cpp
similarity index 100%
rename from clang/test/CIR/global_var_linkage.cpp
rename to clang/test/CIR/global-var-linkage.cpp
diff --git a/clang/test/CIR/global-var-simple.cpp b/clang/test/CIR/global-var-simple.cpp
index 585f1ed38390f..f18f00fd6bd13 100644
--- a/clang/test/CIR/global-var-simple.cpp
+++ b/clang/test/CIR/global-var-simple.cpp
@@ -59,7 +59,7 @@ unsigned _BitInt(48) ub48;
 // CHECK: cir.global external @ub48 : !cir.int<u, 48>
 
 bool boolfalse = false;
-// CHECK: cir.global @boolfalse = #false
+// CHECK: cir.global external @boolfalse = #false
 
 _Float16 f16;
 // CHECK: cir.global external @f16 : !cir.f16

>From c6bb2e4ad6e830df3454e49b21ca1a2196b1f50f Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Mon, 3 Mar 2025 18:39:52 +0100
Subject: [PATCH 3/7] Address more review comments

- Add header comments to CIROpInterfaces
- Fix test clang-cir-ir-global
---
 .../clang/CIR/Interfaces/CIROpInterfaces.h    |   4 +
 .../clang/CIR/Interfaces/CIROpInterfaces.td   |   4 +
 clang/lib/CIR/Interfaces/CIROpInterfaces.cpp  |   4 +
 clang/test/CIR/IR/global.cir                  | 128 +++++++++---------
 4 files changed, 76 insertions(+), 64 deletions(-)

diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
index 4c171c309ae29..cb7488d3aee36 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.h
@@ -5,6 +5,10 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Defines the interface to CIR operations.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef CLANG_CIR_INTERFACES_CIR_OP_H
 #define CLANG_CIR_INTERFACES_CIR_OP_H
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index 235b5a05c5ba8..64a96bd55cf86 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -5,6 +5,10 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Defines the interface to CIR operations.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
 #define CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
diff --git a/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp b/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
index dfbbdc2fd2382..3ae103c2e65b4 100644
--- a/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
+++ b/clang/lib/CIR/Interfaces/CIROpInterfaces.cpp
@@ -5,6 +5,10 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Defines the interface to CIR operations.
+//
+//===----------------------------------------------------------------------===//
 #include "clang/CIR/Interfaces/CIROpInterfaces.h"
 
 using namespace cir;
diff --git a/clang/test/CIR/IR/global.cir b/clang/test/CIR/IR/global.cir
index 9d187686d996c..12eda5a946af5 100644
--- a/clang/test/CIR/IR/global.cir
+++ b/clang/test/CIR/IR/global.cir
@@ -1,69 +1,69 @@
 // RUN: cir-opt %s -o - | FileCheck %s
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
-  cir.global @c : !cir.int<s, 8>
-  cir.global @sc : !cir.int<s, 8>
-  cir.global @uc : !cir.int<u, 8>
-  cir.global @ss : !cir.int<s, 16>
-  cir.global @us = #cir.int<100> : !cir.int<u, 16>
-  cir.global @si = #cir.int<42> : !cir.int<s, 32>
-  cir.global @ui : !cir.int<u, 32>
-  cir.global @sl : !cir.int<s, 64>
-  cir.global @ul : !cir.int<u, 64>
-  cir.global @sll : !cir.int<s, 64>
-  cir.global @ull = #cir.int<123456> : !cir.int<u, 64>
-  cir.global @s128 : !cir.int<s, 128>
-  cir.global @u128 : !cir.int<u, 128>
-  cir.global @wc : !cir.int<s, 32>
-  cir.global @c8 : !cir.int<u, 8>
-  cir.global @c16 : !cir.int<u, 16>
-  cir.global @c32 : !cir.int<u, 32>
-  cir.global @sb20 : !cir.int<s, 20>
-  cir.global @ub48 : !cir.int<u, 48>
-  cir.global @f16 : !cir.f16
-  cir.global @bf16 : !cir.bf16
-  cir.global @f : !cir.float
-  cir.global @d = #cir.fp<1.250000e+00> : !cir.double
-  cir.global @ld : !cir.long_double<!cir.f80>
-  cir.global @f128 : !cir.f128
-  cir.global @vp : !cir.ptr<!cir.void>
-  cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
-  cir.global @dp : !cir.ptr<!cir.double>
-  cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
-  cir.global @fp : !cir.ptr<!cir.func<()>>
-  cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
-  cir.global @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>
+  cir.global external @c : !cir.int<s, 8>
+  cir.global external @sc : !cir.int<s, 8>
+  cir.global external @uc : !cir.int<u, 8>
+  cir.global external @ss : !cir.int<s, 16>
+  cir.global external @us = #cir.int<100> : !cir.int<u, 16>
+  cir.global external @si = #cir.int<42> : !cir.int<s, 32>
+  cir.global external @ui : !cir.int<u, 32>
+  cir.global external @sl : !cir.int<s, 64>
+  cir.global external @ul : !cir.int<u, 64>
+  cir.global external @sll : !cir.int<s, 64>
+  cir.global external @ull = #cir.int<123456> : !cir.int<u, 64>
+  cir.global external @s128 : !cir.int<s, 128>
+  cir.global external @u128 : !cir.int<u, 128>
+  cir.global external @wc : !cir.int<s, 32>
+  cir.global external @c8 : !cir.int<u, 8>
+  cir.global external @c16 : !cir.int<u, 16>
+  cir.global external @c32 : !cir.int<u, 32>
+  cir.global external @sb20 : !cir.int<s, 20>
+  cir.global external @ub48 : !cir.int<u, 48>
+  cir.global external @f16 : !cir.f16
+  cir.global external @bf16 : !cir.bf16
+  cir.global external @f : !cir.float
+  cir.global external @d = #cir.fp<1.250000e+00> : !cir.double
+  cir.global external @ld : !cir.long_double<!cir.f80>
+  cir.global external @f128 : !cir.f128
+  cir.global external @vp : !cir.ptr<!cir.void>
+  cir.global external @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
+  cir.global external @dp : !cir.ptr<!cir.double>
+  cir.global external @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
+  cir.global external @fp : !cir.ptr<!cir.func<()>>
+  cir.global external @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
+  cir.global external @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>
 }
 
-// CHECK: cir.global @c : !cir.int<s, 8>
-// CHECK: cir.global @sc : !cir.int<s, 8>
-// CHECK: cir.global @uc : !cir.int<u, 8>
-// CHECK: cir.global @ss : !cir.int<s, 16>
-// CHECK: cir.global @us = #cir.int<100>
-// CHECK: cir.global @si = #cir.int<42>
-// CHECK: cir.global @ui : !cir.int<u, 32>
-// CHECK: cir.global @sl : !cir.int<s, 64>
-// CHECK: cir.global @ul : !cir.int<u, 64>
-// CHECK: cir.global @sll : !cir.int<s, 64>
-// CHECK: cir.global @ull = #cir.int<123456> : !cir.int<u, 64>
-// CHECK: cir.global @s128 : !cir.int<s, 128>
-// CHECK: cir.global @u128 : !cir.int<u, 128>
-// CHECK: cir.global @wc : !cir.int<s, 32>
-// CHECK: cir.global @c8 : !cir.int<u, 8>
-// CHECK: cir.global @c16 : !cir.int<u, 16>
-// CHECK: cir.global @c32 : !cir.int<u, 32>
-// CHECK: cir.global @sb20 : !cir.int<s, 20>
-// CHECK: cir.global @ub48 : !cir.int<u, 48>
-// CHECK: cir.global @f16 : !cir.f16
-// CHECK: cir.global @bf16 : !cir.bf16
-// CHECK: cir.global @f : !cir.float
-// CHECK: cir.global @d = #cir.fp<1.250000e+00> : !cir.double
-// CHECK: cir.global @ld : !cir.long_double<!cir.f80>
-// CHECK: cir.global @f128 : !cir.f128
-// CHECK: cir.global @vp : !cir.ptr<!cir.void>
-// CHECK: cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
-// CHECK: cir.global @dp : !cir.ptr<!cir.double>
-// CHECK: cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
-// CHECK: cir.global @fp : !cir.ptr<!cir.func<()>>
-// CHECK: cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
-// CHECK: cir.global @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>
+// CHECK: cir.global external @c : !cir.int<s, 8>
+// CHECK: cir.global external @sc : !cir.int<s, 8>
+// CHECK: cir.global external @uc : !cir.int<u, 8>
+// CHECK: cir.global external @ss : !cir.int<s, 16>
+// CHECK: cir.global external @us = #cir.int<100>
+// CHECK: cir.global external @si = #cir.int<42>
+// CHECK: cir.global external @ui : !cir.int<u, 32>
+// CHECK: cir.global external @sl : !cir.int<s, 64>
+// CHECK: cir.global external @ul : !cir.int<u, 64>
+// CHECK: cir.global external @sll : !cir.int<s, 64>
+// CHECK: cir.global external @ull = #cir.int<123456> : !cir.int<u, 64>
+// CHECK: cir.global external @s128 : !cir.int<s, 128>
+// CHECK: cir.global external @u128 : !cir.int<u, 128>
+// CHECK: cir.global external @wc : !cir.int<s, 32>
+// CHECK: cir.global external @c8 : !cir.int<u, 8>
+// CHECK: cir.global external @c16 : !cir.int<u, 16>
+// CHECK: cir.global external @c32 : !cir.int<u, 32>
+// CHECK: cir.global external @sb20 : !cir.int<s, 20>
+// CHECK: cir.global external @ub48 : !cir.int<u, 48>
+// CHECK: cir.global external @f16 : !cir.f16
+// CHECK: cir.global external @bf16 : !cir.bf16
+// CHECK: cir.global external @f : !cir.float
+// CHECK: cir.global external @d = #cir.fp<1.250000e+00> : !cir.double
+// CHECK: cir.global external @ld : !cir.long_double<!cir.f80>
+// CHECK: cir.global external @f128 : !cir.f128
+// CHECK: cir.global external @vp : !cir.ptr<!cir.void>
+// CHECK: cir.global external @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
+// CHECK: cir.global external @dp : !cir.ptr<!cir.double>
+// CHECK: cir.global external @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
+// CHECK: cir.global external @fp : !cir.ptr<!cir.func<()>>
+// CHECK: cir.global external @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!cir.int<s, 32>) -> !cir.int<s, 32>>>
+// CHECK: cir.global external @fpvar : !cir.ptr<!cir.func<(!cir.int<s, 32>, ...)>>

>From 422aded79077ee6e69e05d85c64b73e5f3b25e5d Mon Sep 17 00:00:00 2001
From: Henrich Lauko <xlauko at mail.muni.cz>
Date: Sat, 1 Mar 2025 02:04:44 +0100
Subject: [PATCH 4/7] cherry-pick 0bedc28 Clean up and complete
 CIRGlobalValueInterface methods

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  9 ---
 .../clang/CIR/Interfaces/CIROpInterfaces.td   | 64 ++++++++++++++++---
 2 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2cef98099fdbb..e2ab50c78ec2d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -517,15 +517,6 @@ def GlobalOp : CIR_Op<"global"> {
   let extraClassDeclaration = [{
     bool isDeclaration() { return !getInitialValue(); }
     bool hasInitializer() { return !isDeclaration(); }
-    bool hasAvailableExternallyLinkage() {
-      return cir::isAvailableExternallyLinkage(getLinkage());
-    }
-    bool hasInternalLinkage() {
-      return cir::isInternalLinkage(getLinkage());
-    }
-    /// Whether the definition of this global may be replaced at link time.
-    bool isWeakForLinker() { return cir::isWeakForLinker(getLinkage()); }
-    bool isDSOLocal() { return getDsolocal(); }
   }];
 
   let skipDefaultBuilders = 1;
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index 64a96bd55cf86..bd78be41d0bca 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -14,14 +14,54 @@
 #define CLANG_CIR_INTERFACES_CIROPINTERFACES_TD
 
 include "mlir/IR/OpBase.td"
+include "mlir/IR/SymbolInterfaces.td"
 
 let cppNamespace = "::cir" in {
-  def CIRGlobalValueInterface : OpInterface<"CIRGlobalValueInterface"> {
+  def CIRGlobalValueInterface
+      : OpInterface<"CIRGlobalValueInterface", [Symbol]> {
 
     let methods =
-        [InterfaceMethod<"", "bool", "hasAvailableExternallyLinkage", (ins),
+        [InterfaceMethod<"", "bool", "hasExternalLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isExternalLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasAvailableExternallyLinkage", (ins),
                          [{}],
-                         /*defaultImplementation=*/[{ return false; }]>,
+                         /*defaultImplementation=*/[{
+        return cir::isAvailableExternallyLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasLinkOnceLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isLinkOnceLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasLinkOnceAnyLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isLinkOnceAnyLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasLinkOnceODRLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isLinkOnceODRLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasWeakLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isWeakLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasWeakAnyLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isWeakAnyLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasWeakODRLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isWeakODRLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasInternalLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isInternalLinkage($_op.getLinkage());
+      }]>,
+         InterfaceMethod<"", "bool", "hasPrivateLinkage", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isPrivateLinkage($_op.getLinkage());
+      }]>,
          InterfaceMethod<"", "bool", "hasLocalLinkage", (ins), [{}],
                          /*defaultImplementation=*/[{
         return cir::isLocalLinkage($_op.getLinkage());
@@ -30,9 +70,9 @@ let cppNamespace = "::cir" in {
                          /*defaultImplementation=*/[{
         return cir::isExternalWeakLinkage($_op.getLinkage());
       }]>,
-         InterfaceMethod<"", "bool", "isExternalLinkage", (ins), [{}],
+         InterfaceMethod<"", "bool", "hasCommonLinkage", (ins), [{}],
                          /*defaultImplementation=*/[{
-        return cir::isExternalLinkage($_op.getLinkage());
+        return cir::isCommonLinkage($_op.getLinkage());
       }]>,
          InterfaceMethod<"", "bool", "isDeclarationForLinker", (ins), [{}],
                          /*defaultImplementation=*/[{
@@ -44,10 +84,18 @@ let cppNamespace = "::cir" in {
                          /*defaultImplementation=*/[{
         $_op.setDsolocal(val);
       }]>,
-    ];
+         InterfaceMethod<"", "bool", "isDSOLocal", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return $_op.getDsolocal();
+      }]>,
+         InterfaceMethod<"", "bool", "isWeakForLinker", (ins), [{}],
+                         /*defaultImplementation=*/[{
+        return cir::isWeakForLinker($_op.getLinkage());
+      }]>];
     let extraClassDeclaration = [{
-    bool canBenefitFromLocalAlias();
-  }];
+      bool hasDefaultVisibility();
+      bool canBenefitFromLocalAlias();
+    }];
   }
 
 } // namespace cir

>From 403356204953b27528f6e27e63a4be5cde446f38 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Tue, 4 Mar 2025 18:27:47 +0100
Subject: [PATCH 5/7] Add CIR -> CIR test for global variable linkage

---
 clang/test/CIR/IR/global-var-linkage.cir | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 clang/test/CIR/IR/global-var-linkage.cir

diff --git a/clang/test/CIR/IR/global-var-linkage.cir b/clang/test/CIR/IR/global-var-linkage.cir
new file mode 100644
index 0000000000000..055201b27000d
--- /dev/null
+++ b/clang/test/CIR/IR/global-var-linkage.cir
@@ -0,0 +1,18 @@
+// RUN: cir-opt %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.global external @aaaa : !cir.int<s, 32>
+  cir.global internal @bbbb : !cir.int<s, 32>
+  cir.global linkonce_odr @cccc : !cir.int<s, 32>
+  cir.global internal @ffff = #cir.int<0> : !cir.int<s, 32>
+  cir.global weak_odr @dddd : !cir.int<s, 32>
+}
+
+// CHECK: module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+// CHECK:   cir.global external @aaaa : !cir.int<s, 32>
+// CHECK:   cir.global internal @bbbb : !cir.int<s, 32>
+// CHECK:   cir.global linkonce_odr @cccc : !cir.int<s, 32>
+// CHECK:   cir.global internal @ffff = #cir.int<0> : !cir.int<s, 32>
+// CHECK:   cir.global weak_odr @dddd : !cir.int<s, 32>
+// CHECK: }

>From 8639f6576c7ec814f1aaaea3f813d5d9e01e8001 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Tue, 4 Mar 2025 19:50:56 +0100
Subject: [PATCH 6/7] Reformat CIROpInterfaces.td

---
 .../clang/CIR/Interfaces/CIROpInterfaces.td   | 146 +++++++++++-------
 1 file changed, 93 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index bd78be41d0bca..39ef402c59e43 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -20,78 +20,118 @@ let cppNamespace = "::cir" in {
   def CIRGlobalValueInterface
       : OpInterface<"CIRGlobalValueInterface", [Symbol]> {
 
-    let methods =
-        [InterfaceMethod<"", "bool", "hasExternalLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+    let methods = [
+      InterfaceMethod<"",
+      "bool", "hasExternalLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isExternalLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasAvailableExternallyLinkage", (ins),
-                         [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasAvailableExternallyLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isAvailableExternallyLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasLinkOnceLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasLinkOnceLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isLinkOnceLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasLinkOnceAnyLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasLinkOnceAnyLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isLinkOnceAnyLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasLinkOnceODRLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasLinkOnceODRLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isLinkOnceODRLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasWeakLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasWeakLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isWeakLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasWeakAnyLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasWeakAnyLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isWeakAnyLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasWeakODRLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasWeakODRLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isWeakODRLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasInternalLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasInternalLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isInternalLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasPrivateLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasPrivateLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isPrivateLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasLocalLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasLocalLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isLocalLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasExternalWeakLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasExternalWeakLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isExternalWeakLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "hasCommonLinkage", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasCommonLinkage", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isCommonLinkage($_op.getLinkage());
-      }]>,
-         InterfaceMethod<"", "bool", "isDeclarationForLinker", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "isDeclarationForLinker", (ins), [{}],
+      /*defaultImplementation=*/[{
         if ($_op.hasAvailableExternallyLinkage())
           return true;
         return $_op.isDeclaration();
-      }]>,
-         InterfaceMethod<"", "void", "setDSOLocal", (ins "bool":$val), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "hasComdat", (ins), [{}],
+      /*defaultImplementation=*/[{
+        return $_op.getComdat();
+      }]
+      >,
+      InterfaceMethod<"",
+      "void", "setDSOLocal", (ins "bool":$val), [{}],
+      /*defaultImplementation=*/[{
         $_op.setDsolocal(val);
-      }]>,
-         InterfaceMethod<"", "bool", "isDSOLocal", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "isDSOLocal", (ins), [{}],
+      /*defaultImplementation=*/[{
         return $_op.getDsolocal();
-      }]>,
-         InterfaceMethod<"", "bool", "isWeakForLinker", (ins), [{}],
-                         /*defaultImplementation=*/[{
+      }]
+      >,
+      InterfaceMethod<"",
+      "bool", "isWeakForLinker", (ins), [{}],
+      /*defaultImplementation=*/[{
         return cir::isWeakForLinker($_op.getLinkage());
-      }]>];
+      }]
+      >
+    ];
     let extraClassDeclaration = [{
       bool hasDefaultVisibility();
       bool canBenefitFromLocalAlias();

>From 9f4fcdfb73c8bf1e6df01eb46ffd52d8a34ac0ab Mon Sep 17 00:00:00 2001
From: Morris Hafner <mmha at users.noreply.github.com>
Date: Wed, 5 Mar 2025 13:25:32 +0100
Subject: [PATCH 7/7] Update clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h

Co-authored-by: Henrich Lauko <xlauko at mail.muni.cz>
---
 clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
index 2b7270c42d343..fead5725d183d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
@@ -1,5 +1,4 @@
 //===----------------------------------------------------------------------===//
-//-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.



More information about the cfe-commits mailing list