Skip to content

Commit 135fecd

Browse files
authored
[SystemZ][z/OS] __ptr32 support for z/OS (#101696)
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.
1 parent 7e7a439 commit 135fecd

18 files changed

+786
-12
lines changed

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ LANGOPT(C2y , 1, 0, "C2y")
9191
LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode")
9292
LANGOPT(Kernel , 1, 0, "Kernel mode")
9393
LANGOPT(MicrosoftExt , 1, 0, "Microsoft C++ extensions")
94+
LANGOPT(ZOSExt , 1, 0, "z/OS extensions")
9495
LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks")
9596
LANGOPT(Borland , 1, 0, "Borland extensions")
9697
LANGOPT(CPlusPlus , 1, 0, "C++")

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ PUNCTUATOR(caretcaret, "^^")
292292
// CHAR8SUPPORT - This is a keyword if 'char8_t' is a built-in type
293293
// KEYFIXEDPOINT - This is a keyword according to the N1169 fixed point
294294
// extension.
295+
// KEYZOS - This is a keyword in C/C++ on z/OS
295296
//
296297
KEYWORD(auto , KEYALL)
297298
KEYWORD(break , KEYALL)
@@ -725,7 +726,7 @@ KEYWORD(__funcref , KEYALL)
725726

726727
// Microsoft extensions which should be disabled in strict conformance mode
727728
KEYWORD(__ptr64 , KEYMS)
728-
KEYWORD(__ptr32 , KEYMS)
729+
KEYWORD(__ptr32 , KEYMS | KEYZOS)
729730
KEYWORD(__sptr , KEYMS)
730731
KEYWORD(__uptr , KEYMS)
731732
KEYWORD(__w64 , KEYMS)

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,6 +3066,10 @@ dll version.}]>;
30663066
def fms_omit_default_lib : Joined<["-"], "fms-omit-default-lib">,
30673067
Group<f_Group>, Flags<[]>,
30683068
Visibility<[ClangOption, CLOption]>;
3069+
def fzos_extensions : Flag<["-"], "fzos-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
3070+
HelpText<"Accept some non-standard constructs supported by the z/OS compiler">;
3071+
def fno_zos_extensions : Flag<["-"], "fno-zos-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
3072+
HelpText<"Do not accept non-standard constructs supported by the z/OS compiler">;
30693073
defm delayed_template_parsing : BoolFOption<"delayed-template-parsing",
30703074
LangOpts<"DelayedTemplateParsing">, DefaultFalse,
30713075
PosFlag<SetTrue, [], [ClangOption, CC1Option],

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2727,6 +2727,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
27272727
// <type> ::= U <OpenCL-addrspace>
27282728
// <type> ::= U <CUDA-addrspace>
27292729

2730+
llvm::Triple Triple = getASTContext().getTargetInfo().getTriple();
2731+
27302732
SmallString<64> ASString;
27312733
LangAS AS = Quals.getAddressSpace();
27322734

@@ -2795,7 +2797,11 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
27952797
ASString = "ptr32_sptr";
27962798
break;
27972799
case LangAS::ptr32_uptr:
2798-
ASString = "ptr32_uptr";
2800+
// For z/OS, there are no special mangling rules applied to the ptr32
2801+
// qualifier. Ex: void foo(int * __ptr32 p) -> _Z3f2Pi. The mangling for
2802+
// "p" is treated the same as a regular integer pointer.
2803+
if (!Triple.isOSzOS())
2804+
ASString = "ptr32_uptr";
27992805
break;
28002806
case LangAS::ptr64:
28012807
ASString = "ptr64";

clang/lib/Basic/IdentifierTable.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@ enum TokenKey : unsigned {
107107
KEYMSCOMPAT = 0x400000,
108108
KEYSYCL = 0x800000,
109109
KEYCUDA = 0x1000000,
110-
KEYHLSL = 0x2000000,
111-
KEYFIXEDPOINT = 0x4000000,
110+
KEYZOS = 0x2000000,
111+
KEYNOZOS = 0x4000000,
112+
KEYHLSL = 0x8000000,
113+
KEYFIXEDPOINT = 0x10000000,
112114
KEYMAX = KEYFIXEDPOINT, // The maximum key
113115
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
114-
KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 &
115-
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
116+
KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
117+
~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.
116118
};
117119

