Home | History | Annotate | Download | only in WebAssembly
      1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -disable-wasm-fallthrough-return-opt | FileCheck %s
      2 
      3 ; Test constant load and store address offsets.
      4 
      5 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
      6 target triple = "wasm32-unknown-unknown"
      7 
      8 ;===----------------------------------------------------------------------------
      9 ; Loads: 32-bit
     10 ;===----------------------------------------------------------------------------
     11 
     12 ; Basic load.
     13 
     14 ; CHECK-LABEL: load_i32_no_offset:
     15 ; CHECK: i32.load $push0=, 0($0){{$}}
     16 ; CHECK-NEXT: return $pop0{{$}}
     17 define i32 @load_i32_no_offset(i32 *%p) {
     18   %v = load i32, i32* %p
     19   ret i32 %v
     20 }
     21 
     22 ; With an nuw add, we can fold an offset.
     23 
     24 ; CHECK-LABEL: load_i32_with_folded_offset:
     25 ; CHECK: i32.load  $push0=, 24($0){{$}}
     26 define i32 @load_i32_with_folded_offset(i32* %p) {
     27   %q = ptrtoint i32* %p to i32
     28   %r = add nuw i32 %q, 24
     29   %s = inttoptr i32 %r to i32*
     30   %t = load i32, i32* %s
     31   ret i32 %t
     32 }
     33 
     34 ; With an inbounds gep, we can fold an offset.
     35 
     36 ; CHECK-LABEL: load_i32_with_folded_gep_offset:
     37 ; CHECK: i32.load  $push0=, 24($0){{$}}
     38 define i32 @load_i32_with_folded_gep_offset(i32* %p) {
     39   %s = getelementptr inbounds i32, i32* %p, i32 6
     40   %t = load i32, i32* %s
     41   ret i32 %t
     42 }
     43 
     44 ; We can't fold a negative offset though, even with an inbounds gep.
     45 
     46 ; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
     47 ; CHECK: i32.const $push0=, -24{{$}}
     48 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
     49 ; CHECK: i32.load  $push2=, 0($pop1){{$}}
     50 define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {
     51   %s = getelementptr inbounds i32, i32* %p, i32 -6
     52   %t = load i32, i32* %s
     53   ret i32 %t
     54 }
     55 
     56 ; Without nuw, and even with nsw, we can't fold an offset.
     57 
     58 ; CHECK-LABEL: load_i32_with_unfolded_offset:
     59 ; CHECK: i32.const $push0=, 24{{$}}
     60 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
     61 ; CHECK: i32.load  $push2=, 0($pop1){{$}}
     62 define i32 @load_i32_with_unfolded_offset(i32* %p) {
     63   %q = ptrtoint i32* %p to i32
     64   %r = add nsw i32 %q, 24
     65   %s = inttoptr i32 %r to i32*
     66   %t = load i32, i32* %s
     67   ret i32 %t
     68 }
     69 
     70 ; Without inbounds, we can't fold a gep offset.
     71 
     72 ; CHECK-LABEL: load_i32_with_unfolded_gep_offset:
     73 ; CHECK: i32.const $push0=, 24{{$}}
     74 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
     75 ; CHECK: i32.load  $push2=, 0($pop1){{$}}
     76 define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {
     77   %s = getelementptr i32, i32* %p, i32 6
     78   %t = load i32, i32* %s
     79   ret i32 %t
     80 }
     81 
     82 ; When loading from a fixed address, materialize a zero.
     83 
     84 ; CHECK-LABEL: load_i32_from_numeric_address
     85 ; CHECK: i32.const $push0=, 0{{$}}
     86 ; CHECK: i32.load  $push1=, 42($pop0){{$}}
     87 define i32 @load_i32_from_numeric_address() {
     88   %s = inttoptr i32 42 to i32*
     89   %t = load i32, i32* %s
     90   ret i32 %t
     91 }
     92 
     93 ; CHECK-LABEL: load_i32_from_global_address
     94 ; CHECK: i32.const $push0=, 0{{$}}
     95 ; CHECK: i32.load  $push1=, gv($pop0){{$}}
     96 @gv = global i32 0
     97 define i32 @load_i32_from_global_address() {
     98   %t = load i32, i32* @gv
     99   ret i32 %t
    100 }
    101 
    102 ;===----------------------------------------------------------------------------
    103 ; Loads: 64-bit
    104 ;===----------------------------------------------------------------------------
    105 
    106 ; Basic load.
    107 
    108 ; CHECK-LABEL: load_i64_no_offset:
    109 ; CHECK: i64.load $push0=, 0($0){{$}}
    110 ; CHECK-NEXT: return $pop0{{$}}
    111 define i64 @load_i64_no_offset(i64 *%p) {
    112   %v = load i64, i64* %p
    113   ret i64 %v
    114 }
    115 
    116 ; With an nuw add, we can fold an offset.
    117 
    118 ; CHECK-LABEL: load_i64_with_folded_offset:
    119 ; CHECK: i64.load  $push0=, 24($0){{$}}
    120 define i64 @load_i64_with_folded_offset(i64* %p) {
    121   %q = ptrtoint i64* %p to i32
    122   %r = add nuw i32 %q, 24
    123   %s = inttoptr i32 %r to i64*
    124   %t = load i64, i64* %s
    125   ret i64 %t
    126 }
    127 
    128 ; With an inbounds gep, we can fold an offset.
    129 
    130 ; CHECK-LABEL: load_i64_with_folded_gep_offset:
    131 ; CHECK: i64.load  $push0=, 24($0){{$}}
    132 define i64 @load_i64_with_folded_gep_offset(i64* %p) {
    133   %s = getelementptr inbounds i64, i64* %p, i32 3
    134   %t = load i64, i64* %s
    135   ret i64 %t
    136 }
    137 
    138 ; We can't fold a negative offset though, even with an inbounds gep.
    139 
    140 ; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:
    141 ; CHECK: i32.const $push0=, -24{{$}}
    142 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    143 ; CHECK: i64.load  $push2=, 0($pop1){{$}}
    144 define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {
    145   %s = getelementptr inbounds i64, i64* %p, i32 -3
    146   %t = load i64, i64* %s
    147   ret i64 %t
    148 }
    149 
    150 ; Without nuw, and even with nsw, we can't fold an offset.
    151 
    152 ; CHECK-LABEL: load_i64_with_unfolded_offset:
    153 ; CHECK: i32.const $push0=, 24{{$}}
    154 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    155 ; CHECK: i64.load  $push2=, 0($pop1){{$}}
    156 define i64 @load_i64_with_unfolded_offset(i64* %p) {
    157   %q = ptrtoint i64* %p to i32
    158   %r = add nsw i32 %q, 24
    159   %s = inttoptr i32 %r to i64*
    160   %t = load i64, i64* %s
    161   ret i64 %t
    162 }
    163 
    164 ; Without inbounds, we can't fold a gep offset.
    165 
    166 ; CHECK-LABEL: load_i64_with_unfolded_gep_offset:
    167 ; CHECK: i32.const $push0=, 24{{$}}
    168 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    169 ; CHECK: i64.load  $push2=, 0($pop1){{$}}
    170 define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {
    171   %s = getelementptr i64, i64* %p, i32 3
    172   %t = load i64, i64* %s
    173   ret i64 %t
    174 }
    175 
    176 ;===----------------------------------------------------------------------------
    177 ; Stores: 32-bit
    178 ;===----------------------------------------------------------------------------
    179 
    180 ; Basic store.
    181 
    182 ; CHECK-LABEL: store_i32_no_offset:
    183 ; CHECK-NEXT: .param i32, i32{{$}}
    184 ; CHECK-NEXT: i32.store 0($0), $1{{$}}
    185 ; CHECK-NEXT: return{{$}}
    186 define void @store_i32_no_offset(i32 *%p, i32 %v) {
    187   store i32 %v, i32* %p
    188   ret void
    189 }
    190 
    191 ; With an nuw add, we can fold an offset.
    192 
    193 ; CHECK-LABEL: store_i32_with_folded_offset:
    194 ; CHECK: i32.store 24($0), $pop0{{$}}
    195 define void @store_i32_with_folded_offset(i32* %p) {
    196   %q = ptrtoint i32* %p to i32
    197   %r = add nuw i32 %q, 24
    198   %s = inttoptr i32 %r to i32*
    199   store i32 0, i32* %s
    200   ret void
    201 }
    202 
    203 ; With an inbounds gep, we can fold an offset.
    204 
    205 ; CHECK-LABEL: store_i32_with_folded_gep_offset:
    206 ; CHECK: i32.store 24($0), $pop0{{$}}
    207 define void @store_i32_with_folded_gep_offset(i32* %p) {
    208   %s = getelementptr inbounds i32, i32* %p, i32 6
    209   store i32 0, i32* %s
    210   ret void
    211 }
    212 
    213 ; We can't fold a negative offset though, even with an inbounds gep.
    214 
    215 ; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:
    216 ; CHECK: i32.const $push0=, -24{{$}}
    217 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    218 ; CHECK: i32.store 0($pop1), $pop2{{$}}
    219 define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
    220   %s = getelementptr inbounds i32, i32* %p, i32 -6
    221   store i32 0, i32* %s
    222   ret void
    223 }
    224 
    225 ; Without nuw, and even with nsw, we can't fold an offset.
    226 
    227 ; CHECK-LABEL: store_i32_with_unfolded_offset:
    228 ; CHECK: i32.const $push0=, 24{{$}}
    229 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    230 ; CHECK: i32.store 0($pop1), $pop2{{$}}
    231 define void @store_i32_with_unfolded_offset(i32* %p) {
    232   %q = ptrtoint i32* %p to i32
    233   %r = add nsw i32 %q, 24
    234   %s = inttoptr i32 %r to i32*
    235   store i32 0, i32* %s
    236   ret void
    237 }
    238 
    239 ; Without inbounds, we can't fold a gep offset.
    240 
    241 ; CHECK-LABEL: store_i32_with_unfolded_gep_offset:
    242 ; CHECK: i32.const $push0=, 24{{$}}
    243 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    244 ; CHECK: i32.store 0($pop1), $pop2{{$}}
    245 define void @store_i32_with_unfolded_gep_offset(i32* %p) {
    246   %s = getelementptr i32, i32* %p, i32 6
    247   store i32 0, i32* %s
    248   ret void
    249 }
    250 
    251 ; When storing from a fixed address, materialize a zero.
    252 
    253 ; CHECK-LABEL: store_i32_to_numeric_address:
    254 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
    255 ; CHECK-NEXT: i32.const $push1=, 0{{$}}
    256 ; CHECK-NEXT: i32.store 42($pop0), $pop1{{$}}
    257 define void @store_i32_to_numeric_address() {
    258   %s = inttoptr i32 42 to i32*
    259   store i32 0, i32* %s
    260   ret void
    261 }
    262 
    263 ; CHECK-LABEL: store_i32_to_global_address:
    264 ; CHECK: i32.const $push0=, 0{{$}}
    265 ; CHECK: i32.const $push1=, 0{{$}}
    266 ; CHECK: i32.store gv($pop0), $pop1{{$}}
    267 define void @store_i32_to_global_address() {
    268   store i32 0, i32* @gv
    269   ret void
    270 }
    271 
    272 ;===----------------------------------------------------------------------------
    273 ; Stores: 64-bit
    274 ;===----------------------------------------------------------------------------
    275 
    276 ; Basic store.
    277 
    278 ; CHECK-LABEL: store_i64_with_folded_offset:
    279 ; CHECK: i64.store 24($0), $pop0{{$}}
    280 define void @store_i64_with_folded_offset(i64* %p) {
    281   %q = ptrtoint i64* %p to i32
    282   %r = add nuw i32 %q, 24
    283   %s = inttoptr i32 %r to i64*
    284   store i64 0, i64* %s
    285   ret void
    286 }
    287 
    288 ; With an nuw add, we can fold an offset.
    289 
    290 ; CHECK-LABEL: store_i64_with_folded_gep_offset:
    291 ; CHECK: i64.store 24($0), $pop0{{$}}
    292 define void @store_i64_with_folded_gep_offset(i64* %p) {
    293   %s = getelementptr inbounds i64, i64* %p, i32 3
    294   store i64 0, i64* %s
    295   ret void
    296 }
    297 
    298 ; With an inbounds gep, we can fold an offset.
    299 
    300 ; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:
    301 ; CHECK: i32.const $push0=, -24{{$}}
    302 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    303 ; CHECK: i64.store 0($pop1), $pop2{{$}}
    304 define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
    305   %s = getelementptr inbounds i64, i64* %p, i32 -3
    306   store i64 0, i64* %s
    307   ret void
    308 }
    309 
    310 ; We can't fold a negative offset though, even with an inbounds gep.
    311 
    312 ; CHECK-LABEL: store_i64_with_unfolded_offset:
    313 ; CHECK: i32.const $push0=, 24{{$}}
    314 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    315 ; CHECK: i64.store 0($pop1), $pop2{{$}}
    316 define void @store_i64_with_unfolded_offset(i64* %p) {
    317   %q = ptrtoint i64* %p to i32
    318   %r = add nsw i32 %q, 24
    319   %s = inttoptr i32 %r to i64*
    320   store i64 0, i64* %s
    321   ret void
    322 }
    323 
    324 ; Without nuw, and even with nsw, we can't fold an offset.
    325 
    326 ; CHECK-LABEL: store_i64_with_unfolded_gep_offset:
    327 ; CHECK: i32.const $push0=, 24{{$}}
    328 ; CHECK: i32.add   $push1=, $0, $pop0{{$}}
    329 ; CHECK: i64.store 0($pop1), $pop2{{$}}
    330 define void @store_i64_with_unfolded_gep_offset(i64* %p) {
    331   %s = getelementptr i64, i64* %p, i32 3
    332   store i64 0, i64* %s
    333   ret void
    334 }
    335 
    336 ; Without inbounds, we can't fold a gep offset.
    337 
    338 ; CHECK-LABEL: store_i32_with_folded_or_offset:
    339 ; CHECK: i32.store8 2($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
    340 define void @store_i32_with_folded_or_offset(i32 %x) {
    341   %and = and i32 %x, -4
    342   %t0 = inttoptr i32 %and to i8*
    343   %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
    344   store i8 0, i8* %arrayidx, align 1
    345   ret void
    346 }
    347 
    348 ;===----------------------------------------------------------------------------
    349 ; Sign-extending loads
    350 ;===----------------------------------------------------------------------------
    351 
    352 ; Fold an offset into a sign-extending load.
    353 
    354 ; CHECK-LABEL: load_i8_i32_s_with_folded_offset:
    355 ; CHECK: i32.load8_s $push0=, 24($0){{$}}
    356 define i32 @load_i8_i32_s_with_folded_offset(i8* %p) {
    357   %q = ptrtoint i8* %p to i32
    358   %r = add nuw i32 %q, 24
    359   %s = inttoptr i32 %r to i8*
    360   %t = load i8, i8* %s
    361   %u = sext i8 %t to i32
    362   ret i32 %u
    363 }
    364 
    365 ; CHECK-LABEL: load_i32_i64_s_with_folded_offset:
    366 ; CHECK: i64.load32_s $push0=, 24($0){{$}}
    367 define i64 @load_i32_i64_s_with_folded_offset(i32* %p) {
    368   %q = ptrtoint i32* %p to i32
    369   %r = add nuw i32 %q, 24
    370   %s = inttoptr i32 %r to i32*
    371   %t = load i32, i32* %s
    372   %u = sext i32 %t to i64
    373   ret i64 %u
    374 }
    375 
    376 ; Fold a gep offset into a sign-extending load.
    377 
    378 ; CHECK-LABEL: load_i8_i32_s_with_folded_gep_offset:
    379 ; CHECK: i32.load8_s $push0=, 24($0){{$}}
    380 define i32 @load_i8_i32_s_with_folded_gep_offset(i8* %p) {
    381   %s = getelementptr inbounds i8, i8* %p, i32 24
    382   %t = load i8, i8* %s
    383   %u = sext i8 %t to i32
    384   ret i32 %u
    385 }
    386 
    387 ; CHECK-LABEL: load_i16_i32_s_with_folded_gep_offset:
    388 ; CHECK: i32.load16_s $push0=, 48($0){{$}}
    389 define i32 @load_i16_i32_s_with_folded_gep_offset(i16* %p) {
    390   %s = getelementptr inbounds i16, i16* %p, i32 24
    391   %t = load i16, i16* %s
    392   %u = sext i16 %t to i32
    393   ret i32 %u
    394 }
    395 
    396 ; CHECK-LABEL: load_i16_i64_s_with_folded_gep_offset:
    397 ; CHECK: i64.load16_s $push0=, 48($0){{$}}
    398 define i64 @load_i16_i64_s_with_folded_gep_offset(i16* %p) {
    399   %s = getelementptr inbounds i16, i16* %p, i32 24
    400   %t = load i16, i16* %s
    401   %u = sext i16 %t to i64
    402   ret i64 %u
    403 }
    404 
    405 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
    406 ; an 'add' if the or'ed bits are known to be zero.
    407 
    408 ; CHECK-LABEL: load_i8_i32_s_with_folded_or_offset:
    409 ; CHECK: i32.load8_s $push{{[0-9]+}}=, 2($pop{{[0-9]+}}){{$}}
    410 define i32 @load_i8_i32_s_with_folded_or_offset(i32 %x) {
    411   %and = and i32 %x, -4
    412   %t0 = inttoptr i32 %and to i8*
    413   %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
    414   %t1 = load i8, i8* %arrayidx
    415   %conv = sext i8 %t1 to i32
    416   ret i32 %conv
    417 }
    418 
    419 ; CHECK-LABEL: load_i8_i64_s_with_folded_or_offset:
    420 ; CHECK: i64.load8_s $push{{[0-9]+}}=, 2($pop{{[0-9]+}}){{$}}
    421 define i64 @load_i8_i64_s_with_folded_or_offset(i32 %x) {
    422   %and = and i32 %x, -4
    423   %t0 = inttoptr i32 %and to i8*
    424   %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
    425   %t1 = load i8, i8* %arrayidx
    426   %conv = sext i8 %t1 to i64
    427   ret i64 %conv
    428 }
    429 
    430 ; When loading from a fixed address, materialize a zero.
    431 
    432 ; CHECK-LABEL: load_i16_i32_s_from_numeric_address
    433 ; CHECK: i32.const $push0=, 0{{$}}
    434 ; CHECK: i32.load16_s  $push1=, 42($pop0){{$}}
    435 define i32 @load_i16_i32_s_from_numeric_address() {
    436   %s = inttoptr i32 42 to i16*
    437   %t = load i16, i16* %s
    438   %u = sext i16 %t to i32
    439   ret i32 %u
    440 }
    441 
    442 ; CHECK-LABEL: load_i8_i32_s_from_global_address
    443 ; CHECK: i32.const $push0=, 0{{$}}
    444 ; CHECK: i32.load8_s  $push1=, gv8($pop0){{$}}
    445 @gv8 = global i8 0
    446 define i32 @load_i8_i32_s_from_global_address() {
    447   %t = load i8, i8* @gv8
    448   %u = sext i8 %t to i32
    449   ret i32 %u
    450 }
    451 
    452 ;===----------------------------------------------------------------------------
    453 ; Zero-extending loads
    454 ;===----------------------------------------------------------------------------
    455 
    456 ; Fold an offset into a zero-extending load.
    457 
    458 ; CHECK-LABEL: load_i8_i32_z_with_folded_offset:
    459 ; CHECK: i32.load8_u $push0=, 24($0){{$}}
    460 define i32 @load_i8_i32_z_with_folded_offset(i8* %p) {
    461   %q = ptrtoint i8* %p to i32
    462   %r = add nuw i32 %q, 24
    463   %s = inttoptr i32 %r to i8*
    464   %t = load i8, i8* %s
    465   %u = zext i8 %t to i32
    466   ret i32 %u
    467 }
    468 
    469 ; CHECK-LABEL: load_i32_i64_z_with_folded_offset:
    470 ; CHECK: i64.load32_u $push0=, 24($0){{$}}
    471 define i64 @load_i32_i64_z_with_folded_offset(i32* %p) {
    472   %q = ptrtoint i32* %p to i32
    473   %r = add nuw i32 %q, 24
    474   %s = inttoptr i32 %r to i32*
    475   %t = load i32, i32* %s
    476   %u = zext i32 %t to i64
    477   ret i64 %u
    478 }
    479 
    480 ; Fold a gep offset into a zero-extending load.
    481 
    482 ; CHECK-LABEL: load_i8_i32_z_with_folded_gep_offset:
    483 ; CHECK: i32.load8_u $push0=, 24($0){{$}}
    484 define i32 @load_i8_i32_z_with_folded_gep_offset(i8* %p) {
    485   %s = getelementptr inbounds i8, i8* %p, i32 24
    486   %t = load i8, i8* %s
    487   %u = zext i8 %t to i32
    488   ret i32 %u
    489 }
    490 
    491 ; CHECK-LABEL: load_i16_i32_z_with_folded_gep_offset:
    492 ; CHECK: i32.load16_u $push0=, 48($0){{$}}
    493 define i32 @load_i16_i32_z_with_folded_gep_offset(i16* %p) {
    494   %s = getelementptr inbounds i16, i16* %p, i32 24
    495   %t = load i16, i16* %s
    496   %u = zext i16 %t to i32
    497   ret i32 %u
    498 }
    499 
    500 ; CHECK-LABEL: load_i16_i64_z_with_folded_gep_offset:
    501 ; CHECK: i64.load16_u $push0=, 48($0){{$}}
    502 define i64 @load_i16_i64_z_with_folded_gep_offset(i16* %p) {
    503   %s = getelementptr inbounds i16, i16* %p, i64 24
    504   %t = load i16, i16* %s
    505   %u = zext i16 %t to i64
    506   ret i64 %u
    507 }
    508 
    509 ; When loading from a fixed address, materialize a zero.
    510 
    511 ; CHECK-LABEL: load_i16_i32_z_from_numeric_address
    512 ; CHECK: i32.const $push0=, 0{{$}}
    513 ; CHECK: i32.load16_u  $push1=, 42($pop0){{$}}
    514 define i32 @load_i16_i32_z_from_numeric_address() {
    515   %s = inttoptr i32 42 to i16*
    516   %t = load i16, i16* %s
    517   %u = zext i16 %t to i32
    518   ret i32 %u
    519 }
    520 
    521 ; CHECK-LABEL: load_i8_i32_z_from_global_address
    522 ; CHECK: i32.const $push0=, 0{{$}}
    523 ; CHECK: i32.load8_u  $push1=, gv8($pop0){{$}}
    524 define i32 @load_i8_i32_z_from_global_address() {
    525   %t = load i8, i8* @gv8
    526   %u = zext i8 %t to i32
    527   ret i32 %u
    528 }
    529 
    530 ; i8 return value should test anyext loads
    531 ; CHECK-LABEL: load_i8_i32_retvalue:
    532 ; CHECK: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
    533 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
    534 define i8 @load_i8_i32_retvalue(i8 *%p) {
    535   %v = load i8, i8* %p
    536   ret i8 %v
    537 }
    538 
    539 ;===----------------------------------------------------------------------------
    540 ; Truncating stores
    541 ;===----------------------------------------------------------------------------
    542 
    543 ; Fold an offset into a truncating store.
    544 
    545 ; CHECK-LABEL: store_i8_i32_with_folded_offset:
    546 ; CHECK: i32.store8 24($0), $1{{$}}
    547 define void @store_i8_i32_with_folded_offset(i8* %p, i32 %v) {
    548   %q = ptrtoint i8* %p to i32
    549   %r = add nuw i32 %q, 24
    550   %s = inttoptr i32 %r to i8*
    551   %t = trunc i32 %v to i8
    552   store i8 %t, i8* %s
    553   ret void
    554 }
    555 
    556 ; CHECK-LABEL: store_i32_i64_with_folded_offset:
    557 ; CHECK: i64.store32 24($0), $1{{$}}
    558 define void @store_i32_i64_with_folded_offset(i32* %p, i64 %v) {
    559   %q = ptrtoint i32* %p to i32
    560   %r = add nuw i32 %q, 24
    561   %s = inttoptr i32 %r to i32*
    562   %t = trunc i64 %v to i32
    563   store i32 %t, i32* %s
    564   ret void
    565 }
    566 
    567 ; Fold a gep offset into a truncating store.
    568 
    569 ; CHECK-LABEL: store_i8_i32_with_folded_gep_offset:
    570 ; CHECK: i32.store8 24($0), $1{{$}}
    571 define void @store_i8_i32_with_folded_gep_offset(i8* %p, i32 %v) {
    572   %s = getelementptr inbounds i8, i8* %p, i32 24
    573   %t = trunc i32 %v to i8
    574   store i8 %t, i8* %s
    575   ret void
    576 }
    577 
    578 ; CHECK-LABEL: store_i16_i32_with_folded_gep_offset:
    579 ; CHECK: i32.store16 48($0), $1{{$}}
    580 define void @store_i16_i32_with_folded_gep_offset(i16* %p, i32 %v) {
    581   %s = getelementptr inbounds i16, i16* %p, i32 24
    582   %t = trunc i32 %v to i16
    583   store i16 %t, i16* %s
    584   ret void
    585 }
    586 
    587 ; CHECK-LABEL: store_i16_i64_with_folded_gep_offset:
    588 ; CHECK: i64.store16 48($0), $1{{$}}
    589 define void @store_i16_i64_with_folded_gep_offset(i16* %p, i64 %v) {
    590   %s = getelementptr inbounds i16, i16* %p, i64 24
    591   %t = trunc i64 %v to i16
    592   store i16 %t, i16* %s
    593   ret void
    594 }
    595 
    596 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
    597 ; an 'add' if the or'ed bits are known to be zero.
    598 
    599 ; CHECK-LABEL: store_i8_i32_with_folded_or_offset:
    600 ; CHECK: i32.store8 2($pop{{[0-9]+}}), $1{{$}}
    601 define void @store_i8_i32_with_folded_or_offset(i32 %x, i32 %v) {
    602   %and = and i32 %x, -4
    603   %p = inttoptr i32 %and to i8*
    604   %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
    605   %t = trunc i32 %v to i8
    606   store i8 %t, i8* %arrayidx
    607   ret void
    608 }
    609 
    610 ; CHECK-LABEL: store_i8_i64_with_folded_or_offset:
    611 ; CHECK: i64.store8 2($pop{{[0-9]+}}), $1{{$}}
    612 define void @store_i8_i64_with_folded_or_offset(i32 %x, i64 %v) {
    613   %and = and i32 %x, -4
    614   %p = inttoptr i32 %and to i8*
    615   %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
    616   %t = trunc i64 %v to i8
    617   store i8 %t, i8* %arrayidx
    618   ret void
    619 }
    620 
    621 ;===----------------------------------------------------------------------------
    622 ; Aggregate values
    623 ;===----------------------------------------------------------------------------
    624 
    625 ; Fold the offsets when lowering aggregate loads and stores.
    626 
    627 ; CHECK-LABEL: aggregate_load_store:
    628 ; CHECK: i32.load  $2=, 0($0){{$}}
    629 ; CHECK: i32.load  $3=, 4($0){{$}}
    630 ; CHECK: i32.load  $4=, 8($0){{$}}
    631 ; CHECK: i32.load  $push0=, 12($0){{$}}
    632 ; CHECK: i32.store 12($1), $pop0{{$}}
    633 ; CHECK: i32.store 8($1), $4{{$}}
    634 ; CHECK: i32.store 4($1), $3{{$}}
    635 ; CHECK: i32.store 0($1), $2{{$}}
    636 define void @aggregate_load_store({i32,i32,i32,i32}* %p, {i32,i32,i32,i32}* %q) {
    637   ; volatile so that things stay in order for the tests above
    638   %t = load volatile {i32,i32,i32,i32}, {i32, i32,i32,i32}* %p
    639   store volatile {i32,i32,i32,i32} %t, {i32, i32,i32,i32}* %q
    640   ret void
    641 }
    642 
    643 ; Fold the offsets when lowering aggregate return values. The stores get
    644 ; merged into i64 stores.
    645 
    646 ; CHECK-LABEL: aggregate_return:
    647 ; CHECK: i64.const   $push[[L0:[0-9]+]]=, 0{{$}}
    648 ; CHECK: i64.store   8($0):p2align=2, $pop[[L0]]{{$}}
    649 ; CHECK: i64.const   $push[[L1:[0-9]+]]=, 0{{$}}
    650 ; CHECK: i64.store   0($0):p2align=2, $pop[[L1]]{{$}}
    651 define {i32,i32,i32,i32} @aggregate_return() {
    652   ret {i32,i32,i32,i32} zeroinitializer
    653 }
    654 
    655 ; Fold the offsets when lowering aggregate return values. The stores are not
    656 ; merged.
    657 
    658 ; CHECK-LABEL: aggregate_return_without_merge:
    659 ; CHECK: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
    660 ; CHECK: i32.store8  14($0), $pop[[L0]]{{$}}
    661 ; CHECK: i32.const   $push[[L1:[0-9]+]]=, 0{{$}}
    662 ; CHECK: i32.store16 12($0), $pop[[L1]]{{$}}
    663 ; CHECK: i32.const   $push[[L2:[0-9]+]]=, 0{{$}}
    664 ; CHECK: i32.store   8($0), $pop[[L2]]{{$}}
    665 ; CHECK: i64.const   $push[[L3:[0-9]+]]=, 0{{$}}
    666 ; CHECK: i64.store   0($0), $pop[[L3]]{{$}}
    667 define {i64,i32,i16,i8} @aggregate_return_without_merge() {
    668   ret {i64,i32,i16,i8} zeroinitializer
    669 }
    670