Skip to content

[SystemZ][z/OS] __ptr32 support for z/OS in Clang #96063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

fanbo-meng
Copy link
Contributor

Enabling __ptr32 keyword to support in Clang for z/OS. It is represented by addrspace(1) in LLVM IR. Unlike existing implementation, __ptr32 is not mangled into symbol names for z/OS.

Enabling __ptr32 support for z/OS in Clang.
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:SystemZ clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2024

@llvm/pr-subscribers-backend-systemz

@llvm/pr-subscribers-clang

Author: Fanbo Meng (fanbo-meng)

Changes

Enabling __ptr32 keyword to support in Clang for z/OS. It is represented by addrspace(1) in LLVM IR. Unlike existing implementation, __ptr32 is not mangled into symbol names for z/OS.


Patch is 35.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96063.diff

17 Files Affected:

  • (modified) clang/include/clang/Basic/LangOptions.def (+1)
  • (modified) clang/include/clang/Basic/TokenKinds.def (+2-1)
  • (modified) clang/include/clang/Driver/Options.td (+4)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+7-1)
  • (modified) clang/lib/Basic/IdentifierTable.cpp (+12-4)
  • (modified) clang/lib/Basic/Targets/SystemZ.h (+42-1)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+11)
  • (modified) clang/lib/Sema/SemaType.cpp (+8-3)
  • (modified) clang/test/CodeGen/target-data.c (+1-1)
  • (added) clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c (+53)
  • (added) clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c (+84)
  • (added) clang/test/CodeGen/zos-mixed-ptr-sizes-sizeof.c (+94)
  • (added) clang/test/CodeGen/zos-mixed-ptr-sizes.c (+298)
  • (added) clang/test/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp (+17)
  • (added) clang/test/Sema/ZOSExtensions.cpp (+119)
  • (added) clang/test/Sema/attr-print-zos.c (+31)
  • (modified) llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp (+8)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 2dea3cd4d795b..9f303b2f549bf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -90,6 +90,7 @@ LANGOPT(C23               , 1, 0, "C23")
 LANGOPT(MSVCCompat        , 1, 0, "Microsoft Visual C++ full compatibility mode")
 LANGOPT(Kernel            , 1, 0, "Kernel mode")
 LANGOPT(MicrosoftExt      , 1, 0, "Microsoft C++ extensions")
+LANGOPT(ZOSExt            , 1, 0, "z/OS extensions")
 LANGOPT(AsmBlocks         , 1, 0, "Microsoft inline asm blocks")
 LANGOPT(Borland           , 1, 0, "Borland extensions")
 LANGOPT(CPlusPlus         , 1, 0, "C++")
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 9c4b17465e18a..9717ecd6d7d66 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -286,6 +286,7 @@ PUNCTUATOR(caretcaret,            "^^")
 //   CHAR8SUPPORT - This is a keyword if 'char8_t' is a built-in type
 //   KEYFIXEDPOINT - This is a keyword according to the N1169 fixed point
 //                   extension.
+//   KEYZOS - This is a keyword in C/C++ on z/OS
 //
 KEYWORD(auto                        , KEYALL)
 KEYWORD(break                       , KEYALL)
@@ -708,7 +709,7 @@ KEYWORD(__funcref                     , KEYALL)
 
 // Microsoft extensions which should be disabled in strict conformance mode
 KEYWORD(__ptr64                       , KEYMS)
-KEYWORD(__ptr32                       , KEYMS)
+KEYWORD(__ptr32                       , KEYMS | KEYZOS)
 KEYWORD(__sptr                        , KEYMS)
 KEYWORD(__uptr                        , KEYMS)
 KEYWORD(__w64                         , KEYMS)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d44faa55c456f..e0ae29f881d9e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3038,6 +3038,10 @@ dll version.}]>;
 def fms_omit_default_lib : Joined<["-"], "fms-omit-default-lib">,
   Group<f_Group>, Flags<[]>,
   Visibility<[ClangOption, CLOption]>;
