[clang] [llvm] [clang, SystemZ] Pass HasDef flag to getMinGlobalAlign(). (PR #73511)

Jonas Paulsson via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 19 12:10:52 PST 2023


https://github.com/JonPsson1 updated https://github.com/llvm/llvm-project/pull/73511

>From de673830f94a519c94874516f4da24705b736b2e Mon Sep 17 00:00:00 2001
From: Jonas Paulsson <paulson1 at linux.ibm.com>
Date: Thu, 23 Nov 2023 17:22:32 +0100
Subject: [PATCH 1/4] IP

---
 clang/include/clang/AST/ASTContext.h          |   4 +-
 clang/include/clang/Basic/TargetInfo.h        |   7 +-
 clang/include/clang/Driver/Options.td         |   4 +
 clang/lib/AST/ASTContext.cpp                  |  15 ++-
 clang/lib/Basic/Targets/AArch64.cpp           |   5 +-
 clang/lib/Basic/Targets/AArch64.h             |   2 +-
 clang/lib/Basic/Targets/CSKY.cpp              |   2 +-
 clang/lib/Basic/Targets/CSKY.h                |   2 +-
 clang/lib/Basic/Targets/NVPTX.cpp             |   3 +-
 clang/lib/Basic/Targets/SPIR.h                |   3 +-
 clang/lib/Basic/Targets/SystemZ.cpp           |  10 ++
 clang/lib/Basic/Targets/SystemZ.h             |   9 +-
 clang/lib/CodeGen/CodeGenModule.cpp           |   7 +-
 clang/lib/Driver/ToolChains/Arch/SystemZ.cpp  |   8 ++
 clang/lib/Sema/SemaOpenMP.cpp                 |   3 +-
 .../test/CodeGen/SystemZ/unaligned-symbols.c  | 104 ++++++++++++++++++
 llvm/lib/Target/SystemZ/SystemZFeatures.td    |   5 +
 17 files changed, 171 insertions(+), 22 deletions(-)
 create mode 100644 clang/test/CodeGen/SystemZ/unaligned-symbols.c

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3e46a5da3fc043..9e60ca8fb2ea8c 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2406,11 +2406,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   /// Return the alignment in bits that should be given to a
   /// global variable with type \p T.
-  unsigned getAlignOfGlobalVar(QualType T) const;
+  unsigned getAlignOfGlobalVar(QualType T, bool HasDef) const;
 
   /// Return the alignment in characters that should be given to a
   /// global variable with type \p T.
-  CharUnits getAlignOfGlobalVarInChars(QualType T) const;
+  CharUnits getAlignOfGlobalVarInChars(QualType T, bool HasDef) const;
 
   /// Return a conservative estimate of the alignment of the specified
   /// decl \p D.
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index aa0f5023104a1a..ace9e89eda5869 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -704,8 +704,11 @@ class TargetInfo : public TransferrableTargetInfo,
   }
 
   /// getMinGlobalAlign - Return the minimum alignment of a global variable,
-  /// unless its alignment is explicitly reduced via attributes.
-  virtual unsigned getMinGlobalAlign (uint64_t) const {
+  /// unless its alignment is explicitly reduced via attributes. It may be
+  /// that an external symbol needs to be considered unaligned (like
+  /// artificial symbols created from a linker script). If \param HasDef is
+  /// false, this symbol does not have a definition and is external.
+  virtual unsigned getMinGlobalAlign(uint64_t Size, bool HasDef) const {
     return MinGlobalAlign;
   }
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1b02087425b751..dbfb7580db7535 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4587,6 +4587,10 @@ def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
   HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64/LoongArch/RISC-V only)">;
 def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_Group>,
   HelpText<"Force all memory accesses to be aligned (AArch32/AArch64/LoongArch/RISC-V only)">;
+def munaligned_symbols : Flag<["-"], "munaligned-symbols">, Group<m_Group>,
+  HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
+def mno_unaligned_symbols : Flag<["-"], "mno-unaligned-symbols">, Group<m_Group>,
+  HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
 } // let Flags = [TargetSpecific]
 def mstrict_align : Flag<["-"], "mstrict-align">, Alias<mno_unaligned_access>,
   Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0395b3e47ab6f8..ff15206cbe8862 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1681,7 +1681,8 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
       if (VD->hasGlobalStorage() && !ForAlignof) {
         uint64_t TypeSize =
             !BaseT->isIncompleteType() ? getTypeSize(T.getTypePtr()) : 0;
-        Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize));
+        Align = std::max(Align, getTargetInfo().getMinGlobalAlign(
+                                    TypeSize, VD->hasDefinition()));
       }
 
     // Fields can be subject to extra alignment constraints, like if
