[clang] [llvm] [SystemZ][z/OS] __ptr32 support for z/OS (PR #101696)

Abhina Sree via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 08:46:27 PDT 2024


https://github.com/abhina-sree updated https://github.com/llvm/llvm-project/pull/101696

>From 0246fe8e7f8d93ad3e37ff770a18bd1928552b5f Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Fri, 2 Aug 2024 11:44:44 -0400
Subject: [PATCH] __ptr32 support for z/OS

---
 clang/include/clang/Basic/LangOptions.def     |   1 +
 clang/include/clang/Basic/TokenKinds.def      |   3 +-
 clang/include/clang/Driver/Options.td         |   4 +
 clang/lib/AST/ItaniumMangle.cpp               |   8 +-
 clang/lib/Basic/IdentifierTable.cpp           |  18 +-
 clang/lib/Basic/Targets/SystemZ.h             |  40 ++-
 clang/lib/Frontend/CompilerInvocation.cpp     |  11 +
 clang/lib/Sema/SemaType.cpp                   |   3 +-
 .../SystemZ/zos-mixed-ptr-sizes-definitions.c |  54 ++++
 .../SystemZ/zos-mixed-ptr-sizes-malloc.c      |  84 +++++
 .../SystemZ/zos-mixed-ptr-sizes-sizeof.c      |  94 ++++++
 .../CodeGen/SystemZ/zos-mixed-ptr-sizes.c     | 298 ++++++++++++++++++
 clang/test/CodeGen/target-data.c              |   2 +-
 .../zos-mangle-ptr-size-address-space.cpp     |  17 +
 clang/test/Sema/ZOSExtensions.cpp             | 119 +++++++
 clang/test/Sema/attr-print-zos.c              |  31 ++
 .../Target/SystemZ/SystemZTargetMachine.cpp   |   8 +
 17 files changed, 785 insertions(+), 10 deletions(-)
 create mode 100644 clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-definitions.c
 create mode 100644 clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c
 create mode 100644 clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-sizeof.c
 create mode 100644 clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes.c
 create mode 100644 clang/test/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp
 create mode 100644 clang/test/Sema/ZOSExtensions.cpp
 create mode 100644 clang/test/Sema/attr-print-zos.c

diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 0035092ce0d863..c276c98d57db7b 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -91,6 +91,7 @@ LANGOPT(C2y               , 1, 0, "C2y")
 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 7e638dc1ddcdba..9cb8a34ac15575 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -292,6 +292,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)
@@ -722,7 +723,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 f690467bb82cd3..00b8f7c5635e2c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3065,6 +3065,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 ead5da4e90f2f0..65f30cd2b012b7 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2727,6 +2727,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();
 
@@ -2795,7 +2797,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 4f7ccaf4021d63..1ef07d41839c7a 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 excluded.
   };
 
   /// 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,7 +237,8 @@ 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;
 
   while (Flags != 0) {
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 3bc6f2c1d30832..7390f25d6efb1d 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,16 @@ 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 {
+    return (getTriple().isOSzOS() && getTriple().isArch64Bit() &&
+            getTargetAddressSpace(AddrSpace) == ptr32)
+               ? 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 f6b6c44a4cab6a..790a65942d6761 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3642,6 +3642,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);
 
@@ -4043,6 +4051,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 6fa39cdccef2b9..6ea87cc3425dc7 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7051,6 +7051,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) {
@@ -7059,7 +7060,7 @@ 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() || Attrs[attr::UPtr])
       ASIdx = LangAS::ptr32_uptr;
     else
       ASIdx = LangAS::ptr32_sptr;
