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