+def fzos_extensions : Flag<["-"], "fzos-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Accept some non-standard constructs supported by the z/OS compiler">;
+def fno_zos_extensions : Flag<["-"], "fno-zos-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Do not accept non-standard constructs supported by the z/OS compiler">;
 defm delayed_template_parsing : BoolFOption<"delayed-template-parsing",
   LangOpts<"DelayedTemplateParsing">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index ed9e6eeb36c75..8c0bc9474dbc0 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2728,6 +2728,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
     //   <type> ::= U <OpenCL-addrspace>
     //   <type> ::= U <CUDA-addrspace>
 
+    llvm::Triple Triple = getASTContext().getTargetInfo().getTriple();
+
     SmallString<64> ASString;
     LangAS AS = Quals.getAddressSpace();
 
@@ -2796,7 +2798,11 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
         ASString = "ptr32_sptr";
         break;
       case LangAS::ptr32_uptr:
-        ASString = "ptr32_uptr";
+        // For z/OS, there are no special mangling rules applied to the ptr32
+        // qualifier. Ex: void foo(int * __ptr32 p) -> _Z3f2Pi. The mangling for
+        // "p" is treated the same as a regular integer pointer.
+        if (!Triple.isOSzOS())
+          ASString = "ptr32_uptr";
         break;
       case LangAS::ptr64:
         ASString = "ptr64";
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index feea84544d62f..ac7409c9b587b 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -107,12 +107,14 @@ namespace {
     KEYMSCOMPAT   = 0x400000,
     KEYSYCL       = 0x800000,
     KEYCUDA       = 0x1000000,
-    KEYHLSL       = 0x2000000,
-    KEYFIXEDPOINT = 0x4000000,
+    KEYZOS        = 0x2000000,
+    KEYNOZOS      = 0x4000000,
+    KEYHLSL       = 0x8000000,
+    KEYFIXEDPOINT = 0x10000000,
     KEYMAX        = KEYFIXEDPOINT, // The maximum key
     KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
-    KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
-             ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
+    KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
+             ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are used to exclude.
   };
 
   /// How a keyword is treated in the selected standard. This enum is ordered
@@ -199,6 +201,8 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
     return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
   case KEYCUDA:
     return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
+  case KEYZOS:
+    return LangOpts.ZOSExt ? KS_Enabled : KS_Unknown;
   case KEYHLSL:
     return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
   case KEYNOCXX:
@@ -211,6 +215,9 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
   case KEYNOMS18:
     // The disable behavior for this is handled in getKeywordStatus.
     return KS_Unknown;
+  case KEYNOZOS:
+    // The disable behavior for this is handled in getKeywordStatus.
+    return KS_Unknown;
   case KEYFIXEDPOINT:
     return LangOpts.FixedPoint ? KS_Enabled : KS_Disabled;
   default:
@@ -230,6 +237,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
   if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
       !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
     return KS_Disabled;