diff --git a/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-definitions.c b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-definitions.c
new file mode 100644
index 00000000000000..8fac3ccc78e5a5
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-definitions.c
@@ -0,0 +1,54 @@
+
+// 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/SystemZ/zos-mixed-ptr-sizes-malloc.c b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c
new file mode 100644
index 00000000000000..1018c113ceea01
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/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/SystemZ/zos-mixed-ptr-sizes-sizeof.c b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-sizeof.c
new file mode 100644
index 00000000000000..6b434a926f706b
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/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/SystemZ/zos-mixed-ptr-sizes.c b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes.c
new file mode 100644
index 00000000000000..24bd75284ebc4c
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/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-LABEL: define void @test_indexing_2(ptr noundef %f)
+  // X64: getelementptr inbounds i8, ptr addrspace(1) {{%[0-9]}}, i32 16
+  // X64: getelementptr inbounds i8, ptr {{%[0-9]}}, i64 24
+  f->cp64 = ((char *** __ptr32 *)1028)[1][2][3];
+  use_foo(f);
+}
+
+unsigned long* test_misc() {
+  // X64-LABEL: define ptr @test_misc()
+  // X64: %arrayidx = getelementptr inbounds i8, ptr addrspace(1) %0, i32 88
+  // X64-NEXT: %1 = load ptr, ptr addrspace(1) %arrayidx
+  // X64-NEXT: %arrayidx1 = getelementptr inbounds i8, ptr %1, i64 8
+  // X64-NEXT: %2 = load ptr, ptr %arrayidx1
+  // X64-NEXT: %arrayidx2 = getelementptr inbounds i8, ptr %2, i64 904
+  // X64-NEXT: %3 = load ptr, ptr %arrayidx2
+  // X64-NEXT: %arrayidx3 = getelementptr inbounds i8, ptr %3, i64 1192
+  unsigned long* x = (unsigned long*)((char***** __ptr32*)1208)[0][11][1][113][149];
+  return x;
+}
+
+char* __ptr32* __ptr32 test_misc_2() {
+  // X64-LABEL: define ptr addrspace(1) @test_misc_2()
+  // X64: br i1 %cmp, label %if.then, label %if.end
+  // X64: %1 = load ptr addrspace(1), ptr inttoptr (i64 16 to ptr)
+  // X64-NEXT: %arrayidx = getelementptr inbounds i8, ptr addrspace(1) %1, i32 544
+  // X64-NEXT: %2 = load ptr addrspace(1), ptr addrspace(1) %arrayidx
+  // X64-NEXT: %arrayidx1 = getelementptr inbounds i8, ptr addrspace(1) %2, i32 24
+  // X64-NEXT: %3 = load ptr addrspace(1), ptr addrspace(1) %arrayidx1
+  // X64-NEXT: store ptr addrspace(1) %3, ptr @test_misc_2.res
+  // X64: ret ptr addrspace(1)
+  static char* __ptr32* __ptr32 res = 0;
+  if (res == 0) {
+    res = ((char* __ptr32* __ptr32* __ptr32* __ptr32*)0)[4][136][6];
+  }
+  return res;
+}
+
+unsigned short test_misc_3() {
+  // X64-LABEL: define zeroext i16 @test_misc_3()
+  // X64: %0 = load ptr addrspace(1), ptr inttoptr (i64 548 to ptr)
+  // X64-NEXT: %1 = addrspacecast ptr addrspace(1) %0 to ptr
+  // X64-NEXT: %arrayidx = getelementptr inbounds i8, ptr %1, i64 36
+  // X64-NEXT: %2 = load i16, ptr %arrayidx, align 2
+  // X64-NEXT: ret i16 %2
+  unsigned short this_asid = ((unsigned short*)(*(char* __ptr32*)(0x224)))[18];
+  return this_asid;
+}
+
+int test_misc_4() {
+  // X64-LABEL: define signext range(i32 0, 2) i32 @test_misc_4()
+  // X64: getelementptr inbounds i8, ptr addrspace(1) {{%[0-9]}}, i32 88
+  // X64: getelementptr inbounds i8, ptr {{%[0-9]}}, i64 8
+  // X64: getelementptr inbounds i8, ptr {{%[0-9]}}, i64 984
+  // X64: getelementptr inbounds i8, ptr %3, i64 80
+  // X64: icmp sgt i32 {{.*[0-9]}}, 67240703
+  // X64: ret i32
+  int a = (*(int*)(80 + ((char**** __ptr32*)1208)[0][11][1][123]) > 0x040202FF);
+  return a;
+}
+
+void test_misc_5(struct Foo *f) {
+  // X64-LABEL: define void @test_misc_5(ptr noundef %f)
+  // X64: addrspacecast ptr addrspace(1) %0 to ptr
+  f->cp64  = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
+  use_foo(f);
+}
+
+int test_misc_6() {
+  // X64-LABEL: define {{.*}} i32 @test_misc_6()
+  // X64: ret i32 8
+  int * __ptr32 ip32;
+  int *ip64;
+  ip64 = ip32;
+  return sizeof(ip64);
+}
+
+int test_misc_7() {
+  // X64-LABEL: define {{.*}} i32 @test_misc_7()
+  // X64: ret i32 12
+  int foo = 12;
+
+  int *ip64;
+  int * __ptr32 ip32;
+
+  ip64 = &foo;
+  ip32 = (int * __ptr32) ip64;
+
+  return *ip32;
+}
+
+int test_misc_8() {
+  // X64-LABEL: define {{.*}} i32 @test_misc_8()
+  // X64: ret i32 97
+  char foo = 'a';
+
+  char *cp64;
+  char * __ptr32 cp32;
+
+  cp64 = &foo;
+  cp32 = (char * __ptr32) cp64;
+
+  return *cp32;
+}
+
+int test_misc_9() {
+  // X64-LABEL: define {{.*}} i32 @test_misc_9()
+  // X64: ret i32 15
+  int foo = 15;
+
+  int *ip64;
+  int * __ptr32 ip32;
+
+  ip32 = &foo;
+  ip64 = (int *)ip32;
+
+  return *ip64;
+}
+
+int test_misc_10() {
+  // X64-LABEL: define {{.*}} i32 @test_misc_10()
+  // X64: ret i32 97
+  char foo = 'a';
+
+  char *cp64;
+  char * __ptr32 cp32;
+
+  cp32 = &foo;
+  cp64= (char *)cp32;
+
+  return *cp64;
+}
+
+int test_function_ptr32_is_32bit() {
+  // X64-LABEL: define {{.*}} i32 @test_function_ptr32_is_32bit()
+  // X64: ret i32 4
+  int (* __ptr32 a)(int a);
+  return sizeof(a);
+}
+
+int get_processor_count() {
+  // X64-LABEL: define signext range(i32 -128, 128) i32 @get_processor_count()
+  // X64: load ptr addrspace(1), ptr inttoptr (i64 16 to ptr)
+  // X64-NEXT: [[ARR_IDX1:%[a-z].*]] = getelementptr inbounds i8, ptr addrspace(1) %0, i32 660
+  // X64: load ptr addrspace(1), ptr addrspace(1) [[ARR_IDX1]]
+  // X64: load i8, ptr addrspace(1) {{%[a-z].*}}
+  // X64: sext i8 {{%[0-9]}} to i32
+  // X64-NEXT: ret i32
+  return ((char * __ptr32 * __ptr32 *)0)[4][165][53];
+}
+
+int get_sizes_ptr32() {
+  // X64-LABEL: define {{.*}} i32 @get_sizes_ptr32()
+  // X64: ret i32 72
+  char * __ptr32 a;
+  signed char * __ptr32 b;
+  unsigned char *__ptr32 c;
+  int * __ptr32 d;
+  signed int * __ptr32 e;
+  unsigned int *__ptr32 f;
+  short * __ptr32 g;
+  signed short * __ptr32 h;
+  unsigned short * __ptr32 i;
+  long * __ptr32 j;
+  signed * __ptr32 k;
+  unsigned * __ptr32 l;
+  long long * __ptr32 m;
+  signed long long * __ptr32 n;
+  unsigned long long * __ptr32 o;
+  float * __ptr32 p;
+  double * __ptr32 q;
+  long double * __ptr32 r;
+
+  int sum = 0;
+  sum += sizeof(a);
+  sum += sizeof(b);
+  sum += sizeof(c);
+  sum += sizeof(d);
+  sum += sizeof(e);
+  sum += sizeof(f);
+  sum += sizeof(g);
+  sum += sizeof(h);
+  sum += sizeof(i);
+  sum += sizeof(j);
+  sum += sizeof(k);
+  sum += sizeof(l);
+  sum += sizeof(m);
+  sum += sizeof(n);
+  sum += sizeof(o);
+  sum += sizeof(p);
+  sum += sizeof(q);
+  sum += sizeof(r);
+
+  return sum;
+}
+
+int get_sizes_p64() {
+  // X64-LABEL: define {{.*}} i32 @get_sizes_p64()
+  // X64: ret i32 144
+  char *a;
+  signed char *b;
+  unsigned char *c;
+  int *d;
+  signed int *e;
+  unsigned int *f;
+  short *g;
+  signed short *h;
+  unsigned short *i;
+  long *j;
+  signed *k;
+  unsigned *l;
+  long long *m;
+  signed long long *n;
+  unsigned long long *o;
+  float *p;
+  double *q;
+  long double *r;
+
+  int sum = 0;
+  sum += sizeof(a);
+  sum += sizeof(b);
+  sum += sizeof(c);
+  sum += sizeof(d);
+  sum += sizeof(e);
+  sum += sizeof(f);
+  sum += sizeof(g);
+  sum += sizeof(h);
+  sum += sizeof(i);
+  sum += sizeof(j);
+  sum += sizeof(k);
+  sum += sizeof(l);
+  sum += sizeof(m);
+  sum += sizeof(n);
+  sum += sizeof(o);
+  sum += sizeof(p);
+  sum += sizeof(q);
+  sum += sizeof(r);
+
+  return sum;
+
+}
+
+int host_cpu() {
+  char *__ptr32 CVT = *(char * __ptr32 *__ptr32) 16;
+  unsigned short Id = *(unsigned short *)&CVT[-6];
+  Id = ((((Id >> 12) & 0x0f) * 10 + ((Id >> 8) & 0x0f)) * 10 + ((Id >> 4) & 0x0f)) * 10 + (Id & 0x0f);
+  int HaveVectorSupport = CVT[244] & 0x80;
+  int z13 = (Id >= 2964 && HaveVectorSupport);
+  return z13;
+}
diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c
index 9a9fda70226fc2..41cbd5a0219d5e 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/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp b/clang/test/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp
new file mode 100644
index 00000000000000..d14ce117b2be4a
--- /dev/null
+++ b/clang/test/CodeGenCXX/zos-mangle-ptr-size-address-space.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fzos-extensions -emit-llvm -triple s390x-ibm-zos -x c++ -o - %s | FileCheck %s --check-prefixes=CHECK
+
+// CHECK-LABEL: define void @_Z2f1v()
+void f1() {}
+
+// CHECK-LABEL: define void @_Z2f2Pi(ptr addrspace(1) noundef %p32)
+void f2(int * __ptr32 p32) {}
+
+// CHECK-LABEL: define noundef ptr addrspace(1) @_Z2f3Pi(ptr addrspace(1) noundef %p32)
+int * __ptr32 f3(int * __ptr32 p32) {
+  return p32;
+}
+
+// CHECK-LABEL: define noundef ptr @_Z2f4PPi(ptr noundef %p32)
+int * __ptr32 *f4(int * __ptr32 *p32) {
+  return p32;
+}
diff --git a/clang/test/Sema/ZOSExtensions.cpp b/clang/test/Sema/ZOSExtensions.cpp
new file mode 100644
index 00000000000000..65caa12afdcf09
--- /dev/null
+++ b/clang/test/Sema/ZOSExtensions.cpp
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos %s -fsyntax-only -fzos-extensions -verify
+
+struct A {
+  int a;
+  short b;
+  float q;
+  double z;
+};
+
+union B {
+  int a;
+  short b;
+  float q;
+  double z;
+};
+
+class C {
+  int a;
+  short b;
+  float q;
+  double z;
+};
+
+// ************************
+// INCORRECT DECLARATION
+// ************************
+int * __ptr64 p64; // expected-error {{expected ';' after top level declarator}}
+int *wrong_var3 __ptr32; // expected-error {{expected ';' after top level declarator}} expected-warning {{declaration does not declare anything}}
+
+// **************************
+// INCORRECT USAGES OF PTR32
+// **************************
+struct D {
+  int __ptr32 *a; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+};
+
+union E {
+  int __ptr32 *b; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+};
+
+char __ptr32 *a; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+signed char __ptr32 *b; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+unsigned char __ptr32 *c; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 *d; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+signed int __ptr32 *e; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+unsigned int __ptr32 *f; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+short int __ptr32 *g; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+signed short int __ptr32 *h; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+unsigned short int __ptr32 *i; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+long int __ptr32 *j; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+signed long int __ptr32 *k; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+unsigned long int __ptr32 *l; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+long long int __ptr32 *m; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+signed long long int __ptr32 *n; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+unsigned long long int __ptr32 *o; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+float __ptr32 *p;                  // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+double __ptr32 *q;                 // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 **r;                   // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 *__ptr32 *s;           // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 *__ptr32 *__ptr32 t;   // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 *__ptr32 *__ptr32 *__ptr32 u; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 __ptr32 **v_i;                // expected-error {{'__ptr32' attribute only applies to pointer arguments}} expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int __ptr32 __ptr32 __ptr32 w_i;          // expected-error {{'__ptr32' attribute only applies to pointer arguments}} expected-error {{'__ptr32' attribute only applies to pointer arguments}} expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+__ptr32 int wrong_var; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+struct A __ptr32 *c1;                  // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+struct A __ptr32 **e1;                 // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+struct A __ptr32 *__ptr32 *f1;         // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+struct A __ptr32 *__ptr32 *__ptr32 g1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+union B __ptr32 *d1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+union B __ptr32 **h1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+union B __ptr32 * __ptr32 *i1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+union B __ptr32 * __ptr32 * __ptr32 j1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+C __ptr32 **k1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+C __ptr32 * __ptr32 *l1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+C __ptr32 * __ptr32 * __ptr32 m1; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+
+struct D n1;
+union E o1;
+
+int incorrect_func() {
+  int __ptr32 = 1; // expected-error {{expected unqualified-id}}
+  return __ptr32; // expected-error {{expected expression}}
+}
+
+typedef int __ptr32; // expected-warning {{typedef requires a name}}
+int incorrect_func2() {
+  return 1;
+}
+
+typedef int __ptr32 *v; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
+int incorrect_func3() {
+  v v1;
+  return 0;
+}
+
+int *__ptr32 a_ptr; //expected-note {{previous definition is here}}
+int *a_ptr;         // expected-error {{redefinition of 'a_ptr' with a different type: 'int *' vs 'int * __ptr32'}}
+
+// *******************************************************
+// FUNCTION OVERLOADING BETWEEN PTR32 AND REGULAR POINTERS
+// *******************************************************
+void func(int * __ptr32 p32) {} // expected-note {{previous definition is here}}
+void func(int *p64) {}          // expected-error {{redefinition of 'func'}}
+
+// Overloads between ptr32 and other non-pointer types are permissible
+void func1(int *__ptr32 p32) {}
+void func1(int p64) {}
+
+// ******
+// MISC
+// ******
+void func2() {
+  char * __ptr32 v = ((char * __ptr32 *)1028)[0];
+  char *v1 = ((char ** __ptr32 *)1028)[0][1];
+}
+
diff --git a/clang/test/Sema/attr-print-zos.c b/clang/test/Sema/attr-print-zos.c
new file mode 100644
index 00000000000000..f19926c131a4f3
--- /dev/null
+++ b/clang/test/Sema/attr-print-zos.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -triple s390x-ibm-zos -ast-print -fzos-extensions | FileCheck %s
+
+// CHECK: int * __ptr32 p32;
+int * __ptr32 p32;
+
+// CHECK: char * __ptr32 c32;
+char * __ptr32 c32;
+
+// CHECK: void * __ptr32 v32;
+void * __ptr32 v32;
+
+// CHECK: int * __ptr32 *q;
+int * __ptr32 *q;
+
+// CHECK: void *func(int * __ptr32 p);
+void *func(int * __ptr32 p);
+
+// CHECK: int * __ptr32 func1(int * __ptr32 p);
+int * __ptr32 func1(int * __ptr32 p);
+
+// CHECK: int *func2(void * __ptr32 p);
+int *func2(void * __ptr32 p);
+
+// CHECK: int *const __ptr32 r;
+int * __ptr32 const r;
+
+// CHECK: int ** __ptr32 *v;
+int * *__ptr32* v;
+
+// CHECK: int *** __ptr32 *z;
+int ** * __ptr32 * z;
diff --git a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
index 6f76839724ee9f..53ed46f14f14dc 100644
--- a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
@@ -59,6 +59,14 @@ static std::string computeDataLayout(const Triple &TT) {
   // Data mangling.
   Ret += DataLayout::getManglingComponent(TT);
 
+  // Special features for z/OS.
+  if (TT.isOSzOS()) {
+    if (TT.isArch64Bit()) {
+      // Custom address space for ptr32.
+      Ret += "-p1:32:32";
+    }
+  }
+
   // Make sure that global data has at least 16 bits of alignment by
   // default, so that we can refer to it using LARL.  We don't have any
   // special requirements for stack variables though.



More information about the cfe-commits mailing list