@@ -2502,17 +2503,19 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const {
 }
 
 /// getAlignOfGlobalVar - Return the alignment in bits that should be given
-/// to a global variable of the specified type.
-unsigned ASTContext::getAlignOfGlobalVar(QualType T) const {
+/// to a global variable of the specified type (see comment for
+/// getMinGlobalAlign about HasDef).
+unsigned ASTContext::getAlignOfGlobalVar(QualType T, bool HasDef) const {
   uint64_t TypeSize = getTypeSize(T.getTypePtr());
   return std::max(getPreferredTypeAlign(T),
-                  getTargetInfo().getMinGlobalAlign(TypeSize));
+                  getTargetInfo().getMinGlobalAlign(TypeSize, HasDef));
 }
 
 /// getAlignOfGlobalVarInChars - Return the alignment in characters that
 /// should be given to a global variable of the specified type.
-CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const {
-  return toCharUnitsFromBits(getAlignOfGlobalVar(T));
+CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T,
+                                                 bool HasDef) const {
+  return toCharUnitsFromBits(getAlignOfGlobalVar(T, HasDef));
 }
 
 CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const {
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index def16c032c869e..7690f36c254499 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -1517,8 +1517,9 @@ MicrosoftARM64TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
   return CCK_MicrosoftWin64;
 }
 
-unsigned MicrosoftARM64TargetInfo::getMinGlobalAlign(uint64_t TypeSize) const {
-  unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize);
+unsigned MicrosoftARM64TargetInfo::getMinGlobalAlign(uint64_t TypeSize,
+                                                     bool HasDef) const {
+  unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize, HasDef);
 
   // MSVC does size based alignment for arm64 based on alignment section in
   // below document, replicate that to keep alignment consistent with object
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index f0e0782e7abe97..8cfc4281c44456 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -236,7 +236,7 @@ class LLVM_LIBRARY_VISIBILITY MicrosoftARM64TargetInfo
   TargetInfo::CallingConvKind
   getCallingConvKind(bool ClangABICompat4) const override;
 
-  unsigned getMinGlobalAlign(uint64_t TypeSize) const override;
+  unsigned getMinGlobalAlign(uint64_t TypeSize, bool HasDef) const override;
 };
 
 // ARM64 MinGW target
diff --git a/clang/lib/Basic/Targets/CSKY.cpp b/clang/lib/Basic/Targets/CSKY.cpp
index 851f27dbb1e5ee..e173fa1490cd72 100644
--- a/clang/lib/Basic/Targets/CSKY.cpp
+++ b/clang/lib/Basic/Targets/CSKY.cpp
@@ -308,7 +308,7 @@ bool CSKYTargetInfo::validateAsmConstraint(
   }
 }
 
-unsigned CSKYTargetInfo::getMinGlobalAlign(uint64_t Size) const {
+unsigned CSKYTargetInfo::getMinGlobalAlign(uint64_t Size, bool HasDef) const {
   if (Size >= 32)
     return 32;
   return 0;
diff --git a/clang/lib/Basic/Targets/CSKY.h b/clang/lib/Basic/Targets/CSKY.h
index 11404e37db368a..33a7b7ac2b4c34 100644
--- a/clang/lib/Basic/Targets/CSKY.h
+++ b/clang/lib/Basic/Targets/CSKY.h
@@ -71,7 +71,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo {
 
   bool isValidCPUName(StringRef Name) const override;
 
-  unsigned getMinGlobalAlign(uint64_t) const override;
+  unsigned getMinGlobalAlign(uint64_t, bool) const override;
 
   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
 
diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp
index c0b5db795e2708..adf35bc00868d1 100644
--- a/clang/lib/Basic/Targets/NVPTX.cpp
+++ b/clang/lib/Basic/Targets/NVPTX.cpp
@@ -115,7 +115,8 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
   LongAlign = HostTarget->getLongAlign();
   LongLongWidth = HostTarget->getLongLongWidth();
   LongLongAlign = HostTarget->getLongLongAlign();
-  MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0);
+  MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,
+                                                 /* HasDef = */ true);
   NewAlign = HostTarget->getNewAlign();
   DefaultAlignForAttributeAligned =
       HostTarget->getDefaultAlignForAttributeAligned();
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 9ab2b7c6093639..ff5563d8ecf449 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -124,7 +124,8 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
       LongAlign = HostTarget->getLongAlign();
       LongLongWidth = HostTarget->getLongLongWidth();
       LongLongAlign = HostTarget->getLongLongAlign();
-      MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0);
+      MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,
+                                                     /* HasDef = */ true);
       NewAlign = HostTarget->getNewAlign();
       DefaultAlignForAttributeAligned =
           HostTarget->getDefaultAlignForAttributeAligned();
diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index a9b5ca48386133..76825c6d6a5429 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -138,6 +138,16 @@ bool SystemZTargetInfo::hasFeature(StringRef Feature) const {
       .Default(false);
 }
 
+unsigned SystemZTargetInfo::getMinGlobalAlign(uint64_t Size,
+                                              bool HasDef) const {
+  // Don't enforce the minimum alignment on an external symbol if
+  // -munaligned-symbols is passed.
+  if (UnalignedSymbols && !HasDef)
+    return 0;
+
+  return MinGlobalAlign;
+}
+
 void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   Builder.defineMacro("__s390__");
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index e4ec338880f210..b25360cfbc1c96 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -29,11 +29,13 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
   bool HasTransactionalExecution;
   bool HasVector;
   bool SoftFloat;
+  bool UnalignedSymbols;
 
 public:
   SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
       : TargetInfo(Triple), CPU("z10"), ISARevision(8),
-        HasTransactionalExecution(false), HasVector(false), SoftFloat(false) {
+        HasTransactionalExecution(false), HasVector(false), SoftFloat(false),
+        UnalignedSymbols(false) {
     IntMaxType = SignedLong;
     Int64Type = SignedLong;
     IntWidth = IntAlign = 32;
@@ -64,6 +66,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
     HasStrictFP = true;
   }
 
+  unsigned getMinGlobalAlign(uint64_t Size, bool HasDef) const override;
+
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override;
 
@@ -163,6 +167,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
     HasTransactionalExecution = false;
     HasVector = false;
     SoftFloat = false;
+    UnalignedSymbols = false;
     for (const auto &Feature : Features) {
       if (Feature == "+transactional-execution")
         HasTransactionalExecution = true;
@@ -170,6 +175,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
         HasVector = true;
       else if (Feature == "+soft-float")
         SoftFloat = true;
+      else if (Feature == "+unaligned-symbols")
+        UnalignedSymbols = true;
     }
     HasVector &= !SoftFloat;
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 7ad26ace328ab2..74bd6a563f4c88 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6302,7 +6302,8 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
 ConstantAddress
 CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
                                                   StringRef Name) {
-  CharUnits Alignment = getContext().getAlignOfGlobalVarInChars(S->getType());
+  CharUnits Alignment =
+      getContext().getAlignOfGlobalVarInChars(S->getType(), /*HasDef=*/true);
 
   llvm::Constant *C = GetConstantArrayFromStringLiteral(S);
   llvm::GlobalVariable **Entry = nullptr;
@@ -6365,8 +6366,8 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
 ConstantAddress CodeGenModule::GetAddrOfConstantCString(
     const std::string &Str, const char *GlobalName) {
   StringRef StrWithNull(Str.c_str(), Str.size() + 1);
-  CharUnits Alignment =
-    getContext().getAlignOfGlobalVarInChars(getContext().CharTy);
+  CharUnits Alignment = getContext().getAlignOfGlobalVarInChars(
+      getContext().CharTy, /*HasDef=*/true);
 
   llvm::Constant *C =
       llvm::ConstantDataArray::getString(getLLVMContext(), StrWithNull, false);
diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
index 588bc3176d73e3..2213f431eb8114 100644
--- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
@@ -71,4 +71,12 @@ void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args,
   systemz::FloatABI FloatABI = systemz::getSystemZFloatABI(D, Args);
   if (FloatABI == systemz::FloatABI::Soft)
     Features.push_back("+soft-float");
+
+  if (const Arg *A = Args.getLastArg(options::OPT_munaligned_symbols,
+                                     options::OPT_mno_unaligned_symbols)) {
+    if (A->getOption().matches(options::OPT_munaligned_symbols))
+      Features.push_back("+unaligned-symbols");
+    else
+      Features.push_back("-unaligned-symbols");
+  }
 }
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 3826994ef2126c..b167762561019f 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2293,9 +2293,10 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
   // and alignment, because the runtime library only deals with uintptr types.
   // If it does not fit the uintptr size, we need to pass the data by reference
   // instead.
+  bool IsExtern = isa<VarDecl>(D) && !cast<VarDecl>(D)->hasDefinition();
   if (!IsByRef && (Ctx.getTypeSizeInChars(Ty) >
                        Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) ||
-                   Ctx.getAlignOfGlobalVarInChars(Ty) >
+                   Ctx.getAlignOfGlobalVarInChars(Ty, /*HasDef=*/!IsExtern) >
                        Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) {
     IsByRef = true;
   }
diff --git a/clang/test/CodeGen/SystemZ/unaligned-symbols.c b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
new file mode 100644
index 00000000000000..0906d1b67dae99
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
@@ -0,0 +1,104 @@
+// RUN: %clang -target s390x-linux-gnu %s -o - -emit-llvm -S \
+// RUN:    | FileCheck %s -check-prefixes=CHECK,ALIGNED
+
+// RUN: %clang -target s390x-linux-gnu %s -o - -emit-llvm -S \
+// RUN:    -mno-unaligned-symbols | FileCheck %s -check-prefixes=CHECK,ALIGNED
+
+// RUN: %clang -target s390x-linux-gnu %s -o - -emit-llvm -S \
+// RUN:    -munaligned-symbols | FileCheck %s -check-prefixes=CHECK,UNALIGN
+
+// RUN: %clang -cc1 -triple s390x-linux-gnu %s -o - -emit-llvm \
+// RUN:    -target-feature +unaligned-symbols | FileCheck %s -check-prefixes=CHECK,UNALIGN
+
+
+// With -munaligned-symbols, the external and unaligned ("ExtUnal...")
+// variable of each test should be treated as unaligned. For the explicitly
+// aligned ("ExtExplAlign...") variables and those defined in the translation
+// unit ("Aligned..."), the normal ABI alignment of 2 should still be
+// in effect.
+
+// ALIGNED: @ExtUnal = external global i8, align 2
+// UNALIGN: @ExtUnal = external global i8, align 1
+// CHECK:   @ExtExplAlign = external global i8, align 2
+// CHECK:   @Aligned = {{(dso_local )?}}global i8 0, align 2
+extern unsigned char ExtUnal;
+extern unsigned char ExtExplAlign __attribute__((aligned(2)));
+unsigned char Aligned;
+unsigned char foo0 () {
+  return ExtUnal + ExtExplAlign + Aligned;
+}
+
+// ALIGNED: @ExtUnal_c2Arr = external global [2 x i8], align 2
+// UNALIGN: @ExtUnal_c2Arr = external global [2 x i8], align 1
+// CHECK:   @ExtExplAlign_c2Arr = external global [2 x i8], align 2
+// CHECK:   @Aligned_c2Arr = {{(dso_local )?}}global [2 x i8] zeroinitializer, align 2
+extern unsigned char ExtUnal_c2Arr[2];
+extern unsigned char ExtExplAlign_c2Arr[2] __attribute__((aligned(2)));
+unsigned char Aligned_c2Arr[2];
+unsigned char foo1 () {
+  return ExtUnal_c2Arr[0] + ExtExplAlign_c2Arr[0] + Aligned_c2Arr[0];
+}
+
+// ALIGNED: @ExtUnal_s1c = external global %struct.s1c, align 2
+// UNALIGN: @ExtUnal_s1c = external global %struct.s1c, align 1
+// CHECK:   @ExtExplAlign_s1c = external global %struct.s1c, align 2
+// CHECK:   @Aligned_s1c = {{(dso_local )?}}global %struct.s1c zeroinitializer, align 2
+struct s1c { char c; };
+extern struct s1c ExtUnal_s1c;
+extern struct s1c ExtExplAlign_s1c __attribute__((aligned(2)));
+struct s1c Aligned_s1c;
+unsigned char foo2 () {
+  return ExtUnal_s1c.c + ExtExplAlign_s1c.c + Aligned_s1c.c;
+}
+
+// ALIGNED: @ExtUnal_s2c = external global %struct.s2c, align 2
+// UNALIGN: @ExtUnal_s2c = external global %struct.s2c, align 1
+// CHECK:   @ExtExplAlign_s2c = external global %struct.s2c, align 2
+// CHECK:   @Aligned_s2c = {{(dso_local )?}}global %struct.s2c zeroinitializer, align 2
+struct s2c { char c; char c1;};
+extern struct s2c ExtUnal_s2c;
+extern struct s2c ExtExplAlign_s2c __attribute__((aligned(2)));
+struct s2c Aligned_s2c;
+unsigned char foo3 () {
+  return ExtUnal_s2c.c + ExtExplAlign_s2c.c + Aligned_s2c.c;
+}
+
+// ALIGNED: @ExtUnal_s_c2Arr = external global %struct.s_c2Arr, align 2
+// UNALIGN: @ExtUnal_s_c2Arr = external global %struct.s_c2Arr, align 1
+// CHECK:   @ExtExplAlign_s_c2Arr = external global %struct.s_c2Arr, align 2
+// CHECK:   @Aligned_s_c2Arr = {{(dso_local )?}}global %struct.s_c2Arr zeroinitializer, align 2
+struct s_c2Arr { char c[2]; };
+extern struct s_c2Arr ExtUnal_s_c2Arr;
+extern struct s_c2Arr ExtExplAlign_s_c2Arr __attribute__((aligned(2)));
+struct s_c2Arr Aligned_s_c2Arr;
+unsigned char foo4 () {
+  return ExtUnal_s_c2Arr.c[0] + ExtExplAlign_s_c2Arr.c[0] + Aligned_s_c2Arr.c[0];
+}
+
+// ALIGNED: @ExtUnal_s_packed = external global %struct.s_packed, align 2
+// UNALIGN: @ExtUnal_s_packed = external global %struct.s_packed, align 1
+// CHECK:   @ExtExplAlign_s_packed = external global %struct.s_packed, align 2
+// CHECK:   @Aligned_s_packed = {{(dso_local )?}}global %struct.s_packed zeroinitializer, align 2
+struct s_packed {
+    int __attribute__((__packed__)) i;
+    char c;
+};
+extern struct s_packed ExtUnal_s_packed;
+extern struct s_packed ExtExplAlign_s_packed __attribute__((aligned(2)));
+struct s_packed Aligned_s_packed;
+unsigned char foo5 () {
+  return ExtUnal_s_packed.c + ExtExplAlign_s_packed.c + Aligned_s_packed.c;
+}
+
+// ALIGNED: @ExtUnAl_s_nested = external global [2 x %struct.s_nested], align 2
+// UNALIGN: @ExtUnAl_s_nested = external global [2 x %struct.s_nested], align 1
+// CHECK:   @ExtExplAlign_s_nested = external global [2 x %struct.s_nested], align 2
+// CHECK:   @Aligned_s_nested = {{(dso_local )?}}global [2 x %struct.s_nested] zeroinitializer, align 2
+struct s_nested { struct s_c2Arr a[2]; };
+extern struct s_nested ExtUnAl_s_nested[2];
+extern struct s_nested ExtExplAlign_s_nested[2] __attribute__((aligned(2)));
+struct s_nested Aligned_s_nested[2];
+unsigned char foo6 () {
+  return ExtUnAl_s_nested[0].a[0].c[0] + ExtExplAlign_s_nested[0].a[0].c[0] +
+         Aligned_s_nested[0].a[0].c[0];
+}
diff --git a/llvm/lib/Target/SystemZ/SystemZFeatures.td b/llvm/lib/Target/SystemZ/SystemZFeatures.td
index fdd94206421a41..a1e2a92b40ac23 100644
--- a/llvm/lib/Target/SystemZ/SystemZFeatures.td
+++ b/llvm/lib/Target/SystemZ/SystemZFeatures.td
@@ -37,6 +37,11 @@ def FeatureBackChain : SystemZFeature<
   "Store the address of the caller's frame into the callee's stack frame"
 >;
 
+def FeatureUnalignedSymbols : SystemZFeature<
+  "unaligned-symbols", "UnalignedSymbols", (all_of FeatureUnalignedSymbols),
+  "Don't apply the ABI minimum alignment to external symbols."
+>;
+
 //===----------------------------------------------------------------------===//
 //
 // New features added in the Ninth Edition of the z/Architecture

>From c0001b5b3fdcf3fdab76defc21ead8aad1e80746 Mon Sep 17 00:00:00 2001
From: Jonas Paulsson <paulson1 at linux.ibm.com>
Date: Tue, 19 Dec 2023 12:56:24 -0600
Subject: [PATCH 2/4] Also handle weak symbols

---
 clang/include/clang/AST/ASTContext.h           |  4 ++--
 clang/include/clang/Basic/TargetInfo.h         |  9 ++++-----
 clang/lib/AST/ASTContext.cpp                   | 14 ++++++--------
 clang/lib/Basic/Targets/AArch64.cpp            |  4 ++--
 clang/lib/Basic/Targets/AArch64.h              |  3 ++-
 clang/lib/Basic/Targets/CSKY.cpp               |  3 ++-
 clang/lib/Basic/Targets/CSKY.h                 |  2 +-
 clang/lib/Basic/Targets/NVPTX.cpp              |  2 +-
 clang/lib/Basic/Targets/SPIR.h                 |  2 +-
 clang/lib/Basic/Targets/SystemZ.cpp            |  7 ++++---
 clang/lib/Basic/Targets/SystemZ.h              |  2 +-
 clang/lib/CodeGen/CodeGenModule.cpp            |  4 ++--
 clang/lib/Sema/SemaOpenMP.cpp                  |  3 +--
 clang/test/CodeGen/SystemZ/unaligned-symbols.c |  8 ++++++++
 14 files changed, 37 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 9e60ca8fb2ea8c..2c42602bef5a6f 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2406,11 +2406,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   /// Return the alignment in bits that should be given to a
   /// global variable with type \p T.
-  unsigned getAlignOfGlobalVar(QualType T, bool HasDef) const;
+  unsigned getAlignOfGlobalVar(QualType T, const VarDecl *VD) const;
 
   /// Return the alignment in characters that should be given to a
   /// global variable with type \p T.
-  CharUnits getAlignOfGlobalVarInChars(QualType T, bool HasDef) const;
+  CharUnits getAlignOfGlobalVarInChars(QualType T, const VarDecl *VD) const;
 
   /// Return a conservative estimate of the alignment of the specified
   /// decl \p D.
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index ace9e89eda5869..5263c369c1c77b 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -50,6 +50,7 @@ class DiagnosticsEngine;
 class LangOptions;
 class CodeGenOptions;
 class MacroBuilder;
+class VarDecl;
 
 /// Contains information gathered from parsing the contents of TargetAttr.
 struct ParsedTargetAttr {
@@ -704,11 +705,9 @@ class TargetInfo : public TransferrableTargetInfo,
   }
 
   /// getMinGlobalAlign - Return the minimum alignment of a global variable,
-  /// unless its alignment is explicitly reduced via attributes. It may be
-  /// that an external symbol needs to be considered unaligned (like
-  /// artificial symbols created from a linker script). If \param HasDef is
-  /// false, this symbol does not have a definition and is external.
-  virtual unsigned getMinGlobalAlign(uint64_t Size, bool HasDef) const {
+  /// unless its alignment is explicitly reduced via attributes. If \param VD
+  /// is non-null, it may be used to examine the specific variable's attributes.
+  virtual unsigned getMinGlobalAlign(uint64_t Size, const VarDecl *VD) const {
     return MinGlobalAlign;
   }
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ff15206cbe8862..c7adbcdc302af4 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1681,8 +1681,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
       if (VD->hasGlobalStorage() && !ForAlignof) {
         uint64_t TypeSize =
             !BaseT->isIncompleteType() ? getTypeSize(T.getTypePtr()) : 0;
-        Align = std::max(Align, getTargetInfo().getMinGlobalAlign(
-                                    TypeSize, VD->hasDefinition()));
+        Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize, VD));
       }
 
     // Fields can be subject to extra alignment constraints, like if
