brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.1 KiB · 109607c Raw
752 lines · plain
1; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -disable-wasm-fallthrough-return-opt -mattr=+fp16 | FileCheck %s2 3; Test constant load and store address offsets.4 5target triple = "wasm32-unknown-unknown"6 7;===----------------------------------------------------------------------------8; Loads: 32-bit9;===----------------------------------------------------------------------------10 11; Basic load.12 13; CHECK-LABEL: load_i32_no_offset:14; CHECK: i32.load $push0=, 0($0){{$}}15; CHECK-NEXT: return $pop0{{$}}16define i32 @load_i32_no_offset(ptr %p) {17  %v = load i32, ptr %p18  ret i32 %v19}20 21; With an nuw add, we can fold an offset.22 23; CHECK-LABEL: load_i32_with_folded_offset:24; CHECK: i32.load  $push0=, 24($0){{$}}25define i32 @load_i32_with_folded_offset(ptr %p) {26  %q = ptrtoint ptr %p to i3227  %r = add nuw i32 %q, 2428  %s = inttoptr i32 %r to ptr29  %t = load i32, ptr %s30  ret i32 %t31}32 33; With an inbounds gep, we can fold an offset.34 35; CHECK-LABEL: load_i32_with_folded_gep_offset:36; CHECK: i32.load  $push0=, 24($0){{$}}37define i32 @load_i32_with_folded_gep_offset(ptr %p) {38  %s = getelementptr inbounds i32, ptr %p, i32 639  %t = load i32, ptr %s40  ret i32 %t41}42 43; Same for nusw.44 45; CHECK-LABEL: load_i32_with_folded_gep_offset_nusw:46; CHECK: i32.load  $push0=, 24($0){{$}}47define i32 @load_i32_with_folded_gep_offset_nusw(ptr %p) {48  %s = getelementptr nusw i32, ptr %p, i32 649  %t = load i32, ptr %s50  ret i32 %t51}52 53; For nuw we don't need the offset to be positive.54 55; CHECK-LABEL: load_i32_with_folded_gep_offset_nuw:56; CHECK: i32.load  $push0=, -24($0){{$}}57define i32 @load_i32_with_folded_gep_offset_nuw(ptr %p) {58  %s = getelementptr nuw i32, ptr %p, i32 -659  %t = load i32, ptr %s60  ret i32 %t61}62 63; We can't fold a negative offset though, even with an inbounds gep.64 65; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:66; CHECK: i32.const $push0=, -24{{$}}67; CHECK: i32.add   $push1=, $0, $pop0{{$}}68; CHECK: i32.load  $push2=, 0($pop1){{$}}69define i32 @load_i32_with_unfolded_gep_negative_offset(ptr %p) {70  %s = getelementptr inbounds i32, ptr %p, i32 -671  %t = load i32, ptr %s72  ret i32 %t73}74 75; Without nuw, and even with nsw, we can't fold an offset.76 77; CHECK-LABEL: load_i32_with_unfolded_offset:78; CHECK: i32.const $push0=, 24{{$}}79; CHECK: i32.add   $push1=, $0, $pop0{{$}}80; CHECK: i32.load  $push2=, 0($pop1){{$}}81define i32 @load_i32_with_unfolded_offset(ptr %p) {82  %q = ptrtoint ptr %p to i3283  %r = add nsw i32 %q, 2484  %s = inttoptr i32 %r to ptr85  %t = load i32, ptr %s86  ret i32 %t87}88 89; Without inbounds, we can't fold a gep offset.90 91; CHECK-LABEL: load_i32_with_unfolded_gep_offset:92; CHECK: i32.const $push0=, 24{{$}}93; CHECK: i32.add   $push1=, $0, $pop0{{$}}94; CHECK: i32.load  $push2=, 0($pop1){{$}}95define i32 @load_i32_with_unfolded_gep_offset(ptr %p) {96  %s = getelementptr i32, ptr %p, i32 697  %t = load i32, ptr %s98  ret i32 %t99}100 101; When loading from a fixed address, materialize a zero.102 103; CHECK-LABEL: load_i32_from_numeric_address104; CHECK: i32.const $push0=, 0{{$}}105; CHECK: i32.load  $push1=, 42($pop0){{$}}106define i32 @load_i32_from_numeric_address() {107  %s = inttoptr i32 42 to ptr108  %t = load i32, ptr %s109  ret i32 %t110}111 112; CHECK-LABEL: load_i32_from_global_address113; CHECK: i32.const $push0=, 0{{$}}114; CHECK: i32.load  $push1=, gv($pop0){{$}}115@gv = global i32 0116define i32 @load_i32_from_global_address() {117  %t = load i32, ptr @gv118  ret i32 %t119}120 121define i32 @load_i32_global_with_folded_gep_offset_nonconst_nuw(i32 %idx) {122; CHECK-LABEL: load_i32_global_with_folded_gep_offset_nonconst_nuw:123; CHECK: i32.const $push0=, 2124; CHECK: i32.shl $push1=, $0, $pop0125; CHECK: i32.load $push2=, gv($pop1)126  %s = getelementptr nuw i32, ptr @gv, i32 %idx127  %t = load i32, ptr %s128  ret i32 %t129}130 131;===----------------------------------------------------------------------------132; Loads: 64-bit133;===----------------------------------------------------------------------------134 135; Basic load.136 137; CHECK-LABEL: load_i64_no_offset:138; CHECK: i64.load $push0=, 0($0){{$}}139; CHECK-NEXT: return $pop0{{$}}140define i64 @load_i64_no_offset(ptr %p) {141  %v = load i64, ptr %p142  ret i64 %v143}144 145; With an nuw add, we can fold an offset.146 147; CHECK-LABEL: load_i64_with_folded_offset:148; CHECK: i64.load  $push0=, 24($0){{$}}149define i64 @load_i64_with_folded_offset(ptr %p) {150  %q = ptrtoint ptr %p to i32151  %r = add nuw i32 %q, 24152  %s = inttoptr i32 %r to ptr153  %t = load i64, ptr %s154  ret i64 %t155}156 157; With an inbounds gep, we can fold an offset.158 159; CHECK-LABEL: load_i64_with_folded_gep_offset:160; CHECK: i64.load  $push0=, 24($0){{$}}161define i64 @load_i64_with_folded_gep_offset(ptr %p) {162  %s = getelementptr inbounds i64, ptr %p, i32 3163  %t = load i64, ptr %s164  ret i64 %t165}166 167; We can't fold a negative offset though, even with an inbounds gep.168 169; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:170; CHECK: i32.const $push0=, -24{{$}}171; CHECK: i32.add   $push1=, $0, $pop0{{$}}172; CHECK: i64.load  $push2=, 0($pop1){{$}}173define i64 @load_i64_with_unfolded_gep_negative_offset(ptr %p) {174  %s = getelementptr inbounds i64, ptr %p, i32 -3175  %t = load i64, ptr %s176  ret i64 %t177}178 179; Without nuw, and even with nsw, we can't fold an offset.180 181; CHECK-LABEL: load_i64_with_unfolded_offset:182; CHECK: i32.const $push0=, 24{{$}}183; CHECK: i32.add   $push1=, $0, $pop0{{$}}184; CHECK: i64.load  $push2=, 0($pop1){{$}}185define i64 @load_i64_with_unfolded_offset(ptr %p) {186  %q = ptrtoint ptr %p to i32187  %r = add nsw i32 %q, 24188  %s = inttoptr i32 %r to ptr189  %t = load i64, ptr %s190  ret i64 %t191}192 193; Without inbounds, we can't fold a gep offset.194 195; CHECK-LABEL: load_i64_with_unfolded_gep_offset:196; CHECK: i32.const $push0=, 24{{$}}197; CHECK: i32.add   $push1=, $0, $pop0{{$}}198; CHECK: i64.load  $push2=, 0($pop1){{$}}199define i64 @load_i64_with_unfolded_gep_offset(ptr %p) {200  %s = getelementptr i64, ptr %p, i32 3201  %t = load i64, ptr %s202  ret i64 %t203}204 205;===----------------------------------------------------------------------------206; Stores: 32-bit207;===----------------------------------------------------------------------------208 209; Basic store.210 211; CHECK-LABEL: store_i32_no_offset:212; CHECK-NEXT: .functype store_i32_no_offset (i32, i32) -> (){{$}}213; CHECK-NEXT: i32.store 0($0), $1{{$}}214; CHECK-NEXT: return{{$}}215define void @store_i32_no_offset(ptr %p, i32 %v) {216  store i32 %v, ptr %p217  ret void218}219 220; With an nuw add, we can fold an offset.221 222; CHECK-LABEL: store_i32_with_folded_offset:223; CHECK: i32.store 24($0), $pop0{{$}}224define void @store_i32_with_folded_offset(ptr %p) {225  %q = ptrtoint ptr %p to i32226  %r = add nuw i32 %q, 24227  %s = inttoptr i32 %r to ptr228  store i32 0, ptr %s229  ret void230}231 232; With an inbounds gep, we can fold an offset.233 234; CHECK-LABEL: store_i32_with_folded_gep_offset:235; CHECK: i32.store 24($0), $pop0{{$}}236define void @store_i32_with_folded_gep_offset(ptr %p) {237  %s = getelementptr inbounds i32, ptr %p, i32 6238  store i32 0, ptr %s239  ret void240}241 242; We can't fold a negative offset though, even with an inbounds gep.243 244; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:245; CHECK: i32.const $push0=, -24{{$}}246; CHECK: i32.add   $push1=, $0, $pop0{{$}}247; CHECK: i32.store 0($pop1), $pop2{{$}}248define void @store_i32_with_unfolded_gep_negative_offset(ptr %p) {249  %s = getelementptr inbounds i32, ptr %p, i32 -6250  store i32 0, ptr %s251  ret void252}253 254; Without nuw, and even with nsw, we can't fold an offset.255 256; CHECK-LABEL: store_i32_with_unfolded_offset:257; CHECK: i32.const $push0=, 24{{$}}258; CHECK: i32.add   $push1=, $0, $pop0{{$}}259; CHECK: i32.store 0($pop1), $pop2{{$}}260define void @store_i32_with_unfolded_offset(ptr %p) {261  %q = ptrtoint ptr %p to i32262  %r = add nsw i32 %q, 24263  %s = inttoptr i32 %r to ptr264  store i32 0, ptr %s265  ret void266}267 268; Without inbounds, we can't fold a gep offset.269 270; CHECK-LABEL: store_i32_with_unfolded_gep_offset:271; CHECK: i32.const $push0=, 24{{$}}272; CHECK: i32.add   $push1=, $0, $pop0{{$}}273; CHECK: i32.store 0($pop1), $pop2{{$}}274define void @store_i32_with_unfolded_gep_offset(ptr %p) {275  %s = getelementptr i32, ptr %p, i32 6276  store i32 0, ptr %s277  ret void278}279 280; When storing from a fixed address, materialize a zero.281 282; CHECK-LABEL: store_i32_to_numeric_address:283; CHECK:      i32.const $push0=, 0{{$}}284; CHECK-NEXT: i32.const $push1=, 0{{$}}285; CHECK-NEXT: i32.store 42($pop0), $pop1{{$}}286define void @store_i32_to_numeric_address() {287  %s = inttoptr i32 42 to ptr288  store i32 0, ptr %s289  ret void290}291 292; CHECK-LABEL: store_i32_to_global_address:293; CHECK: i32.const $push0=, 0{{$}}294; CHECK: i32.const $push1=, 0{{$}}295; CHECK: i32.store gv($pop0), $pop1{{$}}296define void @store_i32_to_global_address() {297  store i32 0, ptr @gv298  ret void299}300 301;===----------------------------------------------------------------------------302; Stores: 64-bit303;===----------------------------------------------------------------------------304 305; Basic store.306 307; CHECK-LABEL: store_i64_with_folded_offset:308; CHECK: i64.store 24($0), $pop0{{$}}309define void @store_i64_with_folded_offset(ptr %p) {310  %q = ptrtoint ptr %p to i32311  %r = add nuw i32 %q, 24312  %s = inttoptr i32 %r to ptr313  store i64 0, ptr %s314  ret void315}316 317; With an nuw add, we can fold an offset.318 319; CHECK-LABEL: store_i64_with_folded_gep_offset:320; CHECK: i64.store 24($0), $pop0{{$}}321define void @store_i64_with_folded_gep_offset(ptr %p) {322  %s = getelementptr inbounds i64, ptr %p, i32 3323  store i64 0, ptr %s324  ret void325}326 327; With an inbounds gep, we can fold an offset.328 329; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:330; CHECK: i32.const $push0=, -24{{$}}331; CHECK: i32.add   $push1=, $0, $pop0{{$}}332; CHECK: i64.store 0($pop1), $pop2{{$}}333define void @store_i64_with_unfolded_gep_negative_offset(ptr %p) {334  %s = getelementptr inbounds i64, ptr %p, i32 -3335  store i64 0, ptr %s336  ret void337}338 339; We can't fold a negative offset though, even with an inbounds gep.340 341; CHECK-LABEL: store_i64_with_unfolded_offset:342; CHECK: i32.const $push0=, 24{{$}}343; CHECK: i32.add   $push1=, $0, $pop0{{$}}344; CHECK: i64.store 0($pop1), $pop2{{$}}345define void @store_i64_with_unfolded_offset(ptr %p) {346  %q = ptrtoint ptr %p to i32347  %r = add nsw i32 %q, 24348  %s = inttoptr i32 %r to ptr349  store i64 0, ptr %s350  ret void351}352 353; Without nuw, and even with nsw, we can't fold an offset.354 355; CHECK-LABEL: store_i64_with_unfolded_gep_offset:356; CHECK: i32.const $push0=, 24{{$}}357; CHECK: i32.add   $push1=, $0, $pop0{{$}}358; CHECK: i64.store 0($pop1), $pop2{{$}}359define void @store_i64_with_unfolded_gep_offset(ptr %p) {360  %s = getelementptr i64, ptr %p, i32 3361  store i64 0, ptr %s362  ret void363}364 365; Without inbounds, we can't fold a gep offset.366 367; CHECK-LABEL: store_i32_with_folded_or_offset:368; CHECK: i32.store8 2($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}369define void @store_i32_with_folded_or_offset(i32 %x) {370  %and = and i32 %x, -4371  %t0 = inttoptr i32 %and to ptr372  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2373  store i8 0, ptr %arrayidx, align 1374  ret void375}376 377;===----------------------------------------------------------------------------378; Sign-extending loads379;===----------------------------------------------------------------------------380 381; Fold an offset into a sign-extending load.382 383; CHECK-LABEL: load_i8_i32_s_with_folded_offset:384; CHECK: i32.load8_s $push0=, 24($0){{$}}385define i32 @load_i8_i32_s_with_folded_offset(ptr %p) {386  %q = ptrtoint ptr %p to i32387  %r = add nuw i32 %q, 24388  %s = inttoptr i32 %r to ptr389  %t = load i8, ptr %s390  %u = sext i8 %t to i32391  ret i32 %u392}393 394; CHECK-LABEL: load_i32_i64_s_with_folded_offset:395; CHECK: i64.load32_s $push0=, 24($0){{$}}396define i64 @load_i32_i64_s_with_folded_offset(ptr %p) {397  %q = ptrtoint ptr %p to i32398  %r = add nuw i32 %q, 24399  %s = inttoptr i32 %r to ptr400  %t = load i32, ptr %s401  %u = sext i32 %t to i64402  ret i64 %u403}404 405; Fold a gep offset into a sign-extending load.406 407; CHECK-LABEL: load_i8_i32_s_with_folded_gep_offset:408; CHECK: i32.load8_s $push0=, 24($0){{$}}409define i32 @load_i8_i32_s_with_folded_gep_offset(ptr %p) {410  %s = getelementptr inbounds i8, ptr %p, i32 24411  %t = load i8, ptr %s412  %u = sext i8 %t to i32413  ret i32 %u414}415 416; CHECK-LABEL: load_i16_i32_s_with_folded_gep_offset:417; CHECK: i32.load16_s $push0=, 48($0){{$}}418define i32 @load_i16_i32_s_with_folded_gep_offset(ptr %p) {419  %s = getelementptr inbounds i16, ptr %p, i32 24420  %t = load i16, ptr %s421  %u = sext i16 %t to i32422  ret i32 %u423}424 425; CHECK-LABEL: load_i16_i64_s_with_folded_gep_offset:426; CHECK: i64.load16_s $push0=, 48($0){{$}}427define i64 @load_i16_i64_s_with_folded_gep_offset(ptr %p) {428  %s = getelementptr inbounds i16, ptr %p, i32 24429  %t = load i16, ptr %s430  %u = sext i16 %t to i64431  ret i64 %u432}433 434; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as435; an 'add' if the or'ed bits are known to be zero.436 437; CHECK-LABEL: load_i8_i32_s_with_folded_or_offset:438; CHECK: i32.load8_s $push{{[0-9]+}}=, 2($pop{{[0-9]+}}){{$}}439define i32 @load_i8_i32_s_with_folded_or_offset(i32 %x) {440  %and = and i32 %x, -4441  %t0 = inttoptr i32 %and to ptr442  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2443  %t1 = load i8, ptr %arrayidx444  %conv = sext i8 %t1 to i32445  ret i32 %conv446}447 448; CHECK-LABEL: load_i8_i64_s_with_folded_or_offset:449; CHECK: i64.load8_s $push{{[0-9]+}}=, 2($pop{{[0-9]+}}){{$}}450define i64 @load_i8_i64_s_with_folded_or_offset(i32 %x) {451  %and = and i32 %x, -4452  %t0 = inttoptr i32 %and to ptr453  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2454  %t1 = load i8, ptr %arrayidx455  %conv = sext i8 %t1 to i64456  ret i64 %conv457}458 459; When loading from a fixed address, materialize a zero.460 461; CHECK-LABEL: load_i16_i32_s_from_numeric_address462; CHECK: i32.const $push0=, 0{{$}}463; CHECK: i32.load16_s  $push1=, 42($pop0){{$}}464define i32 @load_i16_i32_s_from_numeric_address() {465  %s = inttoptr i32 42 to ptr466  %t = load i16, ptr %s467  %u = sext i16 %t to i32468  ret i32 %u469}470 471; CHECK-LABEL: load_i8_i32_s_from_global_address472; CHECK: i32.const $push0=, 0{{$}}473; CHECK: i32.load8_s  $push1=, gv8($pop0){{$}}474@gv8 = global i8 0475define i32 @load_i8_i32_s_from_global_address() {476  %t = load i8, ptr @gv8477  %u = sext i8 %t to i32478  ret i32 %u479}480 481;===----------------------------------------------------------------------------482; Zero-extending loads483;===----------------------------------------------------------------------------484 485; Fold an offset into a zero-extending load.486 487; CHECK-LABEL: load_i8_i32_z_with_folded_offset:488; CHECK: i32.load8_u $push0=, 24($0){{$}}489define i32 @load_i8_i32_z_with_folded_offset(ptr %p) {490  %q = ptrtoint ptr %p to i32491  %r = add nuw i32 %q, 24492  %s = inttoptr i32 %r to ptr493  %t = load i8, ptr %s494  %u = zext i8 %t to i32495  ret i32 %u496}497 498; CHECK-LABEL: load_i32_i64_z_with_folded_offset:499; CHECK: i64.load32_u $push0=, 24($0){{$}}500define i64 @load_i32_i64_z_with_folded_offset(ptr %p) {501  %q = ptrtoint ptr %p to i32502  %r = add nuw i32 %q, 24503  %s = inttoptr i32 %r to ptr504  %t = load i32, ptr %s505  %u = zext i32 %t to i64506  ret i64 %u507}508 509; Fold a gep offset into a zero-extending load.510 511; CHECK-LABEL: load_i8_i32_z_with_folded_gep_offset:512; CHECK: i32.load8_u $push0=, 24($0){{$}}513define i32 @load_i8_i32_z_with_folded_gep_offset(ptr %p) {514  %s = getelementptr inbounds i8, ptr %p, i32 24515  %t = load i8, ptr %s516  %u = zext i8 %t to i32517  ret i32 %u518}519 520; CHECK-LABEL: load_i16_i32_z_with_folded_gep_offset:521; CHECK: i32.load16_u $push0=, 48($0){{$}}522define i32 @load_i16_i32_z_with_folded_gep_offset(ptr %p) {523  %s = getelementptr inbounds i16, ptr %p, i32 24524  %t = load i16, ptr %s525  %u = zext i16 %t to i32526  ret i32 %u527}528 529; CHECK-LABEL: load_i16_i64_z_with_folded_gep_offset:530; CHECK: i64.load16_u $push0=, 48($0){{$}}531define i64 @load_i16_i64_z_with_folded_gep_offset(ptr %p) {532  %s = getelementptr inbounds i16, ptr %p, i64 24533  %t = load i16, ptr %s534  %u = zext i16 %t to i64535  ret i64 %u536}537 538; When loading from a fixed address, materialize a zero.539 540; CHECK-LABEL: load_i16_i32_z_from_numeric_address541; CHECK: i32.const $push0=, 0{{$}}542; CHECK: i32.load16_u  $push1=, 42($pop0){{$}}543define i32 @load_i16_i32_z_from_numeric_address() {544  %s = inttoptr i32 42 to ptr545  %t = load i16, ptr %s546  %u = zext i16 %t to i32547  ret i32 %u548}549 550; CHECK-LABEL: load_i8_i32_z_from_global_address551; CHECK: i32.const $push0=, 0{{$}}552; CHECK: i32.load8_u  $push1=, gv8($pop0){{$}}553define i32 @load_i8_i32_z_from_global_address() {554  %t = load i8, ptr @gv8555  %u = zext i8 %t to i32556  ret i32 %u557}558 559; i8 return value should test anyext loads560; CHECK-LABEL: load_i8_i32_retvalue:561; CHECK: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}562; CHECK-NEXT: return $pop[[NUM]]{{$}}563define i8 @load_i8_i32_retvalue(ptr %p) {564  %v = load i8, ptr %p565  ret i8 %v566}567 568;===----------------------------------------------------------------------------569; Truncating stores570;===----------------------------------------------------------------------------571 572; Fold an offset into a truncating store.573 574; CHECK-LABEL: store_i8_i32_with_folded_offset:575; CHECK: i32.store8 24($0), $1{{$}}576define void @store_i8_i32_with_folded_offset(ptr %p, i32 %v) {577  %q = ptrtoint ptr %p to i32578  %r = add nuw i32 %q, 24579  %s = inttoptr i32 %r to ptr580  %t = trunc i32 %v to i8581  store i8 %t, ptr %s582  ret void583}584 585; CHECK-LABEL: store_i32_i64_with_folded_offset:586; CHECK: i64.store32 24($0), $1{{$}}587define void @store_i32_i64_with_folded_offset(ptr %p, i64 %v) {588  %q = ptrtoint ptr %p to i32589  %r = add nuw i32 %q, 24590  %s = inttoptr i32 %r to ptr591  %t = trunc i64 %v to i32592  store i32 %t, ptr %s593  ret void594}595 596; Fold a gep offset into a truncating store.597 598; CHECK-LABEL: store_i8_i32_with_folded_gep_offset:599; CHECK: i32.store8 24($0), $1{{$}}600define void @store_i8_i32_with_folded_gep_offset(ptr %p, i32 %v) {601  %s = getelementptr inbounds i8, ptr %p, i32 24602  %t = trunc i32 %v to i8603  store i8 %t, ptr %s604  ret void605}606 607; CHECK-LABEL: store_i16_i32_with_folded_gep_offset:608; CHECK: i32.store16 48($0), $1{{$}}609define void @store_i16_i32_with_folded_gep_offset(ptr %p, i32 %v) {610  %s = getelementptr inbounds i16, ptr %p, i32 24611  %t = trunc i32 %v to i16612  store i16 %t, ptr %s613  ret void614}615 616; CHECK-LABEL: store_i16_i64_with_folded_gep_offset:617; CHECK: i64.store16 48($0), $1{{$}}618define void @store_i16_i64_with_folded_gep_offset(ptr %p, i64 %v) {619  %s = getelementptr inbounds i16, ptr %p, i64 24620  %t = trunc i64 %v to i16621  store i16 %t, ptr %s622  ret void623}624 625; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as626; an 'add' if the or'ed bits are known to be zero.627 628; CHECK-LABEL: store_i8_i32_with_folded_or_offset:629; CHECK: i32.store8 2($pop{{[0-9]+}}), $1{{$}}630define void @store_i8_i32_with_folded_or_offset(i32 %x, i32 %v) {631  %and = and i32 %x, -4632  %p = inttoptr i32 %and to ptr633  %arrayidx = getelementptr inbounds i8, ptr %p, i32 2634  %t = trunc i32 %v to i8635  store i8 %t, ptr %arrayidx636  ret void637}638 639; CHECK-LABEL: store_i8_i64_with_folded_or_offset:640; CHECK: i64.store8 2($pop{{[0-9]+}}), $1{{$}}641define void @store_i8_i64_with_folded_or_offset(i32 %x, i64 %v) {642  %and = and i32 %x, -4643  %p = inttoptr i32 %and to ptr644  %arrayidx = getelementptr inbounds i8, ptr %p, i32 2645  %t = trunc i64 %v to i8646  store i8 %t, ptr %arrayidx647  ret void648}649 650;===----------------------------------------------------------------------------651; Aggregate values652;===----------------------------------------------------------------------------653 654; Fold the offsets when lowering aggregate loads and stores.655 656; CHECK-LABEL: aggregate_load_store:657; CHECK: i32.load  $2=, 0($0){{$}}658; CHECK: i32.load  $3=, 4($0){{$}}659; CHECK: i32.load  $4=, 8($0){{$}}660; CHECK: i32.load  $push0=, 12($0){{$}}661; CHECK: i32.store 12($1), $pop0{{$}}662; CHECK: i32.store 8($1), $4{{$}}663; CHECK: i32.store 4($1), $3{{$}}664; CHECK: i32.store 0($1), $2{{$}}665define void @aggregate_load_store(ptr %p, ptr %q) {666  ; volatile so that things stay in order for the tests above667  %t = load volatile {i32,i32,i32,i32}, ptr %p668  store volatile {i32,i32,i32,i32} %t, ptr %q669  ret void670}671 672; Fold the offsets when lowering aggregate return values. The stores get673; merged into i64 stores.674 675; CHECK-LABEL: aggregate_return:676; CHECK: i64.const   $push[[L0:[0-9]+]]=, 0{{$}}677; CHECK: i64.store   8($0), $pop[[L0]]{{$}}678; CHECK: i64.const   $push[[L1:[0-9]+]]=, 0{{$}}679; CHECK: i64.store   0($0), $pop[[L1]]{{$}}680define {i32,i32,i32,i32} @aggregate_return() {681  ret {i32,i32,i32,i32} zeroinitializer682}683 684; Fold the offsets when lowering aggregate return values. The stores are not685; merged.686 687; CHECK-LABEL: aggregate_return_without_merge:688; CHECK: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}689; CHECK: i32.store8  14($0), $pop[[L0]]{{$}}690; CHECK: i32.const   $push[[L1:[0-9]+]]=, 0{{$}}691; CHECK: i32.store16 12($0), $pop[[L1]]{{$}}692; CHECK: i32.const   $push[[L2:[0-9]+]]=, 0{{$}}693; CHECK: i32.store   8($0), $pop[[L2]]{{$}}694; CHECK: i64.const   $push[[L3:[0-9]+]]=, 0{{$}}695; CHECK: i64.store   0($0), $pop[[L3]]{{$}}696define {i64,i32,i16,i8} @aggregate_return_without_merge() {697  ret {i64,i32,i16,i8} zeroinitializer698}699 700;===----------------------------------------------------------------------------701; Loads: Half Precision702;===----------------------------------------------------------------------------703 704; Fold an offset into a zero-extending load.705 706; CHECK-LABEL: load_f16_f32_with_folded_offset:707; CHECK: f32.load_f16 $push0=, 24($0){{$}}708define float @load_f16_f32_with_folded_offset(ptr %p) {709  %q = ptrtoint ptr %p to i32710  %r = add nuw i32 %q, 24711  %s = inttoptr i32 %r to ptr712  %t = call float @llvm.wasm.loadf16.f32(ptr %s)713  ret float %t714}715 716; Fold a gep offset into a zero-extending load.717 718; CHECK-LABEL: load_f16_f32_with_folded_gep_offset:719; CHECK: f32.load_f16 $push0=, 24($0){{$}}720define float @load_f16_f32_with_folded_gep_offset(ptr %p) {721  %s = getelementptr inbounds i8, ptr %p, i32 24722  %t = call float @llvm.wasm.loadf16.f32(ptr %s)723  ret float %t724}725 726;===----------------------------------------------------------------------------727; Stores: Half Precision728;===----------------------------------------------------------------------------729 730; Basic store.731 732; CHECK-LABEL: store_f16_f32_no_offset:733; CHECK-NEXT: .functype store_f16_f32_no_offset (i32, f32) -> (){{$}}734; CHECK-NEXT: f32.store_f16 0($0), $1{{$}}735; CHECK-NEXT: return{{$}}736define void @store_f16_f32_no_offset(ptr %p, float %v) {737  call void @llvm.wasm.storef16.f32(float %v, ptr %p)738  ret void739}740 741; Storing to a fixed address.742 743; CHECK-LABEL: store_f16_f32_to_numeric_address:744; CHECK:      i32.const $push1=, 0{{$}}745; CHECK-NEXT: f32.const $push0=, 0x0p0{{$}}746; CHECK-NEXT: f32.store_f16 42($pop1), $pop0{{$}}747define void @store_f16_f32_to_numeric_address() {748  %s = inttoptr i32 42 to ptr749  call void @llvm.wasm.storef16.f32(float 0.0, ptr %s)750  ret void751}752