118120
/// How a keyword is treated in the selected standard. This enum is ordered
@@ -199,16 +201,17 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
199201
return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
200202
case KEYCUDA:
201203
return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
204+
case KEYZOS:
205+
return LangOpts.ZOSExt ? KS_Enabled : KS_Unknown;
202206
case KEYHLSL:
203207
return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
204208
case KEYNOCXX:
205209
// This is enabled in all non-C++ modes, but might be enabled for other
206210
// reasons as well.
207211
return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
208212
case KEYNOOPENCL:
209-
// The disable behavior for this is handled in getKeywordStatus.
210-
return KS_Unknown;
211213
case KEYNOMS18:
214+
case KEYNOZOS:
212215
// The disable behavior for this is handled in getKeywordStatus.
213216
return KS_Unknown;
214217
case KEYFIXEDPOINT:
@@ -230,7 +233,8 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
230233
if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
231234
!LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
232235
return KS_Disabled;
233-
236+
if (LangOpts.ZOSExt && (Flags & KEYNOZOS))
237+
return KS_Disabled;
234238
KeywordStatus CurStatus = KS_Unknown;
235239

236240
while (Flags != 0) {

clang/lib/Basic/Targets/SystemZ.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@
2121
namespace clang {
2222
namespace targets {
2323

24+
static const unsigned ZOSAddressMap[] = {
25+
0, // Default
26+
0, // opencl_global
27+
0, // opencl_local
28+
0, // opencl_constant
29+
0, // opencl_private
30+
0, // opencl_generic
31+
0, // opencl_global_device
32+
0, // opencl_global_host
33+
0, // cuda_device
34+
0, // cuda_constant
35+
0, // cuda_shared
36+
0, // sycl_global
37+
0, // sycl_global_device
38+
0, // sycl_global_host
39+
0, // sycl_local
40+
0, // sycl_private
41+
0, // ptr32_sptr
42+
1, // ptr32_uptr
43+
0, // ptr64
44+
0, // hlsl_groupshared
45+
0 // wasm_funcref
46+
};
47+
2448
class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
2549

2650
static const char *const GCCRegNames[];
@@ -30,6 +54,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
3054
bool HasVector;
3155
bool SoftFloat;
3256
bool UnalignedSymbols;
57+
enum AddrSpace { ptr32 = 1 };
3358

3459
public:
3560
SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -49,14 +74,17 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
4974
MinGlobalAlign = 16;
5075
HasUnalignedAccess = true;
5176
if (Triple.isOSzOS()) {
77+
if (Triple.isArch64Bit()) {
78+
AddrSpaceMap = &ZOSAddressMap;
79+
}
5280
TLSSupported = false;
5381
// All vector types are default aligned on an 8-byte boundary, even if the
5482
// vector facility is not available. That is different from Linux.
5583
MaxVectorAlign = 64;
5684
// Compared to Linux/ELF, the data layout differs only in some details:
5785
// - name mangling is GOFF.
5886
// - 32 bit pointers, either as default or special address space
59-
resetDataLayout("E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-"
87+
resetDataLayout("E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-"
6088
"a:8:16-n32:64");
6189
} else {
6290
TLSSupported = true;
@@ -224,6 +252,16 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
224252
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
225253
return std::make_pair(256, 256);
226254
}
255+
uint64_t getPointerWidthV(LangAS AddrSpace) const override {
256+
return (getTriple().isOSzOS() && getTriple().isArch64Bit() &&
257+
getTargetAddressSpace(AddrSpace) == ptr32)
258+
? 32
259+
: PointerWidth;
260+
}
261+
262+
uint64_t getPointerAlignV(LangAS AddrSpace) const override {
263+
return getPointerWidthV(AddrSpace);
264+
}
227265
};
228266
} // namespace targets
229267
} // namespace clang

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7514,6 +7514,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
75147514
(C.isForDiagnostics() && !HaveModules))
75157515
CmdArgs.push_back("-frewrite-includes");
75167516