@@ -2503,19 +2502,18 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const {
 }
 
 /// getAlignOfGlobalVar - Return the alignment in bits that should be given
-/// to a global variable of the specified type (see comment for
-/// getMinGlobalAlign about HasDef).
-unsigned ASTContext::getAlignOfGlobalVar(QualType T, bool HasDef) const {
+/// to a global variable of the specified type.
+unsigned ASTContext::getAlignOfGlobalVar(QualType T, const VarDecl *VD) const {
   uint64_t TypeSize = getTypeSize(T.getTypePtr());
   return std::max(getPreferredTypeAlign(T),
-                  getTargetInfo().getMinGlobalAlign(TypeSize, HasDef));
+                  getTargetInfo().getMinGlobalAlign(TypeSize, VD));
 }
 
 /// getAlignOfGlobalVarInChars - Return the alignment in characters that
 /// should be given to a global variable of the specified type.
 CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T,
-                                                 bool HasDef) const {
-  return toCharUnitsFromBits(getAlignOfGlobalVar(T, HasDef));
+                                                 const VarDecl *VD) const {
+  return toCharUnitsFromBits(getAlignOfGlobalVar(T, VD));
 }
 
 CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const {
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 7690f36c254499..465c2253535052 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -1518,8 +1518,8 @@ MicrosoftARM64TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
 }
 
 unsigned MicrosoftARM64TargetInfo::getMinGlobalAlign(uint64_t TypeSize,
-                                                     bool HasDef) const {
-  unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize, HasDef);
+                                                     const VarDecl *VD) const {
+  unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize, VD);
 
   // MSVC does size based alignment for arm64 based on alignment section in
   // below document, replicate that to keep alignment consistent with object
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 8cfc4281c44456..7ef01fd44a311a 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -236,7 +236,8 @@ class LLVM_LIBRARY_VISIBILITY MicrosoftARM64TargetInfo
   TargetInfo::CallingConvKind
   getCallingConvKind(bool ClangABICompat4) const override;
 
