1 ; RUN: llc -mtriple=aarch64-linux-gnu -aarch64-atomic-cfg-tidy=0 -verify-machineinstrs -o - %s | FileCheck %s 2 3 ; This file contains tests for the AArch64 load/store optimizer. 4 5 %padding = type { i8*, i8*, i8*, i8* } 6 %s.word = type { i32, i32 } 7 %s.doubleword = type { i64, i32 } 8 %s.quadword = type { fp128, i32 } 9 %s.float = type { float, i32 } 10 %s.double = type { double, i32 } 11 %struct.word = type { %padding, %s.word } 12 %struct.doubleword = type { %padding, %s.doubleword } 13 %struct.quadword = type { %padding, %s.quadword } 14 %struct.float = type { %padding, %s.float } 15 %struct.double = type { %padding, %s.double } 16 17 ; Check the following transform: 18 ; 19 ; (ldr|str) X, [x0, #32] 20 ; ... 21 ; add x0, x0, #32 22 ; -> 23 ; (ldr|str) X, [x0, #32]! 24 ; 25 ; with X being either w1, x1, s0, d0 or q0. 26 27 declare void @bar_word(%s.word*, i32) 28 29 define void @load-pre-indexed-word(%struct.word* %ptr) nounwind { 30 ; CHECK-LABEL: load-pre-indexed-word 31 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #32]! 32 entry: 33 %a = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1, i32 0 34 %add = load i32* %a, align 4 35 br label %bar 36 bar: 37 %c = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1 38 tail call void @bar_word(%s.word* %c, i32 %add) 39 ret void 40 } 41 42 define void @store-pre-indexed-word(%struct.word* %ptr, i32 %val) nounwind { 43 ; CHECK-LABEL: store-pre-indexed-word 44 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #32]! 45 entry: 46 %a = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1, i32 0 47 store i32 %val, i32* %a, align 4 48 br label %bar 49 bar: 50 %c = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1 51 tail call void @bar_word(%s.word* %c, i32 %val) 52 ret void 53 } 54 55 declare void @bar_doubleword(%s.doubleword*, i64) 56 57 define void @load-pre-indexed-doubleword(%struct.doubleword* %ptr) nounwind { 58 ; CHECK-LABEL: load-pre-indexed-doubleword 59 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #32]! 60 entry: 61 %a = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1, i32 0 62 %add = load i64* %a, align 4 63 br label %bar 64 bar: 65 %c = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1 66 tail call void @bar_doubleword(%s.doubleword* %c, i64 %add) 67 ret void 68 } 69 70 define void @store-pre-indexed-doubleword(%struct.doubleword* %ptr, i64 %val) nounwind { 71 ; CHECK-LABEL: store-pre-indexed-doubleword 72 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #32]! 73 entry: 74 %a = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1, i32 0 75 store i64 %val, i64* %a, align 4 76 br label %bar 77 bar: 78 %c = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1 79 tail call void @bar_doubleword(%s.doubleword* %c, i64 %val) 80 ret void 81 } 82 83 declare void @bar_quadword(%s.quadword*, fp128) 84 85 define void @load-pre-indexed-quadword(%struct.quadword* %ptr) nounwind { 86 ; CHECK-LABEL: load-pre-indexed-quadword 87 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #32]! 88 entry: 89 %a = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1, i32 0 90 %add = load fp128* %a, align 4 91 br label %bar 92 bar: 93 %c = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1 94 tail call void @bar_quadword(%s.quadword* %c, fp128 %add) 95 ret void 96 } 97 98 define void @store-pre-indexed-quadword(%struct.quadword* %ptr, fp128 %val) nounwind { 99 ; CHECK-LABEL: store-pre-indexed-quadword 100 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #32]! 101 entry: 102 %a = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1, i32 0 103 store fp128 %val, fp128* %a, align 4 104 br label %bar 105 bar: 106 %c = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1 107 tail call void @bar_quadword(%s.quadword* %c, fp128 %val) 108 ret void 109 } 110 111 declare void @bar_float(%s.float*, float) 112 113 define void @load-pre-indexed-float(%struct.float* %ptr) nounwind { 114 ; CHECK-LABEL: load-pre-indexed-float 115 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #32]! 116 entry: 117 %a = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1, i32 0 118 %add = load float* %a, align 4 119 br label %bar 120 bar: 121 %c = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1 122 tail call void @bar_float(%s.float* %c, float %add) 123 ret void 124 } 125 126 define void @store-pre-indexed-float(%struct.float* %ptr, float %val) nounwind { 127 ; CHECK-LABEL: store-pre-indexed-float 128 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #32]! 129 entry: 130 %a = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1, i32 0 131 store float %val, float* %a, align 4 132 br label %bar 133 bar: 134 %c = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1 135 tail call void @bar_float(%s.float* %c, float %val) 136 ret void 137 } 138 139 declare void @bar_double(%s.double*, double) 140 141 define void @load-pre-indexed-double(%struct.double* %ptr) nounwind { 142 ; CHECK-LABEL: load-pre-indexed-double 143 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #32]! 144 entry: 145 %a = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1, i32 0 146 %add = load double* %a, align 4 147 br label %bar 148 bar: 149 %c = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1 150 tail call void @bar_double(%s.double* %c, double %add) 151 ret void 152 } 153 154 define void @store-pre-indexed-double(%struct.double* %ptr, double %val) nounwind { 155 ; CHECK-LABEL: store-pre-indexed-double 156 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #32]! 157 entry: 158 %a = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1, i32 0 159 store double %val, double* %a, align 4 160 br label %bar 161 bar: 162 %c = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1 163 tail call void @bar_double(%s.double* %c, double %val) 164 ret void 165 } 166 167 ; Check the following transform: 168 ; 169 ; add x8, x8, #16 170 ; ... 171 ; ldr X, [x8] 172 ; -> 173 ; ldr X, [x8, #16]! 174 ; 175 ; with X being either w0, x0, s0, d0 or q0. 176 177 %pre.struct.i32 = type { i32, i32, i32} 178 %pre.struct.i64 = type { i32, i64, i64} 179 %pre.struct.i128 = type { i32, <2 x i64>, <2 x i64>} 180 %pre.struct.float = type { i32, float, float} 181 %pre.struct.double = type { i32, double, double} 182 183 define i32 @load-pre-indexed-word2(%pre.struct.i32** %this, i1 %cond, 184 %pre.struct.i32* %load2) nounwind { 185 ; CHECK-LABEL: load-pre-indexed-word2 186 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #4]! 187 br i1 %cond, label %if.then, label %if.end 188 if.then: 189 %load1 = load %pre.struct.i32** %this 190 %gep1 = getelementptr inbounds %pre.struct.i32* %load1, i64 0, i32 1 191 br label %return 192 if.end: 193 %gep2 = getelementptr inbounds %pre.struct.i32* %load2, i64 0, i32 2 194 br label %return 195 return: 196 %retptr = phi i32* [ %gep1, %if.then ], [ %gep2, %if.end ] 197 %ret = load i32* %retptr 198 ret i32 %ret 199 } 200 201 define i64 @load-pre-indexed-doubleword2(%pre.struct.i64** %this, i1 %cond, 202 %pre.struct.i64* %load2) nounwind { 203 ; CHECK-LABEL: load-pre-indexed-doubleword2 204 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #8]! 205 br i1 %cond, label %if.then, label %if.end 206 if.then: 207 %load1 = load %pre.struct.i64** %this 208 %gep1 = getelementptr inbounds %pre.struct.i64* %load1, i64 0, i32 1 209 br label %return 210 if.end: 211 %gep2 = getelementptr inbounds %pre.struct.i64* %load2, i64 0, i32 2 212 br label %return 213 return: 214 %retptr = phi i64* [ %gep1, %if.then ], [ %gep2, %if.end ] 215 %ret = load i64* %retptr 216 ret i64 %ret 217 } 218 219 define <2 x i64> @load-pre-indexed-quadword2(%pre.struct.i128** %this, i1 %cond, 220 %pre.struct.i128* %load2) nounwind { 221 ; CHECK-LABEL: load-pre-indexed-quadword2 222 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #16]! 223 br i1 %cond, label %if.then, label %if.end 224 if.then: 225 %load1 = load %pre.struct.i128** %this 226 %gep1 = getelementptr inbounds %pre.struct.i128* %load1, i64 0, i32 1 227 br label %return 228 if.end: 229 %gep2 = getelementptr inbounds %pre.struct.i128* %load2, i64 0, i32 2 230 br label %return 231 return: 232 %retptr = phi <2 x i64>* [ %gep1, %if.then ], [ %gep2, %if.end ] 233 %ret = load <2 x i64>* %retptr 234 ret <2 x i64> %ret 235 } 236 237 define float @load-pre-indexed-float2(%pre.struct.float** %this, i1 %cond, 238 %pre.struct.float* %load2) nounwind { 239 ; CHECK-LABEL: load-pre-indexed-float2 240 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #4]! 241 br i1 %cond, label %if.then, label %if.end 242 if.then: 243 %load1 = load %pre.struct.float** %this 244 %gep1 = getelementptr inbounds %pre.struct.float* %load1, i64 0, i32 1 245 br label %return 246 if.end: 247 %gep2 = getelementptr inbounds %pre.struct.float* %load2, i64 0, i32 2 248 br label %return 249 return: 250 %retptr = phi float* [ %gep1, %if.then ], [ %gep2, %if.end ] 251 %ret = load float* %retptr 252 ret float %ret 253 } 254 255 define double @load-pre-indexed-double2(%pre.struct.double** %this, i1 %cond, 256 %pre.struct.double* %load2) nounwind { 257 ; CHECK-LABEL: load-pre-indexed-double2 258 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #8]! 259 br i1 %cond, label %if.then, label %if.end 260 if.then: 261 %load1 = load %pre.struct.double** %this 262 %gep1 = getelementptr inbounds %pre.struct.double* %load1, i64 0, i32 1 263 br label %return 264 if.end: 265 %gep2 = getelementptr inbounds %pre.struct.double* %load2, i64 0, i32 2 266 br label %return 267 return: 268 %retptr = phi double* [ %gep1, %if.then ], [ %gep2, %if.end ] 269 %ret = load double* %retptr 270 ret double %ret 271 } 272 273 ; Check the following transform: 274 ; 275 ; add x8, x8, #16 276 ; ... 277 ; str X, [x8] 278 ; -> 279 ; str X, [x8, #16]! 280 ; 281 ; with X being either w0, x0, s0, d0 or q0. 282 283 define void @store-pre-indexed-word2(%pre.struct.i32** %this, i1 %cond, 284 %pre.struct.i32* %load2, 285 i32 %val) nounwind { 286 ; CHECK-LABEL: store-pre-indexed-word2 287 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #4]! 288 br i1 %cond, label %if.then, label %if.end 289 if.then: 290 %load1 = load %pre.struct.i32** %this 291 %gep1 = getelementptr inbounds %pre.struct.i32* %load1, i64 0, i32 1 292 br label %return 293 if.end: 294 %gep2 = getelementptr inbounds %pre.struct.i32* %load2, i64 0, i32 2 295 br label %return 296 return: 297 %retptr = phi i32* [ %gep1, %if.then ], [ %gep2, %if.end ] 298 store i32 %val, i32* %retptr 299 ret void 300 } 301 302 define void @store-pre-indexed-doubleword2(%pre.struct.i64** %this, i1 %cond, 303 %pre.struct.i64* %load2, 304 i64 %val) nounwind { 305 ; CHECK-LABEL: store-pre-indexed-doubleword2 306 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #8]! 307 br i1 %cond, label %if.then, label %if.end 308 if.then: 309 %load1 = load %pre.struct.i64** %this 310 %gep1 = getelementptr inbounds %pre.struct.i64* %load1, i64 0, i32 1 311 br label %return 312 if.end: 313 %gep2 = getelementptr inbounds %pre.struct.i64* %load2, i64 0, i32 2 314 br label %return 315 return: 316 %retptr = phi i64* [ %gep1, %if.then ], [ %gep2, %if.end ] 317 store i64 %val, i64* %retptr 318 ret void 319 } 320 321 define void @store-pre-indexed-quadword2(%pre.struct.i128** %this, i1 %cond, 322 %pre.struct.i128* %load2, 323 <2 x i64> %val) nounwind { 324 ; CHECK-LABEL: store-pre-indexed-quadword2 325 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #16]! 326 br i1 %cond, label %if.then, label %if.end 327 if.then: 328 %load1 = load %pre.struct.i128** %this 329 %gep1 = getelementptr inbounds %pre.struct.i128* %load1, i64 0, i32 1 330 br label %return 331 if.end: 332 %gep2 = getelementptr inbounds %pre.struct.i128* %load2, i64 0, i32 2 333 br label %return 334 return: 335 %retptr = phi <2 x i64>* [ %gep1, %if.then ], [ %gep2, %if.end ] 336 store <2 x i64> %val, <2 x i64>* %retptr 337 ret void 338 } 339 340 define void @store-pre-indexed-float2(%pre.struct.float** %this, i1 %cond, 341 %pre.struct.float* %load2, 342 float %val) nounwind { 343 ; CHECK-LABEL: store-pre-indexed-float2 344 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #4]! 345 br i1 %cond, label %if.then, label %if.end 346 if.then: 347 %load1 = load %pre.struct.float** %this 348 %gep1 = getelementptr inbounds %pre.struct.float* %load1, i64 0, i32 1 349 br label %return 350 if.end: 351 %gep2 = getelementptr inbounds %pre.struct.float* %load2, i64 0, i32 2 352 br label %return 353 return: 354 %retptr = phi float* [ %gep1, %if.then ], [ %gep2, %if.end ] 355 store float %val, float* %retptr 356 ret void 357 } 358 359 define void @store-pre-indexed-double2(%pre.struct.double** %this, i1 %cond, 360 %pre.struct.double* %load2, 361 double %val) nounwind { 362 ; CHECK-LABEL: store-pre-indexed-double2 363 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #8]! 364 br i1 %cond, label %if.then, label %if.end 365 if.then: 366 %load1 = load %pre.struct.double** %this 367 %gep1 = getelementptr inbounds %pre.struct.double* %load1, i64 0, i32 1 368 br label %return 369 if.end: 370 %gep2 = getelementptr inbounds %pre.struct.double* %load2, i64 0, i32 2 371 br label %return 372 return: 373 %retptr = phi double* [ %gep1, %if.then ], [ %gep2, %if.end ] 374 store double %val, double* %retptr 375 ret void 376 } 377 378 ; Check the following transform: 379 ; 380 ; ldr X, [x20] 381 ; ... 382 ; add x20, x20, #32 383 ; -> 384 ; ldr X, [x20], #32 385 ; 386 ; with X being either w0, x0, s0, d0 or q0. 387 388 define void @load-post-indexed-word(i32* %array, i64 %count) nounwind { 389 ; CHECK-LABEL: load-post-indexed-word 390 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}], #16 391 entry: 392 %gep1 = getelementptr i32* %array, i64 2 393 br label %body 394 395 body: 396 %iv2 = phi i32* [ %gep3, %body ], [ %gep1, %entry ] 397 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 398 %gep2 = getelementptr i32* %iv2, i64 -1 399 %load = load i32* %gep2 400 call void @use-word(i32 %load) 401 %load2 = load i32* %iv2 402 call void @use-word(i32 %load2) 403 %iv.next = add i64 %iv, -4 404 %gep3 = getelementptr i32* %iv2, i64 4 405 %cond = icmp eq i64 %iv.next, 0 406 br i1 %cond, label %exit, label %body 407 408 exit: 409 ret void 410 } 411 412 define void @load-post-indexed-doubleword(i64* %array, i64 %count) nounwind { 413 ; CHECK-LABEL: load-post-indexed-doubleword 414 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #32 415 entry: 416 %gep1 = getelementptr i64* %array, i64 2 417 br label %body 418 419 body: 420 %iv2 = phi i64* [ %gep3, %body ], [ %gep1, %entry ] 421 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 422 %gep2 = getelementptr i64* %iv2, i64 -1 423 %load = load i64* %gep2 424 call void @use-doubleword(i64 %load) 425 %load2 = load i64* %iv2 426 call void @use-doubleword(i64 %load2) 427 %iv.next = add i64 %iv, -4 428 %gep3 = getelementptr i64* %iv2, i64 4 429 %cond = icmp eq i64 %iv.next, 0 430 br i1 %cond, label %exit, label %body 431 432 exit: 433 ret void 434 } 435 436 define void @load-post-indexed-quadword(<2 x i64>* %array, i64 %count) nounwind { 437 ; CHECK-LABEL: load-post-indexed-quadword 438 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}], #64 439 entry: 440 %gep1 = getelementptr <2 x i64>* %array, i64 2 441 br label %body 442 443 body: 444 %iv2 = phi <2 x i64>* [ %gep3, %body ], [ %gep1, %entry ] 445 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 446 %gep2 = getelementptr <2 x i64>* %iv2, i64 -1 447 %load = load <2 x i64>* %gep2 448 call void @use-quadword(<2 x i64> %load) 449 %load2 = load <2 x i64>* %iv2 450 call void @use-quadword(<2 x i64> %load2) 451 %iv.next = add i64 %iv, -4 452 %gep3 = getelementptr <2 x i64>* %iv2, i64 4 453 %cond = icmp eq i64 %iv.next, 0 454 br i1 %cond, label %exit, label %body 455 456 exit: 457 ret void 458 } 459 460 define void @load-post-indexed-float(float* %array, i64 %count) nounwind { 461 ; CHECK-LABEL: load-post-indexed-float 462 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}], #16 463 entry: 464 %gep1 = getelementptr float* %array, i64 2 465 br label %body 466 467 body: 468 %iv2 = phi float* [ %gep3, %body ], [ %gep1, %entry ] 469 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 470 %gep2 = getelementptr float* %iv2, i64 -1 471 %load = load float* %gep2 472 call void @use-float(float %load) 473 %load2 = load float* %iv2 474 call void @use-float(float %load2) 475 %iv.next = add i64 %iv, -4 476 %gep3 = getelementptr float* %iv2, i64 4 477 %cond = icmp eq i64 %iv.next, 0 478 br i1 %cond, label %exit, label %body 479 480 exit: 481 ret void 482 } 483 484 define void @load-post-indexed-double(double* %array, i64 %count) nounwind { 485 ; CHECK-LABEL: load-post-indexed-double 486 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}], #32 487 entry: 488 %gep1 = getelementptr double* %array, i64 2 489 br label %body 490 491 body: 492 %iv2 = phi double* [ %gep3, %body ], [ %gep1, %entry ] 493 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 494 %gep2 = getelementptr double* %iv2, i64 -1 495 %load = load double* %gep2 496 call void @use-double(double %load) 497 %load2 = load double* %iv2 498 call void @use-double(double %load2) 499 %iv.next = add i64 %iv, -4 500 %gep3 = getelementptr double* %iv2, i64 4 501 %cond = icmp eq i64 %iv.next, 0 502 br i1 %cond, label %exit, label %body 503 504 exit: 505 ret void 506 } 507 508 ; Check the following transform: 509 ; 510 ; str X, [x20] 511 ; ... 512 ; add x20, x20, #32 513 ; -> 514 ; str X, [x20], #32 515 ; 516 ; with X being either w0, x0, s0, d0 or q0. 517 518 define void @store-post-indexed-word(i32* %array, i64 %count, i32 %val) nounwind { 519 ; CHECK-LABEL: store-post-indexed-word 520 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}], #16 521 entry: 522 %gep1 = getelementptr i32* %array, i64 2 523 br label %body 524 525 body: 526 %iv2 = phi i32* [ %gep3, %body ], [ %gep1, %entry ] 527 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 528 %gep2 = getelementptr i32* %iv2, i64 -1 529 %load = load i32* %gep2 530 call void @use-word(i32 %load) 531 store i32 %val, i32* %iv2 532 %iv.next = add i64 %iv, -4 533 %gep3 = getelementptr i32* %iv2, i64 4 534 %cond = icmp eq i64 %iv.next, 0 535 br i1 %cond, label %exit, label %body 536 537 exit: 538 ret void 539 } 540 541 define void @store-post-indexed-doubleword(i64* %array, i64 %count, i64 %val) nounwind { 542 ; CHECK-LABEL: store-post-indexed-doubleword 543 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #32 544 entry: 545 %gep1 = getelementptr i64* %array, i64 2 546 br label %body 547 548 body: 549 %iv2 = phi i64* [ %gep3, %body ], [ %gep1, %entry ] 550 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 551 %gep2 = getelementptr i64* %iv2, i64 -1 552 %load = load i64* %gep2 553 call void @use-doubleword(i64 %load) 554 store i64 %val, i64* %iv2 555 %iv.next = add i64 %iv, -4 556 %gep3 = getelementptr i64* %iv2, i64 4 557 %cond = icmp eq i64 %iv.next, 0 558 br i1 %cond, label %exit, label %body 559 560 exit: 561 ret void 562 } 563 564 define void @store-post-indexed-quadword(<2 x i64>* %array, i64 %count, <2 x i64> %val) nounwind { 565 ; CHECK-LABEL: store-post-indexed-quadword 566 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}], #64 567 entry: 568 %gep1 = getelementptr <2 x i64>* %array, i64 2 569 br label %body 570 571 body: 572 %iv2 = phi <2 x i64>* [ %gep3, %body ], [ %gep1, %entry ] 573 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 574 %gep2 = getelementptr <2 x i64>* %iv2, i64 -1 575 %load = load <2 x i64>* %gep2 576 call void @use-quadword(<2 x i64> %load) 577 store <2 x i64> %val, <2 x i64>* %iv2 578 %iv.next = add i64 %iv, -4 579 %gep3 = getelementptr <2 x i64>* %iv2, i64 4 580 %cond = icmp eq i64 %iv.next, 0 581 br i1 %cond, label %exit, label %body 582 583 exit: 584 ret void 585 } 586 587 define void @store-post-indexed-float(float* %array, i64 %count, float %val) nounwind { 588 ; CHECK-LABEL: store-post-indexed-float 589 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}], #16 590 entry: 591 %gep1 = getelementptr float* %array, i64 2 592 br label %body 593 594 body: 595 %iv2 = phi float* [ %gep3, %body ], [ %gep1, %entry ] 596 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 597 %gep2 = getelementptr float* %iv2, i64 -1 598 %load = load float* %gep2 599 call void @use-float(float %load) 600 store float %val, float* %iv2 601 %iv.next = add i64 %iv, -4 602 %gep3 = getelementptr float* %iv2, i64 4 603 %cond = icmp eq i64 %iv.next, 0 604 br i1 %cond, label %exit, label %body 605 606 exit: 607 ret void 608 } 609 610 define void @store-post-indexed-double(double* %array, i64 %count, double %val) nounwind { 611 ; CHECK-LABEL: store-post-indexed-double 612 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}], #32 613 entry: 614 %gep1 = getelementptr double* %array, i64 2 615 br label %body 616 617 body: 618 %iv2 = phi double* [ %gep3, %body ], [ %gep1, %entry ] 619 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ] 620 %gep2 = getelementptr double* %iv2, i64 -1 621 %load = load double* %gep2 622 call void @use-double(double %load) 623 store double %val, double* %iv2 624 %iv.next = add i64 %iv, -4 625 %gep3 = getelementptr double* %iv2, i64 4 626 %cond = icmp eq i64 %iv.next, 0 627 br i1 %cond, label %exit, label %body 628 629 exit: 630 ret void 631 } 632 633 declare void @use-word(i32) 634 declare void @use-doubleword(i64) 635 declare void @use-quadword(<2 x i64>) 636 declare void @use-float(float) 637 declare void @use-double(double) 638 639 ; Check the following transform: 640 ; 641 ; (ldr|str) X, [x20] 642 ; ... 643 ; sub x20, x20, #16 644 ; -> 645 ; (ldr|str) X, [x20], #-16 646 ; 647 ; with X being either w0, x0, s0, d0 or q0. 648 649 define void @post-indexed-sub-word(i32* %a, i32* %b, i64 %count) nounwind { 650 ; CHECK-LABEL: post-indexed-sub-word 651 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}], #-8 652 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}], #-8 653 br label %for.body 654 for.body: 655 %phi1 = phi i32* [ %gep4, %for.body ], [ %b, %0 ] 656 %phi2 = phi i32* [ %gep3, %for.body ], [ %a, %0 ] 657 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ] 658 %gep1 = getelementptr i32* %phi1, i64 -1 659 %load1 = load i32* %gep1 660 %gep2 = getelementptr i32* %phi2, i64 -1 661 store i32 %load1, i32* %gep2 662 %load2 = load i32* %phi1 663 store i32 %load2, i32* %phi2 664 %dec.i = add nsw i64 %i, -1 665 %gep3 = getelementptr i32* %phi2, i64 -2 666 %gep4 = getelementptr i32* %phi1, i64 -2 667 %cond = icmp sgt i64 %dec.i, 0 668 br i1 %cond, label %for.body, label %end 669 end: 670 ret void 671 } 672 673 define void @post-indexed-sub-doubleword(i64* %a, i64* %b, i64 %count) nounwind { 674 ; CHECK-LABEL: post-indexed-sub-doubleword 675 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #-16 676 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #-16 677 br label %for.body 678 for.body: 679 %phi1 = phi i64* [ %gep4, %for.body ], [ %b, %0 ] 680 %phi2 = phi i64* [ %gep3, %for.body ], [ %a, %0 ] 681 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ] 682 %gep1 = getelementptr i64* %phi1, i64 -1 683 %load1 = load i64* %gep1 684 %gep2 = getelementptr i64* %phi2, i64 -1 685 store i64 %load1, i64* %gep2 686 %load2 = load i64* %phi1 687 store i64 %load2, i64* %phi2 688 %dec.i = add nsw i64 %i, -1 689 %gep3 = getelementptr i64* %phi2, i64 -2 690 %gep4 = getelementptr i64* %phi1, i64 -2 691 %cond = icmp sgt i64 %dec.i, 0 692 br i1 %cond, label %for.body, label %end 693 end: 694 ret void 695 } 696 697 define void @post-indexed-sub-quadword(<2 x i64>* %a, <2 x i64>* %b, i64 %count) nounwind { 698 ; CHECK-LABEL: post-indexed-sub-quadword 699 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}], #-32 700 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}], #-32 701 br label %for.body 702 for.body: 703 %phi1 = phi <2 x i64>* [ %gep4, %for.body ], [ %b, %0 ] 704 %phi2 = phi <2 x i64>* [ %gep3, %for.body ], [ %a, %0 ] 705 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ] 706 %gep1 = getelementptr <2 x i64>* %phi1, i64 -1 707 %load1 = load <2 x i64>* %gep1 708 %gep2 = getelementptr <2 x i64>* %phi2, i64 -1 709 store <2 x i64> %load1, <2 x i64>* %gep2 710 %load2 = load <2 x i64>* %phi1 711 store <2 x i64> %load2, <2 x i64>* %phi2 712 %dec.i = add nsw i64 %i, -1 713 %gep3 = getelementptr <2 x i64>* %phi2, i64 -2 714 %gep4 = getelementptr <2 x i64>* %phi1, i64 -2 715 %cond = icmp sgt i64 %dec.i, 0 716 br i1 %cond, label %for.body, label %end 717 end: 718 ret void 719 } 720 721 define void @post-indexed-sub-float(float* %a, float* %b, i64 %count) nounwind { 722 ; CHECK-LABEL: post-indexed-sub-float 723 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}], #-8 724 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}], #-8 725 br label %for.body 726 for.body: 727 %phi1 = phi float* [ %gep4, %for.body ], [ %b, %0 ] 728 %phi2 = phi float* [ %gep3, %for.body ], [ %a, %0 ] 729 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ] 730 %gep1 = getelementptr float* %phi1, i64 -1 731 %load1 = load float* %gep1 732 %gep2 = getelementptr float* %phi2, i64 -1 733 store float %load1, float* %gep2 734 %load2 = load float* %phi1 735 store float %load2, float* %phi2 736 %dec.i = add nsw i64 %i, -1 737 %gep3 = getelementptr float* %phi2, i64 -2 738 %gep4 = getelementptr float* %phi1, i64 -2 739 %cond = icmp sgt i64 %dec.i, 0 740 br i1 %cond, label %for.body, label %end 741 end: 742 ret void 743 } 744 745 define void @post-indexed-sub-double(double* %a, double* %b, i64 %count) nounwind { 746 ; CHECK-LABEL: post-indexed-sub-double 747 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}], #-16 748 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}], #-16 749 br label %for.body 750 for.body: 751 %phi1 = phi double* [ %gep4, %for.body ], [ %b, %0 ] 752 %phi2 = phi double* [ %gep3, %for.body ], [ %a, %0 ] 753 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ] 754 %gep1 = getelementptr double* %phi1, i64 -1 755 %load1 = load double* %gep1 756 %gep2 = getelementptr double* %phi2, i64 -1 757 store double %load1, double* %gep2 758 %load2 = load double* %phi1 759 store double %load2, double* %phi2 760 %dec.i = add nsw i64 %i, -1 761 %gep3 = getelementptr double* %phi2, i64 -2 762 %gep4 = getelementptr double* %phi1, i64 -2 763 %cond = icmp sgt i64 %dec.i, 0 764 br i1 %cond, label %for.body, label %end 765 end: 766 ret void 767 } 768