; RUN: llc < %s -mtriple s390x-ibm-zos | FileCheck %s ; Source to regenerate: ; struct Foo { ; int * __ptr32 p32; ; int *p64; ; char *cp64; ; }; ; void use_foo(Foo *f); ; ; // Assiging a ptr32 value to a 64-bit pointer ; void ptr32_to_ptr(Foo *f, int * __ptr32 i) { ; f->p64 = i; ; use_foo(f); ; } ; ; // Assigning a 64-bit ptr value to a ptr32 ; void ptr_to_ptr32(Foo *f, int *i) { ; f->p32 = i; ; use_foo(f); ; } ; ; // Assigning a ptr32 value to a ptr32 value ; void ptr32_to_ptr32(Foo *f, int * __ptr32 i) { ; f->p32 = i; ; use_foo(f); ; } ; ; void ptr_to_ptr(Foo *f, int *i) { ; f->p64 = i; ; use_foo(f); ; } ; ; void test_indexing(Foo *f) { ; f->cp64 = ((char * __ptr32 *)1028)[1]; ; use_foo(f); ; } ; ; void test_indexing_2(Foo *f) { ; f->cp64 = ((char *** __ptr32 *)1028)[1][2][3]; ; use_foo(f); ; } ; ; unsigned long* test_misc() { ; unsigned long* x = (unsigned long*)((char***** __ptr32*)1208)[0][11][1][113][149]; ; return x; ; } ; ; char* __ptr32* __ptr32 test_misc_2() { ; 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() { ; unsigned short this_asid = ((unsigned short*)(*(char* __ptr32*)(0x224)))[18]; ; return this_asid; ; } ; ; int test_misc_4() { ; int a = (*(int*)(80 + ((char**** __ptr32*)1208)[0][11][1][123]) > 0x040202FF); ; return a; ; } ; ; void test_misc_5(struct Foo *f) { ; f->cp64 = *(char* __ptr32 *)(PSA_PTR + PSAAOLD); ; use_foo(f); ; } ; ; int get_processor_count() { ; return ((char * __ptr32 * __ptr32 *)0)[4][165][53]; ; } ; ; void spill_ptr32_args_to_registers( char *__ptr32 p ) { ; void g ( int, ... ); ; g ( 5, p, p, p, p, p ); ; } ; ; $ clang -cc1 -triple s390x-ibm-zos -fzos-extensions -O2 -S t.cpp ; ; For the last test case: ; ;#include ; ;int foo(); ; ;typedef struct qa_area {/* Area descriptor */ ; char* __ptr32 text; /* Start address of area */ ; int length; /* Size of area in bytes */ ;} qa_area; ; ;int main() { ; qa_area* __ptr32 fap_asm_option_a = (qa_area*)__malloc31(sizeof(qa_area)); ; ; //((qa_area*)fap_asm_option_a)->length = foo(); //PASSES ; fap_asm_option_a->length = foo(); //CRASHES ; return 0; ;} %struct.Foo = type { ptr addrspace(1), ptr, ptr } declare void @use_foo(ptr) define void @ptr32_to_ptr(ptr %f, ptr addrspace(1) %i) { entry: ; CHECK-LABEL: ptr32_to_ptr: ; CHECK: llgtr 0,2 ; CHECK-NEXT: stg 0,8(1) %0 = addrspacecast ptr addrspace(1) %i to ptr %p64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 1 store ptr %0, ptr %p64, align 8 tail call void @use_foo(ptr %f) ret void } define void @ptr_to_ptr32(ptr %f, ptr %i) { entry: ; CHECK-LABEL: ptr_to_ptr32: ; CHECK: nilh 2,32767 ; CHECK-NEXT: st 2,0(1) %0 = addrspacecast ptr %i to ptr addrspace(1) %p32 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 0 store ptr addrspace(1) %0, ptr %p32, align 8 tail call void @use_foo(ptr %f) ret void } define void @ptr32_to_ptr32(ptr %f, ptr addrspace(1) %i) { entry: ; CHECK-LABEL: ptr32_to_ptr32: ; CHECK: st 2,0(1) %p32 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 0 store ptr addrspace(1) %i, ptr %p32, align 8 tail call void @use_foo(ptr %f) ret void } define void @ptr_to_ptr(ptr %f, ptr %i) { ; CHECK-LABEL: ptr_to_ptr: ; CHECK: stg 2,8(1) %p64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 1 store ptr %i, ptr %p64, align 8 tail call void @use_foo(ptr %f) ret void } define void @test_indexing(ptr %f) { entry: ; CHECK-LABEL: test_indexing: ; CHECK: l 0,1032 ; CHECK: llgtr 0,0 ; CHECK: stg 0,16(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 1032 to ptr), align 8 %1 = addrspacecast ptr addrspace(1) %0 to ptr %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 store ptr %1, ptr %cp64, align 8 tail call void @use_foo(ptr %f) ret void } define void @test_indexing_2(ptr %f) { entry: ; CHECK-LABEL: test_indexing_2: ; CHECK: lhi 0,16 ; CHECK-NEXT: a 0,1032 ; CHECK-NEXT: llgtr 2,0 ; CHECK: lg 0,24(2) ; CHECK: stg 0,16(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 1032 to ptr), align 8 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 2 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 3 %2 = bitcast ptr %arrayidx1 to ptr %3 = load i64, ptr %2, align 8 %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 %4 = bitcast ptr %cp64 to ptr store i64 %3, ptr %4, align 8 tail call void @use_foo(ptr %f) ret void } define ptr @test_misc() { entry: ; CHECK-LABEL: test_misc: ; CHECK: lhi 0,88 ; CHECK-NEXT: a 0,1208 ; CHECK-NEXT: llgtr 1,0 ; CHECK-NEXT: lg 1,0(1) ; CHECK-NEXT: lg 1,8(1) ; CHECK-NEXT: lg 1,904(1) ; CHECK-NEXT: lg 3,1192(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 1208 to ptr), align 8 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 11 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 1 %2 = load ptr, ptr %arrayidx1, align 8 %arrayidx2 = getelementptr inbounds ptr, ptr %2, i64 113 %3 = load ptr, ptr %arrayidx2, align 8 %arrayidx3 = getelementptr inbounds ptr, ptr %3, i64 149 %4 = bitcast ptr %arrayidx3 to ptr %5 = load ptr, ptr %4, align 8 ret ptr %5 } define ptr addrspace(1) @test_misc_2() { entry: ; CHECK-LABEL: test_misc_2: ; CHECK: lhi 0,544 ; CHECK: a 0,16 ; CHECK: llgtr 1,0 ; CHECK: lhi 0,24 ; CHECK: a 0,0(1) ; CHECK: llgtr 1,0 %0 = load ptr addrspace(1), ptr inttoptr (i64 16 to ptr), align 16 %arrayidx = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %0, i32 136 %1 = load ptr addrspace(1), ptr addrspace(1) %arrayidx, align 4 %arrayidx1 = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %1, i32 6 %2 = load ptr addrspace(1), ptr addrspace(1) %arrayidx1, align 4 ret ptr addrspace(1) %2 } define zeroext i16 @test_misc_3() { entry: ; CHECK-LABEL: test_misc_3: ; CHECK: a 0,548 ; CHECK-NEXT: llgtr 1,0 ; CHECK-NEXT: llgh 3,0(1) ; CHECK-NEXT: b 2(7) %0 = load ptr addrspace(1), ptr inttoptr (i64 548 to ptr), align 4 %arrayidx2 = getelementptr inbounds i16, ptr addrspace(1) %0, i32 18 %arrayidx = addrspacecast ptr addrspace(1) %arrayidx2 to ptr %1 = load i16, ptr %arrayidx, align 2 ret i16 %1 } define signext i32 @test_misc_4() { entry: ; CHECK-LABEL: test_misc_4: ; CHECK: lhi 0,88 ; CHECK-NEXT: a 0,1208 ; CHECK-NEXT: llgtr 1,0 ; CHECK-NEXT: lg 1,0(1) ; CHECK-NEXT: lg 1,8(1) ; CHECK-NEXT: lg 1,984(1) ; CHECK-NEXT: iilf 0,67240703 ; CHECK-NEXT: c 0,80(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 1208 to ptr), align 8 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 11 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 1 %2 = load ptr, ptr %arrayidx1, align 8 %arrayidx2 = getelementptr inbounds ptr, ptr %2, i64 123 %3 = load ptr, ptr %arrayidx2, align 8 %add.ptr = getelementptr inbounds i8, ptr %3, i64 80 %4 = bitcast ptr %add.ptr to ptr %5 = load i32, ptr %4, align 4 %cmp = icmp sgt i32 %5, 67240703 %conv = zext i1 %cmp to i32 ret i32 %conv } define void @test_misc_5(ptr %f) { entry: ; CHECK-LABEL: test_misc_5: ; CHECK: l 0,548 ; CHECK-NEXT: lg 6,8(5) ; CHECK-NEXT: lg 5,0(5) ; CHECK-NEXT: llgtr 0,0 ; CHECK-NEXT: stg 0,16(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 548 to ptr), align 4 %1 = addrspacecast ptr addrspace(1) %0 to ptr %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 store ptr %1, ptr %cp64, align 8 tail call void @use_foo(ptr %f) ret void } define signext i32 @get_processor_count() { entry: ; CHECK-LABEL: get_processor_count: ; CHECK: lhi 0,660 ; CHECK-NEXT: a 0,16 ; CHECK-NEXT: llgtr 1,0 ; CHECK-NEXT: lhi 0,53 ; CHECK-NEXT: a 0,0(1) ; CHECK-NEXT: llgtr 1,0 ; CHECK-NEXT: lgb 3,0(1) %0 = load ptr addrspace(1), ptr inttoptr (i64 16 to ptr), align 16 %arrayidx = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %0, i32 165 %1 = load ptr addrspace(1), ptr addrspace(1) %arrayidx, align 4 %arrayidx1 = getelementptr inbounds i8, ptr addrspace(1) %1, i32 53 %2 = load i8, ptr addrspace(1) %arrayidx1, align 1 %conv = sext i8 %2 to i32 ret i32 %conv } define void @spill_ptr32_args_to_registers(i8 addrspace(1)* %p) { entry: ; CHECK-LABEL: spill_ptr32_args_to_registers: ; CHECK: stmg 6,7,1872(4) ; CHECK-NEXT: aghi 4,-192 ; CHECK-NEXT: lgr 2,1 ; CHECK-NEXT: lg 6,24(5) ; CHECK-NEXT: lg 5,16(5) ; CHECK-NEXT: stg 1,2216(4) ; CHECK-NEXT: stg 1,2208(4) ; CHECK-NEXT: lghi 1,5 ; CHECK-NEXT: stg 2,2200(4) ; CHECK-NEXT: lgr 3,2 ; CHECK-NEXT: basr 7,6 ; CHECK-NEXT: bcr 0,0 ; CHECK-NEXT: lg 7,2072(4) ; CHECK-NEXT: aghi 4,192 ; CHECK-NEXT: b 2(7) tail call void (i32, ...) @g(i32 noundef signext 5, ptr addrspace(1) noundef %p, ptr addrspace(1) noundef %p, ptr addrspace(1) noundef %p, ptr addrspace(1) noundef %p, ptr addrspace(1) noundef %p) ret void } declare void @g(i32 signext, ...) ; The resulting instructions may look odd on first view but it is a result of ; the C code. __malloc31() returns a 64 bit pointer, thus the sequence ; ; la 1, 4(8) ; llgtr 1, 1 ; ; references the length attribute via the 64 bit pointer, and performs the ; cast to __ptr32, setting the upper 32 bit to zero. ; define signext i32 @setlength() { ; CHECK-LABEL: setlength: ; CHECK: basr 7,6 ; CHECK: lgr [[MALLOC:[0-9]+]],3 ; CHECK: basr 7,6 ; CHECK: lgr [[LENGTH:[0-9]+]],3 ; CHECK: la [[ADDR:[0-9]+]],4([[MALLOC]]) ; CHECK: llgtr [[ADDR]],[[ADDR]] ; CHECK: stg [[LENGTH]],0([[ADDR]]) entry: %call = tail call ptr @__malloc31(i64 noundef 8) %call1 = tail call signext i32 @foo() %length = getelementptr inbounds i8, ptr %call, i64 4 %0 = bitcast ptr %length to ptr %1 = addrspacecast ptr %0 to ptr addrspace(1) store i32 %call1, ptr addrspace(1) %1, align 4 ret i32 0 } ; Same as test before, but this time calling ; extern char* __ptr32 domalloc(unsigned long); ; instead of __malloc31(). Note the different instruction sequence, because ; the function now returns a __ptr32. ; define signext i32 @setlength2() { ; CHECK-LABEL: setlength2: ; CHECK: basr 7,6 ; CHECK: lgr [[MALLOC:[0-9]+]],3 ; CHECK: basr 7,6 ; CHECK: lgr [[LENGTH:[0-9]+]],3 ; CHECK: ahi [[MALLOC]],4 ; CHECK: llgtr [[ADDR]],[[MALLOC]] ; CHECK: stg [[LENGTH]],0([[ADDR]]) entry: %call = tail call ptr addrspace(1) @domalloc(i64 noundef 8) %call1 = tail call signext i32 @foo() %length = getelementptr inbounds i8, ptr addrspace(1) %call, i32 4 %0 = bitcast ptr addrspace(1) %length to ptr addrspace(1) store i32 %call1, ptr addrspace(1) %0, align 4 ret i32 0 } declare ptr @__malloc31(i64) declare signext i32 @foo(...) declare ptr addrspace(1) @domalloc(i64)