1; Test the handling of base + index + 12-bit displacement addresses for 2; large frames, in cases where no 20-bit form exists. 3; 4; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck -check-prefix=CHECK-NOFP %s 5; RUN: llc < %s -mtriple=s390x-linux-gnu -disable-fp-elim | FileCheck -check-prefix=CHECK-FP %s 6 7declare void @foo(float *%ptr1, float *%ptr2) 8 9; This file tests what happens when a displacement is converted from 10; being relative to the start of a frame object to being relative to 11; the frame itself. In some cases the test is only possible if two 12; objects are allocated. 13; 14; Rather than rely on a particular order for those objects, the tests 15; instead allocate two objects of the same size and apply the test to 16; both of them. For consistency, all tests follow this model, even if 17; one object would actually be enough. 18 19; First check the highest in-range offset after conversion, which is 4092 20; for word-addressing instructions like LDEB. 21; 22; The last in-range doubleword offset is 4088. Since the frame has two 23; emergency spill slots at 160(%r15), the amount that we need to allocate 24; in order to put another object at offset 4088 is (4088 - 176) / 4 = 978 25; words. 26define void @f1(double *%dst) { 27; CHECK-NOFP-LABEL: f1: 28; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r15) 29; CHECK-NOFP: br %r14 30; 31; CHECK-FP-LABEL: f1: 32; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r11) 33; CHECK-FP: br %r14 34 %region1 = alloca [978 x float], align 8 35 %region2 = alloca [978 x float], align 8 36 %start1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 0 37 %start2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 0 38 call void @foo(float *%start1, float *%start2) 39 %ptr1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 1 40 %ptr2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 1 41 %float1 = load float *%ptr1 42 %float2 = load float *%ptr2 43 %double1 = fpext float %float1 to double 44 %double2 = fpext float %float2 to double 45 store volatile double %double1, double *%dst 46 store volatile double %double2, double *%dst 47 ret void 48} 49 50; Test the first out-of-range offset. 51define void @f2(double *%dst) { 52; CHECK-NOFP-LABEL: f2: 53; CHECK-NOFP: lghi %r1, 4096 54; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15) 55; CHECK-NOFP: br %r14 56; 57; CHECK-FP-LABEL: f2: 58; CHECK-FP: lghi %r1, 4096 59; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11) 60; CHECK-FP: br %r14 61 %region1 = alloca [978 x float], align 8 62 %region2 = alloca [978 x float], align 8 63 %start1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 0 64 %start2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 0 65 call void @foo(float *%start1, float *%start2) 66 %ptr1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 2 67 %ptr2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 2 68 %float1 = load float *%ptr1 69 %float2 = load float *%ptr2 70 %double1 = fpext float %float1 to double 71 %double2 = fpext float %float2 to double 72 store volatile double %double1, double *%dst 73 store volatile double %double2, double *%dst 74 ret void 75} 76 77; Test the next offset after that. 78define void @f3(double *%dst) { 79; CHECK-NOFP-LABEL: f3: 80; CHECK-NOFP: lghi %r1, 4096 81; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15) 82; CHECK-NOFP: br %r14 83; 84; CHECK-FP-LABEL: f3: 85; CHECK-FP: lghi %r1, 4096 86; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11) 87; CHECK-FP: br %r14 88 %region1 = alloca [978 x float], align 8 89 %region2 = alloca [978 x float], align 8 90 %start1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 0 91 %start2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 0 92 call void @foo(float *%start1, float *%start2) 93 %ptr1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 3 94 %ptr2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 3 95 %float1 = load float *%ptr1 96 %float2 = load float *%ptr2 97 %double1 = fpext float %float1 to double 98 %double2 = fpext float %float2 to double 99 store volatile double %double1, double *%dst 100 store volatile double %double2, double *%dst 101 ret void 102} 103 104; Add 4096 bytes (1024 words) to the size of each object and repeat. 105define void @f4(double *%dst) { 106; CHECK-NOFP-LABEL: f4: 107; CHECK-NOFP: lghi %r1, 4096 108; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15) 109; CHECK-NOFP: br %r14 110; 111; CHECK-FP-LABEL: f4: 112; CHECK-FP: lghi %r1, 4096 113; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11) 114; CHECK-FP: br %r14 115 %region1 = alloca [2002 x float], align 8 116 %region2 = alloca [2002 x float], align 8 117 %start1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 0 118 %start2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 0 119 call void @foo(float *%start1, float *%start2) 120 %ptr1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 1 121 %ptr2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 1 122 %float1 = load float *%ptr1 123 %float2 = load float *%ptr2 124 %double1 = fpext float %float1 to double 125 %double2 = fpext float %float2 to double 126 store volatile double %double1, double *%dst 127 store volatile double %double2, double *%dst 128 ret void 129} 130 131; ...as above. 132define void @f5(double *%dst) { 133; CHECK-NOFP-LABEL: f5: 134; CHECK-NOFP: lghi %r1, 8192 135; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15) 136; CHECK-NOFP: br %r14 137; 138; CHECK-FP-LABEL: f5: 139; CHECK-FP: lghi %r1, 8192 140; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11) 141; CHECK-FP: br %r14 142 %region1 = alloca [2002 x float], align 8 143 %region2 = alloca [2002 x float], align 8 144 %start1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 0 145 %start2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 0 146 call void @foo(float *%start1, float *%start2) 147 %ptr1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 2 148 %ptr2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 2 149 %float1 = load float *%ptr1 150 %float2 = load float *%ptr2 151 %double1 = fpext float %float1 to double 152 %double2 = fpext float %float2 to double 153 store volatile double %double1, double *%dst 154 store volatile double %double2, double *%dst 155 ret void 156} 157 158; ...as above. 159define void @f6(double *%dst) { 160; CHECK-NOFP-LABEL: f6: 161; CHECK-NOFP: lghi %r1, 8192 162; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15) 163; CHECK-NOFP: br %r14 164; 165; CHECK-FP-LABEL: f6: 166; CHECK-FP: lghi %r1, 8192 167; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11) 168; CHECK-FP: br %r14 169 %region1 = alloca [2002 x float], align 8 170 %region2 = alloca [2002 x float], align 8 171 %start1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 0 172 %start2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 0 173 call void @foo(float *%start1, float *%start2) 174 %ptr1 = getelementptr inbounds [2002 x float]* %region1, i64 0, i64 3 175 %ptr2 = getelementptr inbounds [2002 x float]* %region2, i64 0, i64 3 176 %float1 = load float *%ptr1 177 %float2 = load float *%ptr2 178 %double1 = fpext float %float1 to double 179 %double2 = fpext float %float2 to double 180 store volatile double %double1, double *%dst 181 store volatile double %double2, double *%dst 182 ret void 183} 184 185; Now try an offset of 4092 from the start of the object, with the object 186; being at offset 8192. This time we need objects of (8192 - 168) / 4 = 2004 187; words. 188define void @f7(double *%dst) { 189; CHECK-NOFP-LABEL: f7: 190; CHECK-NOFP: lghi %r1, 8192 191; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15) 192; CHECK-NOFP: br %r14 193; 194; CHECK-FP-LABEL: f7: 195; CHECK-FP: lghi %r1, 8192 196; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11) 197; CHECK-FP: br %r14 198 %region1 = alloca [2004 x float], align 8 199 %region2 = alloca [2004 x float], align 8 200 %start1 = getelementptr inbounds [2004 x float]* %region1, i64 0, i64 0 201 %start2 = getelementptr inbounds [2004 x float]* %region2, i64 0, i64 0 202 call void @foo(float *%start1, float *%start2) 203 %ptr1 = getelementptr inbounds [2004 x float]* %region1, i64 0, i64 1023 204 %ptr2 = getelementptr inbounds [2004 x float]* %region2, i64 0, i64 1023 205 %float1 = load float *%ptr1 206 %float2 = load float *%ptr2 207 %double1 = fpext float %float1 to double 208 %double2 = fpext float %float2 to double 209 store volatile double %double1, double *%dst 210 store volatile double %double2, double *%dst 211 ret void 212} 213 214; Keep the object-relative offset the same but bump the size of the 215; objects by one doubleword. 216define void @f8(double *%dst) { 217; CHECK-NOFP-LABEL: f8: 218; CHECK-NOFP: lghi %r1, 12288 219; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15) 220; CHECK-NOFP: br %r14 221; 222; CHECK-FP-LABEL: f8: 223; CHECK-FP: lghi %r1, 12288 224; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11) 225; CHECK-FP: br %r14 226 %region1 = alloca [2006 x float], align 8 227 %region2 = alloca [2006 x float], align 8 228 %start1 = getelementptr inbounds [2006 x float]* %region1, i64 0, i64 0 229 %start2 = getelementptr inbounds [2006 x float]* %region2, i64 0, i64 0 230 call void @foo(float *%start1, float *%start2) 231 %ptr1 = getelementptr inbounds [2006 x float]* %region1, i64 0, i64 1023 232 %ptr2 = getelementptr inbounds [2006 x float]* %region2, i64 0, i64 1023 233 %float1 = load float *%ptr1 234 %float2 = load float *%ptr2 235 %double1 = fpext float %float1 to double 236 %double2 = fpext float %float2 to double 237 store volatile double %double1, double *%dst 238 store volatile double %double2, double *%dst 239 ret void 240} 241 242; Check a case where the original displacement is out of range. The backend 243; should force an LAY from the outset. We don't yet do any kind of anchor 244; optimization, so there should be no offset on the LDEB itself. 245define void @f9(double *%dst) { 246; CHECK-NOFP-LABEL: f9: 247; CHECK-NOFP: lay %r1, 12296(%r15) 248; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1) 249; CHECK-NOFP: br %r14 250; 251; CHECK-FP-LABEL: f9: 252; CHECK-FP: lay %r1, 12296(%r11) 253; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1) 254; CHECK-FP: br %r14 255 %region1 = alloca [2006 x float], align 8 256 %region2 = alloca [2006 x float], align 8 257 %start1 = getelementptr inbounds [2006 x float]* %region1, i64 0, i64 0 258 %start2 = getelementptr inbounds [2006 x float]* %region2, i64 0, i64 0 259 call void @foo(float *%start1, float *%start2) 260 %ptr1 = getelementptr inbounds [2006 x float]* %region1, i64 0, i64 1024 261 %ptr2 = getelementptr inbounds [2006 x float]* %region2, i64 0, i64 1024 262 %float1 = load float *%ptr1 263 %float2 = load float *%ptr2 264 %double1 = fpext float %float1 to double 265 %double2 = fpext float %float2 to double 266 store volatile double %double1, double *%dst 267 store volatile double %double2, double *%dst 268 ret void 269} 270 271; Repeat f2 in a case that needs the emergency spill slots, because all 272; call-clobbered and allocated call-saved registers are live. Note that 273; %vptr and %dst are copied to call-saved registers, freeing up %r2 and 274; %r3 during the main test. 275define void @f10(i32 *%vptr, double *%dst) { 276; CHECK-NOFP-LABEL: f10: 277; CHECK-NOFP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r15) 278; CHECK-NOFP: lghi [[REGISTER]], 4096 279; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r15) 280; CHECK-NOFP: lg [[REGISTER]], [[OFFSET]](%r15) 281; CHECK-NOFP: br %r14 282; 283; CHECK-FP-LABEL: f10: 284; CHECK-FP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r11) 285; CHECK-FP: lghi [[REGISTER]], 4096 286; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r11) 287; CHECK-FP: lg [[REGISTER]], [[OFFSET]](%r11) 288; CHECK-FP: br %r14 289 %region1 = alloca [978 x float], align 8 290 %region2 = alloca [978 x float], align 8 291 %start1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 0 292 %start2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 0 293 call void @foo(float *%start1, float *%start2) 294 %ptr1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 2 295 %ptr2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 2 296 %i0 = load volatile i32 *%vptr 297 %i1 = load volatile i32 *%vptr 298 %i2 = load volatile i32 *%vptr 299 %i3 = load volatile i32 *%vptr 300 %i4 = load volatile i32 *%vptr 301 %i5 = load volatile i32 *%vptr 302 %i14 = load volatile i32 *%vptr 303 %float1 = load float *%ptr1 304 %float2 = load float *%ptr2 305 %double1 = fpext float %float1 to double 306 %double2 = fpext float %float2 to double 307 store volatile double %double1, double *%dst 308 store volatile double %double2, double *%dst 309 store volatile i32 %i0, i32 *%vptr 310 store volatile i32 %i1, i32 *%vptr 311 store volatile i32 %i2, i32 *%vptr 312 store volatile i32 %i3, i32 *%vptr 313 store volatile i32 %i4, i32 *%vptr 314 store volatile i32 %i5, i32 *%vptr 315 store volatile i32 %i14, i32 *%vptr 316 ret void 317} 318 319; Repeat f2 in a case where the index register is already occupied. 320define void @f11(double *%dst, i64 %index) { 321; CHECK-NOFP-LABEL: f11: 322; CHECK-NOFP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3 323; CHECK-NOFP: lay %r1, 4096(%r15) 324; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1) 325; CHECK-NOFP: br %r14 326; 327; CHECK-FP-LABEL: f11: 328; CHECK-FP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3 329; CHECK-FP: lay %r1, 4096(%r11) 330; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1) 331; CHECK-FP: br %r14 332 %region1 = alloca [978 x float], align 8 333 %region2 = alloca [978 x float], align 8 334 %start1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 0 335 %start2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 0 336 call void @foo(float *%start1, float *%start2) 337 %elem1 = getelementptr inbounds [978 x float]* %region1, i64 0, i64 2 338 %elem2 = getelementptr inbounds [978 x float]* %region2, i64 0, i64 2 339 %base1 = ptrtoint float *%elem1 to i64 340 %base2 = ptrtoint float *%elem2 to i64 341 %addr1 = add i64 %base1, %index 342 %addr2 = add i64 %base2, %index 343 %ptr1 = inttoptr i64 %addr1 to float * 344 %ptr2 = inttoptr i64 %addr2 to float * 345 %float1 = load float *%ptr1 346 %float2 = load float *%ptr2 347 %double1 = fpext float %float1 to double 348 %double2 = fpext float %float2 to double 349 store volatile double %double1, double *%dst 350 store volatile double %double2, double *%dst 351 ret void 352} 353