7517+
if (Args.hasFlag(options::OPT_fzos_extensions,
7518+
options::OPT_fno_zos_extensions, false))
7519+
CmdArgs.push_back("-fzos-extensions");
7520+
else if (Args.hasArg(options::OPT_fno_zos_extensions))
7521+
CmdArgs.push_back("-fno-zos-extensions");
7522+
75177523
// Only allow -traditional or -traditional-cpp outside in preprocessing modes.
75187524
if (Arg *A = Args.getLastArg(options::OPT_traditional,
75197525
options::OPT_traditional_cpp)) {

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3650,6 +3650,11 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
36503650
GenerateArg(Consumer, OPT_ftrigraphs);
36513651
}
36523652

3653+
if (T.isOSzOS() && !Opts.ZOSExt)
3654+
GenerateArg(Consumer, OPT_fno_zos_extensions);
3655+
else if (Opts.ZOSExt)
3656+
GenerateArg(Consumer, OPT_fzos_extensions);
3657+
36533658
if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
36543659
GenerateArg(Consumer, OPT_fblocks);
36553660

@@ -4051,6 +4056,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
40514056
Opts.Trigraphs =
40524057
Args.hasFlag(OPT_ftrigraphs, OPT_fno_trigraphs, Opts.Trigraphs);
40534058

4059+
Opts.ZOSExt =
4060+
Args.hasFlag(OPT_fzos_extensions, OPT_fno_zos_extensions, T.isOSzOS());
4061+
40544062
Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL
40554063
&& Opts.OpenCLVersion == 200);
40564064

clang/lib/Sema/SemaType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7057,6 +7057,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
70577057

