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 7 declare 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. 26 define 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. 51 define 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. 78 define 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. 105 define 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. 132 define 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. 159 define 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. 188 define 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. 216 define 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. 245 define 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. 275 define 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. 320 define 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