Home | History | Annotate | Download | only in AArch64
      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