-  unsigned getMinGlobalAlign(uint64_t TypeSize, bool HasDef) const override;
+  unsigned getMinGlobalAlign(uint64_t TypeSize,
+                             const VarDecl *VD) const override;
 };
 
 // ARM64 MinGW target
diff --git a/clang/lib/Basic/Targets/CSKY.cpp b/clang/lib/Basic/Targets/CSKY.cpp
index e173fa1490cd72..e0c6d72a364433 100644
--- a/clang/lib/Basic/Targets/CSKY.cpp
+++ b/clang/lib/Basic/Targets/CSKY.cpp
@@ -308,7 +308,8 @@ bool CSKYTargetInfo::validateAsmConstraint(
   }
 }
 
-unsigned CSKYTargetInfo::getMinGlobalAlign(uint64_t Size, bool HasDef) const {
+unsigned CSKYTargetInfo::getMinGlobalAlign(uint64_t Size,
+                                           const VarDecl *VD) const {
   if (Size >= 32)
     return 32;
   return 0;
diff --git a/clang/lib/Basic/Targets/CSKY.h b/clang/lib/Basic/Targets/CSKY.h
index 33a7b7ac2b4c34..ad46eae6fc9de2 100644
--- a/clang/lib/Basic/Targets/CSKY.h
+++ b/clang/lib/Basic/Targets/CSKY.h
@@ -71,7 +71,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo {
 
   bool isValidCPUName(StringRef Name) const override;
 
-  unsigned getMinGlobalAlign(uint64_t, bool) const override;
+  unsigned getMinGlobalAlign(uint64_t, const VarDecl *) const override;
 
   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
 
diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp
index adf35bc00868d1..0806719ef3722e 100644
--- a/clang/lib/Basic/Targets/NVPTX.cpp
+++ b/clang/lib/Basic/Targets/NVPTX.cpp
@@ -116,7 +116,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
   LongLongWidth = HostTarget->getLongLongWidth();
   LongLongAlign = HostTarget->getLongLongAlign();
   MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,
-                                                 /* HasDef = */ true);
+                                                 /* VD = */ nullptr);
   NewAlign = HostTarget->getNewAlign();
   DefaultAlignForAttributeAligned =
       HostTarget->getDefaultAlignForAttributeAligned();
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index ff5563d8ecf449..5745ec860e5e7e 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -125,7 +125,7 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
       LongLongWidth = HostTarget->getLongLongWidth();
       LongLongAlign = HostTarget->getLongLongAlign();
       MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,
-                                                     /* HasDef = */ true);
+                                                     /* VD = */ nullptr);
       NewAlign = HostTarget->getNewAlign();
       DefaultAlignForAttributeAligned =
           HostTarget->getDefaultAlignForAttributeAligned();
diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index 76825c6d6a5429..578e026661c541 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SystemZ.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/MacroBuilder.h"
@@ -139,10 +140,10 @@ bool SystemZTargetInfo::hasFeature(StringRef Feature) const {
 }
 
 unsigned SystemZTargetInfo::getMinGlobalAlign(uint64_t Size,
-                                              bool HasDef) const {
-  // Don't enforce the minimum alignment on an external symbol if
+                                              const VarDecl *VD) const {
+  // Don't enforce the minimum alignment on an external or weak symbol if
   // -munaligned-symbols is passed.
-  if (UnalignedSymbols && !HasDef)
+  if (UnalignedSymbols && VD && (!VD->hasDefinition() || VD->isWeak()))
     return 0;
 
   return MinGlobalAlign;
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index b25360cfbc1c96..f701a2370c074e 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -66,7 +66,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
     HasStrictFP = true;
   }
 
-  unsigned getMinGlobalAlign(uint64_t Size, bool HasDef) const override;
+  unsigned getMinGlobalAlign(uint64_t Size, const VarDecl *VD) const override;
 
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 74bd6a563f4c88..7605bae497bea0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6303,7 +6303,7 @@ ConstantAddress
 CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
                                                   StringRef Name) {
   CharUnits Alignment =
-      getContext().getAlignOfGlobalVarInChars(S->getType(), /*HasDef=*/true);
+      getContext().getAlignOfGlobalVarInChars(S->getType(), /*VD=*/nullptr);
 
   llvm::Constant *C = GetConstantArrayFromStringLiteral(S);
   llvm::GlobalVariable **Entry = nullptr;
@@ -6367,7 +6367,7 @@ ConstantAddress CodeGenModule::GetAddrOfConstantCString(
     const std::string &Str, const char *GlobalName) {
   StringRef StrWithNull(Str.c_str(), Str.size() + 1);
   CharUnits Alignment = getContext().getAlignOfGlobalVarInChars(
-      getContext().CharTy, /*HasDef=*/true);
+      getContext().CharTy, /*VD=*/nullptr);
 
   llvm::Constant *C =
       llvm::ConstantDataArray::getString(getLLVMContext(), StrWithNull, false);
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index b167762561019f..40fa7b74a178a2 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2293,10 +2293,9 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
   // and alignment, because the runtime library only deals with uintptr types.
   // If it does not fit the uintptr size, we need to pass the data by reference
   // instead.
-  bool IsExtern = isa<VarDecl>(D) && !cast<VarDecl>(D)->hasDefinition();
   if (!IsByRef && (Ctx.getTypeSizeInChars(Ty) >
                        Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) ||
-                   Ctx.getAlignOfGlobalVarInChars(Ty, /*HasDef=*/!IsExtern) >
+                   Ctx.getAlignOfGlobalVarInChars(Ty, dyn_cast<VarDecl>(D)) >
                        Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) {
     IsByRef = true;
   }
diff --git a/clang/test/CodeGen/SystemZ/unaligned-symbols.c b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
index 0906d1b67dae99..4ed2a1b739b223 100644
--- a/clang/test/CodeGen/SystemZ/unaligned-symbols.c
+++ b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
@@ -102,3 +102,11 @@ unsigned char foo6 () {
   return ExtUnAl_s_nested[0].a[0].c[0] + ExtExplAlign_s_nested[0].a[0].c[0] +
          Aligned_s_nested[0].a[0].c[0];
 }
+
+// A weak symbol could be replaced with an unaligned one at link time.
+// CHECK-LABEL: foo7
+// CHECK-NOT: larl {{.*}}Weaksym
+unsigned char __attribute__((weak)) Weaksym = 0;
+unsigned char foo7 () {
+  return Weaksym;
+}

>From 94ac7f22f74f2495bf0dc43d457eb4f2a7676c2e Mon Sep 17 00:00:00 2001
From: Jonas Paulsson <paulson1 at linux.ibm.com>
Date: Tue, 19 Dec 2023 14:05:32 -0600
Subject: [PATCH 3/4] Fix test for -emit-llvm

---
 clang/test/CodeGen/SystemZ/unaligned-symbols.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGen/SystemZ/unaligned-symbols.c b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
index 4ed2a1b739b223..193e092b99c2b5 100644
--- a/clang/test/CodeGen/SystemZ/unaligned-symbols.c
+++ b/clang/test/CodeGen/SystemZ/unaligned-symbols.c
@@ -105,7 +105,8 @@ unsigned char foo6 () {
 
 // A weak symbol could be replaced with an unaligned one at link time.
 // CHECK-LABEL: foo7
-// CHECK-NOT: larl {{.*}}Weaksym
+// ALIGNED: %0 = load i8, ptr @Weaksym, align 2
+// UNALIGN: %0 = load i8, ptr @Weaksym, align 1
 unsigned char __attribute__((weak)) Weaksym = 0;
 unsigned char foo7 () {
   return Weaksym;

>From abf9110194d14bb6830c488bc57ec2b27b05085f Mon Sep 17 00:00:00 2001
From: Jonas Paulsson <paulson1 at linux.ibm.com>
Date: Tue, 19 Dec 2023 14:10:35 -0600
Subject: [PATCH 4/4] clang-format

---
 clang/lib/AST/ASTContext.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c7adbcdc302af4..06739eb9ff24fa 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1681,7 +1681,8 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
       if (VD->hasGlobalStorage() && !ForAlignof) {
         uint64_t TypeSize =
             !BaseT->isIncompleteType() ? getTypeSize(T.getTypePtr()) : 0;
-        Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize, VD));
+        Align =
+            std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize, VD));
       }
 
     // Fields can be subject to extra alignment constraints, like if



More information about the cfe-commits mailing list