+  if (LangOpts.ZOSExt && (Flags & KEYNOZOS)) return KS_Disabled;
 
   KeywordStatus CurStatus = KS_Unknown;
 
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 3bc6f2c1d3083..5f4f93cbfa48e 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -21,6 +21,30 @@
 namespace clang {
 namespace targets {
 
+static const unsigned ZOSAddressMap[] = {
+    0, // Default
+    0, // opencl_global
+    0, // opencl_local
+    0, // opencl_constant
+    0, // opencl_private
+    0, // opencl_generic
+    0, // opencl_global_device
+    0, // opencl_global_host
+    0, // cuda_device
+    0, // cuda_constant
+    0, // cuda_shared
+    0, // sycl_global
+    0, // sycl_global_device
+    0, // sycl_global_host
+    0, // sycl_local
+    0, // sycl_private
+    0, // ptr32_sptr
+    1, // ptr32_uptr
+    0, // ptr64
+    0, // hlsl_groupshared
+    0  // wasm_funcref
+};
+
 class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
 
   static const char *const GCCRegNames[];
@@ -30,6 +54,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
   bool HasVector;
   bool SoftFloat;
   bool UnalignedSymbols;
+  enum AddrSpace { ptr32 = 1 };
 
 public:
   SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -49,6 +74,9 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
     MinGlobalAlign = 16;
     HasUnalignedAccess = true;
     if (Triple.isOSzOS()) {
+      if (Triple.isArch64Bit()) {
+        AddrSpaceMap = &ZOSAddressMap;
+      }
       TLSSupported = false;
       // All vector types are default aligned on an 8-byte boundary, even if the
       // vector facility is not available. That is different from Linux.
@@ -56,7 +84,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
       // Compared to Linux/ELF, the data layout differs only in some details:
       // - name mangling is GOFF.
       // - 32 bit pointers, either as default or special address space
-      resetDataLayout("E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-"
+      resetDataLayout("E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-"
                       "a:8:16-n32:64");
     } else {
       TLSSupported = true;
@@ -224,6 +252,19 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
   std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
     return std::make_pair(256, 256);
   }
+
+  uint64_t getPointerWidthV(LangAS AddrSpace) const override {
+    unsigned TargetAddrSpace = getTargetAddressSpace(AddrSpace);
+    return (TargetAddrSpace == ptr32 && getTriple().isOSzOS() &&
+            getTriple().isArch64Bit())
+               ? 32
+               : PointerWidth;
+  }
+
+  uint64_t getPointerAlignV(LangAS AddrSpace) const override {
+    return getPointerWidthV(AddrSpace);
+  }
+
 };
 } // namespace targets
 } // namespace clang
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 58694e5399d58..ef982214eba61 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3567,6 +3567,14 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
       GenerateArg(Consumer, OPT_ftrigraphs);
   }
 
+  if (T.isOSzOS()) {
+    if (!Opts.ZOSExt)
+      GenerateArg(Consumer, OPT_fno_zos_extensions);
+  } else {
+    if (Opts.ZOSExt)
+      GenerateArg(Consumer, OPT_fzos_extensions);
+  }
+
   if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
     GenerateArg(Consumer, OPT_fblocks);
 
@@ -3968,6 +3976,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
   Opts.Trigraphs =
       Args.hasFlag(OPT_ftrigraphs, OPT_fno_trigraphs, Opts.Trigraphs);
 
+  Opts.ZOSExt =
+      Args.hasFlag(OPT_fzos_extensions, OPT_fno_zos_extensions, T.isOSzOS());
+
   Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL
     && Opts.OpenCLVersion == 200);
 
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 441fdcca0758f..346139042d114 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7089,6 +7089,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
 
   // Add address space to type based on its attributes.
   LangAS ASIdx = LangAS::Default;
+  llvm::Triple Triple = S.Context.getTargetInfo().getTriple();
   uint64_t PtrWidth =
       S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
   if (PtrWidth == 32) {
@@ -7097,10 +7098,14 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
     else if (Attrs[attr::UPtr])
       ASIdx = LangAS::ptr32_uptr;
   } else if (PtrWidth == 64 && Attrs[attr::Ptr32]) {
-    if (Attrs[attr::UPtr])
+    if (Triple.isOSzOS()) {
       ASIdx = LangAS::ptr32_uptr;
-    else
-      ASIdx = LangAS::ptr32_sptr;
+    } else {
+      if (Attrs[attr::UPtr])
+        ASIdx = LangAS::ptr32_uptr;
+      else
+        ASIdx = LangAS::ptr32_sptr;
+    }
   }
 
   QualType Pointee = Type->getPointeeType();
diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c
index 7f7005d21b99a..d487584521e78 100644
--- a/clang/test/CodeGen/target-data.c
+++ b/clang/test/CodeGen/target-data.c
@@ -235,7 +235,7 @@
 // RUN: FileCheck %s -check-prefix=ZOS
 // RUN: %clang_cc1 -triple s390x-none-zos -target-cpu z13 -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=ZOS
-// ZOS: target datalayout = "E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
+// ZOS: target datalayout = "E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
 
 // RUN: %clang_cc1 -triple msp430-unknown -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=MSP430
