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

Jonas Paulsson via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 27 05:20:30 PST 2023


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

External symbols created from a linker script may not get the ABI minimum alignment and must therefore be treated as unaligned by the compiler.

To implement this, getMinGlobalAlign() (and getAlignOfGlobalVar) gets a second parameter 'HasDef', which lets SystemZTargetInfo::getMinGlobalAlign() handle this.

My first idea was to pass a VarDecl to getMinGlobalAlign(), and assume the value to be external only in cases of (VD && !VD->hasDefiniton()). I got however link problems with 'ninja check', so opted to pass a boolean 'HasDef' instead. In SemaOpenMP.cpp the check with VD was added, and in CodeGenModule.cpp 'true' is
passed for strings (which I am hoping is correct as the strings seem to be passed to the functions which makes it look like they are being created for the module...)

The assumption generally would then be that everything is generated for the module except for a VarDecl that returns false in hasDefinition().

This is controlled by a new CL option '-munaligned-symbols', where I looked at -munaligned-access (e.g. RISCVTargetInfo::handleTargetFeatures() / FastUnalignedAccess).

SystemZ:

- Test: I reused Andreas' test for GCC and also added cases of char arrays and structs, but not sure if those are relevant/needed after all as they just worked without any extra handling...

- The backend seems to emit a GOT lookup also for the external and aligned cases - I suppose this is because the linker will fixup those...

>From c2f300a46eea861fac1a7f253e5f2998eb6740cd 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] 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 3e46a5da3fc043f..9e60ca8fb2ea8c6 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 41f3c2e403cbef6..1a536b3448df162 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -705,8 +705,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 b2f2bcb6ac37910..1ad01c2307c3079 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4544,6 +4544,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 a7cee3b7ba2b0db..849a32b21ef9de1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1687,7 +1687,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
@@ -2508,17 +2509,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 c31f2e0bee54393..e1c4b60086ad0a1 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -1516,8 +1516,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 f0e0782e7abe973..8cfc4281c44456e 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 851f27dbb1e5eed..e173fa1490cd724 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 11404e37db368a6..33a7b7ac2b4c345 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 a9fc88295700b89..2b873045243de7e 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 9ab2b7c60936392..ff5563d8ecf4495 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 a9b5ca483861332..76825c6d6a5429b 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 9ba255745cf2cc5..e884ebe024842f9 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 7cdf50a281cd278..38ddbe16462ac22 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6205,7 +6205,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;
@@ -6268,8 +6269,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 588bc3176d73e38..2213f431eb81145 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 dcdd6e7a3f5c762..366354deb23d31b 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 000000000000000..0906d1b67dae999
--- /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 fdd94206421a418..a1e2a92b40ac232 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



More information about the cfe-commits mailing list