1; RUN: llc < %s -mtriple s390x-ibm-zos | FileCheck %s 2; Source to regenerate: 3; struct Foo { 4; int * __ptr32 p32; 5; int *p64; 6; char *cp64; 7; }; 8; void use_foo(Foo *f); 9; 10; // Assiging a ptr32 value to a 64-bit pointer 11; void ptr32_to_ptr(Foo *f, int * __ptr32 i) { 12; f->p64 = i; 13; use_foo(f); 14; } 15; 16; // Assigning a 64-bit ptr value to a ptr32 17; void ptr_to_ptr32(Foo *f, int *i) { 18; f->p32 = i; 19; use_foo(f); 20; } 21; 22; // Assigning a ptr32 value to a ptr32 value 23; void ptr32_to_ptr32(Foo *f, int * __ptr32 i) { 24; f->p32 = i; 25; use_foo(f); 26; } 27; 28; void ptr_to_ptr(Foo *f, int *i) { 29; f->p64 = i; 30; use_foo(f); 31; } 32; 33; void test_indexing(Foo *f) { 34; f->cp64 = ((char * __ptr32 *)1028)[1]; 35; use_foo(f); 36; } 37; 38; void test_indexing_2(Foo *f) { 39; f->cp64 = ((char *** __ptr32 *)1028)[1][2][3]; 40; use_foo(f); 41; } 42; 43; unsigned long* test_misc() { 44; unsigned long* x = (unsigned long*)((char***** __ptr32*)1208)[0][11][1][113][149]; 45; return x; 46; } 47; 48; char* __ptr32* __ptr32 test_misc_2() { 49; static char* __ptr32* __ptr32 res = 0; 50; if (res == 0) { 51; res = ((char* __ptr32* __ptr32* __ptr32* __ptr32*)0)[4][136][6]; 52; } 53; return res; 54; } 55; 56; unsigned short test_misc_3() { 57; unsigned short this_asid = ((unsigned short*)(*(char* __ptr32*)(0x224)))[18]; 58; return this_asid; 59; } 60; 61; int test_misc_4() { 62; int a = (*(int*)(80 + ((char**** __ptr32*)1208)[0][11][1][123]) > 0x040202FF); 63; return a; 64; } 65; 66; void test_misc_5(struct Foo *f) { 67; f->cp64 = *(char* __ptr32 *)(PSA_PTR + PSAAOLD); 68; use_foo(f); 69; } 70; 71; int get_processor_count() { 72; return ((char * __ptr32 * __ptr32 *)0)[4][165][53]; 73; } 74; 75; void spill_ptr32_args_to_registers( char *__ptr32 p ) { 76; void g ( int, ... ); 77; g ( 5, p, p, p, p, p ); 78; } 79; 80; $ clang -cc1 -triple s390x-ibm-zos -fzos-extensions -O2 -S t.cpp 81; 82; For the last test case: 83; 84;#include <stdlib.h> 85; 86;int foo(); 87; 88;typedef struct qa_area {/* Area descriptor */ 89; char* __ptr32 text; /* Start address of area */ 90; int length; /* Size of area in bytes */ 91;} qa_area; 92; 93;int main() { 94; qa_area* __ptr32 fap_asm_option_a = (qa_area*)__malloc31(sizeof(qa_area)); 95; 96; //((qa_area*)fap_asm_option_a)->length = foo(); //PASSES 97; fap_asm_option_a->length = foo(); //CRASHES 98; return 0; 99;} 100 101%struct.Foo = type { ptr addrspace(1), ptr, ptr } 102declare void @use_foo(ptr) 103 104define void @ptr32_to_ptr(ptr %f, ptr addrspace(1) %i) { 105entry: 106; CHECK-LABEL: ptr32_to_ptr: 107; CHECK: llgtr 0,2 108; CHECK-NEXT: stg 0,8(1) 109 %0 = addrspacecast ptr addrspace(1) %i to ptr 110 %p64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 1 111 store ptr %0, ptr %p64, align 8 112 tail call void @use_foo(ptr %f) 113 ret void 114} 115 116define void @ptr_to_ptr32(ptr %f, ptr %i) { 117entry: 118; CHECK-LABEL: ptr_to_ptr32: 119; CHECK: nilh 2,32767 120; CHECK-NEXT: st 2,0(1) 121 %0 = addrspacecast ptr %i to ptr addrspace(1) 122 %p32 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 0 123 store ptr addrspace(1) %0, ptr %p32, align 8 124 tail call void @use_foo(ptr %f) 125 ret void 126} 127 128define void @ptr32_to_ptr32(ptr %f, ptr addrspace(1) %i) { 129entry: 130; CHECK-LABEL: ptr32_to_ptr32: 131; CHECK: st 2,0(1) 132 %p32 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 0 133 store ptr addrspace(1) %i, ptr %p32, align 8 134 tail call void @use_foo(ptr %f) 135 ret void 136} 137 138define void @ptr_to_ptr(ptr %f, ptr %i) { 139; CHECK-LABEL: ptr_to_ptr: 140; CHECK: stg 2,8(1) 141 %p64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 1 142 store ptr %i, ptr %p64, align 8 143 tail call void @use_foo(ptr %f) 144 ret void 145} 146 147define void @test_indexing(ptr %f) { 148entry: 149; CHECK-LABEL: test_indexing: 150; CHECK: l 0,1032 151; CHECK: llgtr 0,0 152; CHECK: stg 0,16(1) 153 %0 = load ptr addrspace(1), ptr inttoptr (i64 1032 to ptr), align 8 154 %1 = addrspacecast ptr addrspace(1) %0 to ptr 155 %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 156 store ptr %1, ptr %cp64, align 8 157 tail call void @use_foo(ptr %f) 158 ret void 159} 160 161define void @test_indexing_2(ptr %f) { 162entry: 163; CHECK-LABEL: test_indexing_2: 164; CHECK: lhi 0,16 165; CHECK-NEXT: a 0,1032 166; CHECK-NEXT: llgtr 2,0 167; CHECK: lg 0,24(2) 168; CHECK: stg 0,16(1) 169 %0 = load ptr addrspace(1), ptr inttoptr (i64 1032 to ptr), align 8 170 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 2 171 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 172 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 3 173 %2 = bitcast ptr %arrayidx1 to ptr 174 %3 = load i64, ptr %2, align 8 175 %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 176 %4 = bitcast ptr %cp64 to ptr 177 store i64 %3, ptr %4, align 8 178 tail call void @use_foo(ptr %f) 179 ret void 180} 181 182define ptr @test_misc() { 183entry: 184; CHECK-LABEL: test_misc: 185; CHECK: lhi 0,88 186; CHECK-NEXT: a 0,1208 187; CHECK-NEXT: llgtr 1,0 188; CHECK-NEXT: lg 1,0(1) 189; CHECK-NEXT: lg 1,8(1) 190; CHECK-NEXT: lg 1,904(1) 191; CHECK-NEXT: lg 3,1192(1) 192 %0 = load ptr addrspace(1), ptr inttoptr (i64 1208 to ptr), align 8 193 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 11 194 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 195 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 1 196 %2 = load ptr, ptr %arrayidx1, align 8 197 %arrayidx2 = getelementptr inbounds ptr, ptr %2, i64 113 198 %3 = load ptr, ptr %arrayidx2, align 8 199 %arrayidx3 = getelementptr inbounds ptr, ptr %3, i64 149 200 %4 = bitcast ptr %arrayidx3 to ptr 201 %5 = load ptr, ptr %4, align 8 202 ret ptr %5 203} 204 205define ptr addrspace(1) @test_misc_2() { 206entry: 207; CHECK-LABEL: test_misc_2: 208; CHECK: lhi 0,544 209; CHECK: a 0,16 210; CHECK: llgtr 1,0 211; CHECK: lhi 0,24 212; CHECK: a 0,0(1) 213; CHECK: llgtr 1,0 214 %0 = load ptr addrspace(1), ptr inttoptr (i64 16 to ptr), align 16 215 %arrayidx = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %0, i32 136 216 %1 = load ptr addrspace(1), ptr addrspace(1) %arrayidx, align 4 217 %arrayidx1 = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %1, i32 6 218 %2 = load ptr addrspace(1), ptr addrspace(1) %arrayidx1, align 4 219 ret ptr addrspace(1) %2 220} 221 222define zeroext i16 @test_misc_3() { 223entry: 224; CHECK-LABEL: test_misc_3: 225; CHECK: a 0,548 226; CHECK-NEXT: llgtr 1,0 227; CHECK-NEXT: llgh 3,0(1) 228; CHECK-NEXT: b 2(7) 229 %0 = load ptr addrspace(1), ptr inttoptr (i64 548 to ptr), align 4 230 %arrayidx2 = getelementptr inbounds i16, ptr addrspace(1) %0, i32 18 231 %arrayidx = addrspacecast ptr addrspace(1) %arrayidx2 to ptr 232 %1 = load i16, ptr %arrayidx, align 2 233 ret i16 %1 234} 235 236define signext i32 @test_misc_4() { 237entry: 238; CHECK-LABEL: test_misc_4: 239; CHECK: lhi 0,88 240; CHECK-NEXT: a 0,1208 241; CHECK-NEXT: llgtr 1,0 242; CHECK-NEXT: lg 1,0(1) 243; CHECK-NEXT: lg 1,8(1) 244; CHECK-NEXT: lg 1,984(1) 245; CHECK-NEXT: iilf 0,67240703 246; CHECK-NEXT: c 0,80(1) 247 %0 = load ptr addrspace(1), ptr inttoptr (i64 1208 to ptr), align 8 248 %arrayidx = getelementptr inbounds ptr, ptr addrspace(1) %0, i32 11 249 %1 = load ptr, ptr addrspace(1) %arrayidx, align 8 250 %arrayidx1 = getelementptr inbounds ptr, ptr %1, i64 1 251 %2 = load ptr, ptr %arrayidx1, align 8 252 %arrayidx2 = getelementptr inbounds ptr, ptr %2, i64 123 253 %3 = load ptr, ptr %arrayidx2, align 8 254 %add.ptr = getelementptr inbounds i8, ptr %3, i64 80 255 %4 = bitcast ptr %add.ptr to ptr 256 %5 = load i32, ptr %4, align 4 257 %cmp = icmp sgt i32 %5, 67240703 258 %conv = zext i1 %cmp to i32 259 ret i32 %conv 260} 261 262define void @test_misc_5(ptr %f) { 263entry: 264; CHECK-LABEL: test_misc_5: 265; CHECK: l 0,548 266; CHECK-NEXT: lg 6,8(5) 267; CHECK-NEXT: lg 5,0(5) 268; CHECK-NEXT: llgtr 0,0 269; CHECK-NEXT: stg 0,16(1) 270 %0 = load ptr addrspace(1), ptr inttoptr (i64 548 to ptr), align 4 271 %1 = addrspacecast ptr addrspace(1) %0 to ptr 272 %cp64 = getelementptr inbounds %struct.Foo, ptr %f, i64 0, i32 2 273 store ptr %1, ptr %cp64, align 8 274 tail call void @use_foo(ptr %f) 275 ret void 276} 277 278define signext i32 @get_processor_count() { 279entry: 280; CHECK-LABEL: get_processor_count: 281; CHECK: lhi 0,660 282; CHECK-NEXT: a 0,16 283; CHECK-NEXT: llgtr 1,0 284; CHECK-NEXT: lhi 0,53 285; CHECK-NEXT: a 0,0(1) 286; CHECK-NEXT: llgtr 1,0 287; CHECK-NEXT: lgb 3,0(1) 288 %0 = load ptr addrspace(1), ptr inttoptr (i64 16 to ptr), align 16 289 %arrayidx = getelementptr inbounds ptr addrspace(1), ptr addrspace(1) %0, i32 165 290 %1 = load ptr addrspace(1), ptr addrspace(1) %arrayidx, align 4 291 %arrayidx1 = getelementptr inbounds i8, ptr addrspace(1) %1, i32 53 292 %2 = load i8, ptr addrspace(1) %arrayidx1, align 1 293 %conv = sext i8 %2 to i32 294 ret i32 %conv 295} 296 297define void @spill_ptr32_args_to_registers(i8 addrspace(1)* %p) { 298entry: 299; CHECK-LABEL: spill_ptr32_args_to_registers: 300; CHECK: stmg 6,7,1872(4) 301; CHECK-NEXT: aghi 4,-192 302; CHECK-NEXT: lgr 2,1 303; CHECK-NEXT: lg 6,24(5) 304; CHECK-NEXT: lg 5,16(5) 305; CHECK-NEXT: stg 1,2216(4) 306; CHECK-NEXT: stg 1,2208(4) 307; CHECK-NEXT: lghi 1,5 308; CHECK-NEXT: stg 2,2200(4) 309; CHECK-NEXT: lgr 3,2 310; CHECK-NEXT: basr 7,6 311; CHECK-NEXT: bcr 0,0 312; CHECK-NEXT: lg 7,2072(4) 313; CHECK-NEXT: aghi 4,192 314; CHECK-NEXT: b 2(7) 315 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) 316 ret void 317} 318declare void @g(i32 signext, ...) 319 320; The resulting instructions may look odd on first view but it is a result of 321; the C code. __malloc31() returns a 64 bit pointer, thus the sequence 322; 323; la 1, 4(8) 324; llgtr 1, 1 325; 326; references the length attribute via the 64 bit pointer, and performs the 327; cast to __ptr32, setting the upper 32 bit to zero. 328; 329define signext i32 @setlength() { 330; CHECK-LABEL: setlength: 331; CHECK: basr 7,6 332; CHECK: lgr [[MALLOC:[0-9]+]],3 333; CHECK: basr 7,6 334; CHECK: lgr [[LENGTH:[0-9]+]],3 335; CHECK: la [[ADDR:[0-9]+]],4([[MALLOC]]) 336; CHECK: llgtr [[ADDR]],[[ADDR]] 337; CHECK: stg [[LENGTH]],0([[ADDR]]) 338entry: 339 %call = tail call ptr @__malloc31(i64 noundef 8) 340 %call1 = tail call signext i32 @foo() 341 %length = getelementptr inbounds i8, ptr %call, i64 4 342 %0 = bitcast ptr %length to ptr 343 %1 = addrspacecast ptr %0 to ptr addrspace(1) 344 store i32 %call1, ptr addrspace(1) %1, align 4 345 ret i32 0 346} 347 348; Same as test before, but this time calling 349; extern char* __ptr32 domalloc(unsigned long); 350; instead of __malloc31(). Note the different instruction sequence, because 351; the function now returns a __ptr32. 352; 353define signext i32 @setlength2() { 354; CHECK-LABEL: setlength2: 355; CHECK: basr 7,6 356; CHECK: lgr [[MALLOC:[0-9]+]],3 357; CHECK: basr 7,6 358; CHECK: lgr [[LENGTH:[0-9]+]],3 359; CHECK: ahi [[MALLOC]],4 360; CHECK: llgtr [[ADDR]],[[MALLOC]] 361; CHECK: stg [[LENGTH]],0([[ADDR]]) 362entry: 363 %call = tail call ptr addrspace(1) @domalloc(i64 noundef 8) 364 %call1 = tail call signext i32 @foo() 365 %length = getelementptr inbounds i8, ptr addrspace(1) %call, i32 4 366 %0 = bitcast ptr addrspace(1) %length to ptr addrspace(1) 367 store i32 %call1, ptr addrspace(1) %0, align 4 368 ret i32 0 369} 370 371declare ptr @__malloc31(i64) 372 373declare signext i32 @foo(...) 374 375declare ptr addrspace(1) @domalloc(i64) 376