diff --git a/clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c b/clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c
new file mode 100644
index 0000000000000..887ce1ddfe931
--- /dev/null
+++ b/clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos -fzos-extensions -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-ZOS
+// RUN: %clang_cc1 -triple s390x-ibm-linux -fzos-extensions -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-LINUX
+// RUN: %clang_cc1 -triple s390x-linux-gnu -fzos-extensions -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-LINUX
+
+void ptr32_declarations() {
+  // PTR32-ZOS-LABEL: @ptr32_declarations()
+  // PTR32-LINUX-LABEL: @ptr32_declarations()
+
+  // PTR32-ZOS: %p1 = alloca ptr addrspace(1), align 4
+  // PTR32-LINUX-NOT: %p1 = alloca i8 addrspace(1)*, align 4
+  // PTR32-LINUX: %p1 = alloca ptr, align 8
+  char * __ptr32 p1;
+
+  // PTR32-ZOS: %p2 = alloca ptr, align 8
+  // PTR32-LINUX-NOT: %p2 = alloca ptr addrspace(1), align 8
+  // PTR32-LINUX: %p2 = alloca ptr, align 8
+  char * __ptr32 *p2;
+
+  // PTR32-ZOS: %p3 = alloca ptr addrspace(1), align 4
+  // PTR32-LINUX-NOT: %p3 = alloca i8* addrspace(1)*, align 4
+  // PTR32-LINUX: %p3 = alloca ptr, align 8
+  char ** __ptr32 p3;
+
+  // PTR32-ZOS: %p4 = alloca ptr, align 8
+  // PTR32-LINUX-NOT: %p4 = alloca ptr addrspace(1), align 8
+  // PTR32-LINUX: %p4 = alloca ptr, align 8
+  char ** __ptr32 *p4;
+
+  // PTR32-ZOS: %p5 = alloca ptr, align 8
+  // PTR32-LINUX-NOT:  %p5 = alloca ptr addrspace(1), align 8
+  // PTR32-LINUX: %p5 = alloca ptr, align 8
+  char *** __ptr32 *p5;
+
+  // PTR32-ZOS: %p6 = alloca ptr, align 8
+  // PTR32-LINUX: %p6 = alloca ptr, align 8
+  char **p6;
+
+  // PTR32-ZOS: %p7 = alloca ptr addrspace(1), align 4
+  // PTR32-LINUX-NOT: %p7 = alloca i8 addrspace(1)* addrspace(1)*, align 4
+  // PTR32-LINUX: %p7 = alloca ptr, align 8
+  char * __ptr32 * __ptr32 p7;
+
+  // PTR32-ZOS: %p8 = alloca ptr addrspace(1), align 4
+  // PTR32-LINUX-NOT: %p8 = alloca i8* addrspace(1)* addrspace(1)*, align 4
+  // PTR32-LINUX: %p8 = alloca ptr, align 8
+  char ** __ptr32 * __ptr32 p8;
+
+  // PTR32-ZOS: %p9 = alloca ptr, align 8
+  // PTR32-LINUX-NOT: %p9 = alloca i8* addrspace(1)* addrspace(1)**, align 8
+  // PTR32-LINUX: %p9 = alloca ptr, align 8
+  char ** __ptr32 * __ptr32 *p9;
+
+}
diff --git a/clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c b/clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c
new file mode 100644
index 0000000000000..1018c113ceea0
--- /dev/null
+++ b/clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos -fzos-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefix=X64
+#include <stddef.h>
+void *__malloc31(size_t);
+
+int test_1() {
+  // X64-LABEL: define {{.*}} i32 @test_1()
+  // X64: ret i32 135
+  int *__ptr32 a;
+  int *b;
+  int i;
+  int sum1, sum2, sum3;
+
+  a = (int *__ptr32)__malloc31(sizeof(int) * 10);
+
+  b = a;
+  sum1 = 0;
+  for (i = 0; i < 10; ++i) {
+    a[i] = i;
+    sum1 += i;
+  }
+
+  sum2 = 0;
+  for (i = 0; i < 10; ++i) {
+    sum2 += a[i];
+  }
+  sum3 = 0;
+  for (i = 0; i < 10; ++i) {
+    sum3 += b[i];
+  }
+
+  return (sum1 + sum2 + sum3);
+}
+
+int test_2() {
+  // X64-LABEL: define {{.*}} i32 @test_2()
+  // X64: ret i32 4
+  int *a = (int *)__malloc31(sizeof(int));
+  int *__ptr32 b;
+
+  *a = 99;
+  b = a;
+  *b = 44;
+
+  // Test should return 4
+  return (*b - 40);
+}
+
+int test_3() {
+  // X64-LABEL: define {{.*}} i32 @test_3()
+  // X64: ret i32 4
+  int *a = (int *)__malloc31(sizeof(int));
+  int *__ptr32 b;
+
+  *a = 99;
+  b = a;
+
+  // Test should return 4
+  return (*b - 95);
+}
+
+int test_4() {
+  // X64-LABEL: define {{.*}} i32 @test_4()
+  // X64: ret i32 1
+  int *a = (int *)__malloc31(sizeof(int));
+  float *d = (float *)__malloc31(sizeof(float));
+
+  int *__ptr32 b;
+  int *c;
+
+  float *__ptr32 e;
+  float *f;
+
+  *a = 0;
+  *d = 0.0;
+
+  b = a;
+  c = a;
+  e = d;
+  f = d;
+
+  // Test should return 1
+  return (b == c && e == f);
+}
+
diff --git a/clang/test/CodeGen/zos-mixed-ptr-sizes-sizeof.c b/clang/test/CodeGen/zos-mixed-ptr-sizes-sizeof.c
new file mode 100644
index 0000000000000..6b434a926f706
--- /dev/null
+++ b/clang/test/CodeGen/zos-mixed-ptr-sizes-sizeof.c
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -emit-llvm -triple s390x-ibm-zos -fzos-extensions -fdump-record-layouts < %s | FileCheck %s --check-prefix=PTR32-ZOS
+// RUN: %clang_cc1 -emit-llvm -triple s390x-ibm-linux -fzos-extensions -fdump-record-layouts < %s | FileCheck %s --check-prefix=PTR32-LINUX
+// RUN: %clang_cc1 -emit-llvm -triple s390x-linux-gnu -fzos-extensions -fdump-record-layouts < %s | FileCheck %s --check-prefix=PTR32-LINUX
+
+// PTR32-ZOS:          0  | struct s1
+// PTR32-ZOS-NEXT:     0  | long a
+// PTR32-ZOS-NEXT:     8  | int b
+// PTR32-ZOS-NEXT:     12 | int * __ptr32 c
+// PTR32-ZOS-NEXT:     16 | int d
+// PTR32-ZOS-NEXT:        | [sizeof=24, align=8]
+
+// PTR32-LINUX:        0  | struct s1
+// PTR32-LINUX-NEXT:   0  | long a
+// PTR32-LINUX-NEXT:   8  | int b
+// PTR32-LINUX-NEXT:   16 | int * __ptr32 c
+// PTR32-LINUX-NEXT:   24 | int d
+// PTR32-LINUX-NEXT:      | [sizeof=32, align=8]
+struct s1 {
+  long a;
+  int b;
+  int * __ptr32 c;
+  int d;
+} S1;
+
+// PTR32-ZOS:          0  | struct s2
+// PTR32-ZOS-NEXT:     0  | long a
+// PTR32-ZOS-NEXT:     8  | int b
+// PTR32-ZOS-NEXT:     16 | int * c
+// PTR32-ZOS-NEXT:     24 | int d
+// PTR32-ZOS-NEXT:        | [sizeof=32, align=8]
+
+// PTR32-LINUX:        0  | struct s2
+// PTR32-LINUX-NEXT:   0  | long a
+// PTR32-LINUX-NEXT:   8  | int b
+// PTR32-LINUX-NEXT:   16 | int * c
+// PTR32-LINUX-NEXT:   24 | int d
+// PTR32-LINUX-NEXT:      | [sizeof=32, align=8]
+struct s2 {
+  long a;
+  int b;
+  int *c;
+  int d;
+} S2;
+
+// PTR32-ZOS:          0  | struct s3
+// PTR32-ZOS-NEXT:     0  | int a
+// PTR32-ZOS-NEXT:     4  | int * __ptr32 b
+// PTR32-ZOS-NEXT:     8  | int * __ptr32 c
+// PTR32-ZOS-NEXT:     12 | int * d
+// PTR32-ZOS-NEXT:        | [sizeof=20, align=1]
+
+struct __attribute__((packed)) s3 {
+  int a;
+  int *__ptr32 b;
+  int *__ptr32 c;
+  int *d;
+};
+struct s3 S3;
+
+// PTR32-ZOS:          0 | union u1
+// PTR32-ZOS-NEXT:     0 | int * __ptr32 a
+// PTR32-ZOS-NEXT:     0 | int * b
+// PTR32-ZOS-NEXT:       | [sizeof=8, align=8]
+
+// PTR32-LINUX:        0 | union u1
+// PTR32-LINUX-NEXT:   0 | int * __ptr32 a
+// PTR32-LINUX-NEXT:   0 | int * b
+// PTR32-LINUX-NEXT:     | [sizeof=8, align=8]
+union u1 {
+  int *__ptr32 a;
+  int *b;
+} U1;
+
+// PTR32-ZOS:          0 | union u2
+// PTR32-ZOS-NEXT:     0 | int * __ptr32 a
+// PTR32-ZOS-NEXT:     0 | int * b
+// PTR32-ZOS-NEXT:       | [sizeof=8, align=1]
+
+union __attribute__((packed)) u2 {
+  int *__ptr32 a;
+  int *b;
+};
+union u2 U2;
+
+// PTR32-ZOS:          0 | union u3
+// PTR32-ZOS-NEXT:     0 | int * __ptr32 a
+// PTR32-ZOS-NEXT:     0 | short b
+// PTR32-ZOS-NEXT:       | [sizeof=4, align=1]
+
+union __attribute__((packed)) u3 {
+  int *__ptr32 a;
+  short b;
+};
+union u3 U3;
diff --git a/clang/test/CodeGen/zos-mixed-ptr-sizes.c b/clang/test/CodeGen/zos-mixed-ptr-sizes.c
new file mode 100644
index 0000000000000..24bd75284ebc4
--- /dev/null
+++ b/clang/test/CodeGen/zos-mixed-ptr-sizes.c
@@ -0,0 +1,298 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos -fzos-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefix=X64
+
+#define PSA_PTR 0x00
+#define PSAAOLD 0x224
+
+struct Foo {
+  int * __ptr32 p32;
+  int *p64;
+  char *cp64;
+};
+
+void use_foo(struct Foo *f);
+
+void ptr32_to_ptr(struct Foo *f, int * __ptr32 i) {
+  // X64-LABEL: define void @ptr32_to_ptr(ptr noundef %f, ptr addrspace(1) noundef %i)
+  // X64: %{{.+}} = addrspacecast ptr addrspace(1) %i to ptr
+  f->p64= i;
+  use_foo(f);
+}
+
+void ptr_to_ptr32(struct Foo *f, int *i) {
+  // X64-LABEL: define void @ptr_to_ptr32(ptr noundef %f, ptr noundef %i)
+  // X64: %{{.+}} = addrspacecast ptr %i to ptr addrspace(1)
+  f->p32 = i;
+  use_foo(f);
+}
+
+void ptr32_to_ptr32(struct Foo *f, int * __ptr32 i) {
+  // X64-LABEL: define void @ptr32_to_ptr32(ptr noundef %f, ptr addrspace(1) noundef %i)
+  // X64-NOT: addrspacecast
+  f->p32 = i;
+  use_foo(f);
+}
+
+void ptr_to_ptr32_explicit_cast(struct Foo *f, int *i) {
+  // X64-LABEL: define void @ptr_to_ptr32_explicit_cast(ptr noundef %f, ptr noundef %i)
+  // X64: %{{.+}} = addrspacecast ptr %i to ptr addrspace(1)
+  f->p32 = (int * __ptr32)i;
+  use_foo(f);
+}
+
+void test_indexing(struct Foo *f) {
+  // X64-LABEL: define void @test_indexing(ptr noundef %f)
+  // X64: addrspacecast ptr addrspace(1) {{%[0-9]}} to ptr
+  f->cp64 = ((char * __ptr32 *)1028)[1];
+  use_foo(f);
+}
+
+void test_indexing_2(struct Foo *f) {
+  // X64...
[truncated]

Copy link

github-actions bot commented Jun 19, 2024

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 0c97ac0a46d0c29fbe5168adcd32e1f25336096d 994729c4576e98744477cf5654c5f7ca651363cc --extensions 'c,cpp,h' -- clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c clang/test/CodeGen/zos-mixed-ptr-sizes-sizeof.c clang/test/CodeGen/zos-mixed-ptr-sizes.c clang/test/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp clang/test/Sema/ZOSExtensions.cpp clang/test/Sema/attr-print-zos.c clang/lib/AST/ItaniumMangle.cpp clang/lib/Basic/IdentifierTable.cpp clang/lib/Basic/Targets/SystemZ.h clang/lib/Frontend/CompilerInvocation.cpp clang/lib/Sema/SemaType.cpp clang/test/CodeGen/target-data.c llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
View the diff from clang-format here.
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 3d72e36741..735aac0504 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -81,51 +81,51 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
 // Constants for TokenKinds.def
 namespace {
 
-  enum TokenKey : unsigned {
-    KEYC99        = 0x1,
-    KEYCXX        = 0x2,
-    KEYCXX11      = 0x4,
-    KEYGNU        = 0x8,
-    KEYMS         = 0x10,
-    BOOLSUPPORT   = 0x20,
-    KEYALTIVEC    = 0x40,
-    KEYNOCXX      = 0x80,
-    KEYBORLAND    = 0x100,
-    KEYOPENCLC    = 0x200,
-    KEYC23        = 0x400,
-    KEYNOMS18     = 0x800,
-    KEYNOOPENCL   = 0x1000,
-    WCHARSUPPORT  = 0x2000,
-    HALFSUPPORT   = 0x4000,
-    CHAR8SUPPORT  = 0x8000,
-    KEYOBJC       = 0x10000,
-    KEYZVECTOR    = 0x20000,
-    KEYCOROUTINES = 0x40000,
-    KEYMODULES    = 0x80000,
-    KEYCXX20      = 0x100000,
-    KEYOPENCLCXX  = 0x200000,
-    KEYMSCOMPAT   = 0x400000,
-    KEYSYCL       = 0x800000,
-    KEYCUDA       = 0x1000000,
-    KEYZOS        = 0x2000000,
-    KEYNOZOS      = 0x4000000,
-    KEYHLSL       = 0x8000000,
-    KEYFIXEDPOINT = 0x10000000,
-    KEYMAX        = KEYFIXEDPOINT, // The maximum key
-    KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
-    KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
-             ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are used to exclude.
-  };
-
-  /// How a keyword is treated in the selected standard. This enum is ordered
-  /// intentionally so that the value that 'wins' is the most 'permissive'.
-  enum KeywordStatus {
-    KS_Unknown,     // Not yet calculated. Used when figuring out the status.
-    KS_Disabled,    // Disabled
-    KS_Future,      // Is a keyword in future standard
-    KS_Extension,   // Is an extension
-    KS_Enabled,     // Enabled
-  };
+enum TokenKey : unsigned {
+  KEYC99 = 0x1,
+  KEYCXX = 0x2,
+  KEYCXX11 = 0x4,
+  KEYGNU = 0x8,
+  KEYMS = 0x10,
+  BOOLSUPPORT = 0x20,
+  KEYALTIVEC = 0x40,
+  KEYNOCXX = 0x80,
+  KEYBORLAND = 0x100,
+  KEYOPENCLC = 0x200,
+  KEYC23 = 0x400,
+  KEYNOMS18 = 0x800,
+  KEYNOOPENCL = 0x1000,
+  WCHARSUPPORT = 0x2000,
+  HALFSUPPORT = 0x4000,
+  CHAR8SUPPORT = 0x8000,
+  KEYOBJC = 0x10000,
+  KEYZVECTOR = 0x20000,
+  KEYCOROUTINES = 0x40000,
+  KEYMODULES = 0x80000,
+  KEYCXX20 = 0x100000,
+  KEYOPENCLCXX = 0x200000,
+  KEYMSCOMPAT = 0x400000,
+  KEYSYCL = 0x800000,
+  KEYCUDA = 0x1000000,
+  KEYZOS = 0x2000000,
+  KEYNOZOS = 0x4000000,
+  KEYHLSL = 0x8000000,
+  KEYFIXEDPOINT = 0x10000000,
+  KEYMAX = KEYFIXEDPOINT, // The maximum key
+  KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
+  KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
+           ~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are used to exclude.
+};
+
+/// How a keyword is treated in the selected standard. This enum is ordered
+/// intentionally so that the value that 'wins' is the most 'permissive'.
+enum KeywordStatus {
+  KS_Unknown,   // Not yet calculated. Used when figuring out the status.
+  KS_Disabled,  // Disabled
+  KS_Future,    // Is a keyword in future standard
+  KS_Extension, // Is an extension
+  KS_Enabled,   // Enabled
+};
 
 } // namespace
 

@fanbo-meng
Copy link
Contributor Author

code-formatter is complaining about the entire enum table. To be less pervasive, I'll not address that.

KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are used to exclude.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are used to exclude.
~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.

Comment on lines +257 to +259
unsigned TargetAddrSpace = getTargetAddressSpace(AddrSpace);
return (TargetAddrSpace == ptr32 && getTriple().isOSzOS() &&
getTriple().isArch64Bit())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unsigned TargetAddrSpace = getTargetAddressSpace(AddrSpace);
return (TargetAddrSpace == ptr32 && getTriple().isOSzOS() &&
getTriple().isArch64Bit())
return (getTriple().isOSzOS() && getTriple().isArch64Bit() &&
getTargetAddressSpace(AddrSpace) == ptr32)

@@ -3567,6 +3567,14 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_ftrigraphs);
}