70587058
// Add address space to type based on its attributes.
70597059
LangAS ASIdx = LangAS::Default;
7060+
llvm::Triple Triple = S.Context.getTargetInfo().getTriple();
70607061
uint64_t PtrWidth =
70617062
S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
70627063
if (PtrWidth == 32) {
@@ -7065,7 +7066,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
70657066
else if (Attrs[attr::UPtr])
70667067
ASIdx = LangAS::ptr32_uptr;
70677068
} else if (PtrWidth == 64 && Attrs[attr::Ptr32]) {
7068-
if (Attrs[attr::UPtr])
7069+
if (Triple.isOSzOS() || Attrs[attr::UPtr])
70697070
ASIdx = LangAS::ptr32_uptr;
70707071
else
70717072
ASIdx = LangAS::ptr32_sptr;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -triple s390x-ibm-zos -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-ZOS
2+
// RUN: %clang_cc1 -triple s390x-ibm-linux -fzos-extensions -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-LINUX
3+
// RUN: %clang_cc1 -triple s390x-linux-gnu -fzos-extensions -emit-llvm < %s | FileCheck %s --check-prefix=PTR32-LINUX
4+
5+
void ptr32_declarations() {
6+
// PTR32-ZOS-LABEL: @ptr32_declarations()
7+
// PTR32-LINUX-LABEL: @ptr32_declarations()
8+
9+
// PTR32-ZOS: %p1 = alloca ptr addrspace(1), align 4
10+
// PTR32-LINUX-NOT: %p1 = alloca i8 addrspace(1)*, align 4
11+
// PTR32-LINUX: %p1 = alloca ptr, align 8
12+
char * __ptr32 p1;
13+
14+
// PTR32-ZOS: %p2 = alloca ptr, align 8
15+
// PTR32-LINUX-NOT: %p2 = alloca ptr addrspace(1), align 8
16+
// PTR32-LINUX: %p2 = alloca ptr, align 8
17+
char * __ptr32 *p2;
18+
19+
// PTR32-ZOS: %p3 = alloca ptr addrspace(1), align 4
20+
// PTR32-LINUX-NOT: %p3 = alloca i8* addrspace(1)*, align 4
21+
// PTR32-LINUX: %p3 = alloca ptr, align 8
22+
char ** __ptr32 p3;
23+
24+
// PTR32-ZOS: %p4 = alloca ptr, align 8
25+
// PTR32-LINUX-NOT: %p4 = alloca ptr addrspace(1), align 8
26+
// PTR32-LINUX: %p4 = alloca ptr, align 8
27+
char ** __ptr32 *p4;
28+
29+
// PTR32-ZOS: %p5 = alloca ptr, align 8
30+
// PTR32-LINUX-NOT: %p5 = alloca ptr addrspace(1), align 8
31+
// PTR32-LINUX: %p5 = alloca ptr, align 8
32+
char *** __ptr32 *p5;
33+
34+
// PTR32-ZOS: %p6 = alloca ptr, align 8
35+
// PTR32-LINUX: %p6 = alloca ptr, align 8
36+
char **p6;
37+
38+
// PTR32-ZOS: %p7 = alloca ptr addrspace(1), align 4
39+
// PTR32-LINUX-NOT: %p7 = alloca i8 addrspace(1)* addrspace(1)*, align 4
40+
// PTR32-LINUX: %p7 = alloca ptr, align 8
41+
char * __ptr32 * __ptr32 p7;
42+
43+
// PTR32-ZOS: %p8 = alloca ptr addrspace(1), align 4
44+
// PTR32-LINUX-NOT: %p8 = alloca i8* addrspace(1)* addrspace(1)*, align 4
45+
// PTR32-LINUX: %p8 = alloca ptr, align 8
46+
char ** __ptr32 * __ptr32 p8;
47+
48+
// PTR32-ZOS: %p9 = alloca ptr, align 8
49+
// PTR32-LINUX-NOT: %p9 = alloca i8* addrspace(1)* addrspace(1)**, align 8
50+
// PTR32-LINUX: %p9 = alloca ptr, align 8
51+
char ** __ptr32 * __ptr32 *p9;
52+
53+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: %clang -target s390x-ibm-zos -emit-llvm -S -O2 %s -o - | FileCheck %s --check-prefix=X64
2+
#include <stddef.h>
3+
void *__malloc31(size_t);
4+
5+
int test_1() {
6+
// X64-LABEL: define {{.*}} i32 @test_1()
7+
// X64: ret i32 135
8+
int *__ptr32 a;
9+
int *b;
10+
int i;
11+
int sum1, sum2, sum3;
12+
13+
a = (int *__ptr32)__malloc31(sizeof(int) * 10);
14+
15+
b = a;
16+
sum1 = 0;
17+
for (i = 0; i < 10; ++i) {
18+
a[i] = i;
19+
sum1 += i;
20+
}
21+
22+
sum2 = 0;
23+
for (i = 0; i < 10; ++i) {
24+
sum2 += a[i];
25+
}
26+
sum3 = 0;
27+
for (i = 0; i < 10; ++i) {
28+
sum3 += b[i];
29+
}
30+
31+
return (sum1 + sum2 + sum3);
32+
}
33+
34+
int test_2() {
35+
// X64-LABEL: define {{.*}} i32 @test_2()
36+
// X64: ret i32 4
37+
int *a = (int *)__malloc31(sizeof(int));
38+
int *__ptr32 b;
39+
40+
*a = 99;
41+
b = a;
42+
*b = 44;
43+
44+
// Test should return 4
45+
return (*b - 40);
46+
}
47+
48+
int test_3() {
49+
// X64-LABEL: define {{.*}} i32 @test_3()
50+
// X64: ret i32 4
51+
int *a = (int *)__malloc31(sizeof(int));
52+
int *__ptr32 b;
53+
54+
*a = 99;
55+
b = a;
56+
57+
// Test should return 4
58+
return (*b - 95);
59+
}
60+
61+
int test_4() {
62+
// X64-LABEL: define {{.*}} i32 @test_4()
63+
// X64: ret i32 1
64+
int *a = (int *)__malloc31(sizeof(int));
65+
float *d = (float *)__malloc31(sizeof(float));
66+
67+
int *__ptr32 b;
68+
int *c;
69+
70+
float *__ptr32 e;
71+
float *f;
72+
73+
*a = 0;
74+
*d = 0.0;
75+
76+
b = a;
77+
c = a;
78+
e = d;
79+
f = d;
80+
81+
// Test should return 1
82+
return (b == c && e == f);
83+
}
84+

0 commit comments

Comments
 (0)