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
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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++")
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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";
Expand Down
17 changes: 13 additions & 4 deletions clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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.

};

/// How a keyword is treated in the selected standard. This enum is ordered
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -230,6 +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;

Expand Down
43 changes: 42 additions & 1 deletion clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand All @@ -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 &)
Expand All @@ -49,14 +74,17 @@ 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.
MaxVectorAlign = 64;
// 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;
Expand Down Expand Up @@ -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())
Comment on lines +257 to +259
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)

? 32
: PointerWidth;
}

uint64_t getPointerAlignV(LangAS AddrSpace) const override {
return getPointerWidthV(AddrSpace);
}

};
} // namespace targets
} // namespace clang
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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?

} else {
if (Opts.ZOSExt)
GenerateArg(Consumer, OPT_fzos_extensions);
}

if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
GenerateArg(Consumer, OPT_fblocks);

Expand Down Expand Up @@ -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);

Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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.

ASIdx = LangAS::ptr32_uptr;
else
ASIdx = LangAS::ptr32_sptr;
} else {
if (Attrs[attr::UPtr])
ASIdx = LangAS::ptr32_uptr;
else
ASIdx = LangAS::ptr32_sptr;
}
Comment on lines +7101 to +7108
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

}

QualType Pointee = Type->getPointeeType();
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions clang/test/CodeGen/zos-mixed-ptr-sizes-definitions.c
Original file line number Diff line number Diff line change
@@ -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;

}
84 changes: 84 additions & 0 deletions clang/test/CodeGen/zos-mixed-ptr-sizes-malloc.c
Original file line number Diff line number Diff line change
@@ -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?

#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);
}

Loading
Loading