if (T.isOSzOS()) {
if (!Opts.ZOSExt)
GenerateArg(Consumer, OPT_fno_zos_extensions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the default is -fno-zos-extensions, can you check why we need to explicitly pass this option?

Comment on lines +7101 to +7108
if (Triple.isOSzOS()) {
ASIdx = LangAS::ptr32_uptr;
else
ASIdx = LangAS::ptr32_sptr;
} else {
if (Attrs[attr::UPtr])
ASIdx = LangAS::ptr32_uptr;
else
ASIdx = LangAS::ptr32_sptr;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this block can be simplifed

Comment on lines +63 to +64
if (TT.isOSzOS()) {
if (TT.isArch64Bit()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can collapse these 2 if statements into one.

@@ -7097,10 +7098,14 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
else if (Attrs[attr::UPtr])
ASIdx = LangAS::ptr32_uptr;
} else if (PtrWidth == 64 && Attrs[attr::Ptr32]) {
if (Attrs[attr::UPtr])
if (Triple.isOSzOS()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (Triple.isOSzOS()) {
if (Attrs[attr::UPtr] || Triple.isOSzOS())
ASIdx = LangAS::ptr32_uptr;
else
ASIdx = LangAS::ptr32_sptr;

This is simpler.

@@ -0,0 +1,84 @@
// RUN: %clang_cc1 -triple s390x-ibm-zos -fzos-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefix=X64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this test need to be some complicated?

@fanbo-meng
Copy link
Contributor Author

Transferring this to @abhina-sree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:SystemZ clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants