| ; 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 <stdlib.h> | |
| ; | |
| ;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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update7 DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue7 DS 0H | |
| ; 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 DS 0H | |
| ; 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 DS 0H | |
| ; 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) | |
| define void @f1(ptr %inp, ptr %outp) "target-features"="-vector" { | |
| ; CHECK-LABEL: f1 DS 0H | |
| ; CHECK: iilf 0,2147483647 | |
| ; CHECK-NEXT: iilf 3,2147483647 | |
| ; CHECK-NEXT: n 0,12(1) | |
| ; CHECK-NEXT: n 3,4(1) | |
| ; CHECK-NEXT: st 0,4(2) | |
| ; CHECK-NEXT: st 3,0(2) | |
| ; CHECK-NEXT: b 2(7) | |
| %in = load <2 x ptr>, ptr %inp, align 8 | |
| %out = addrspacecast <2 x ptr> %in to <2 x ptr addrspace(1)> | |
| store <2 x ptr addrspace(1)> %out, ptr %outp, align 4 | |
| ret void | |
| } | |
| define void @f1_v(ptr %inp, ptr %outp) "target-features"="+vector" { | |
| ; CHECK-LABEL: f1_v DS 0H | |
| ; CHECK: vl 0,0(1),3 | |
| ; CHECK-NEXT: vlgvg 0,0,1 | |
| ; CHECK-NEXT: llgtr 0,0 | |
| ; CHECK-NEXT: lghi 1,0 | |
| ; CHECK-NEXT: vlvgp 1,0,1 | |
| ; CHECK-NEXT: vlgvg 0,0,0 | |
| ; CHECK-NEXT: nilh 0,32767 | |
| ; CHECK-NEXT: vlvgf 1,0,0 | |
| ; CHECK-NEXT: vsteg 1,0(2),0 | |
| ; CHECK-NEXT: b 2(7) | |
| %in = load <2 x ptr>, ptr %inp, align 8 | |
| %out = addrspacecast <2 x ptr> %in to <2 x ptr addrspace(1)> | |
| store <2 x ptr addrspace(1)> %out, ptr %outp, align 4 | |
| ret void | |
| } |