1; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -disable-wasm-fallthrough-return-opt | FileCheck %s 2 3; Test constant load and store address offsets. 4 5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6target 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{{$}} 17define 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){{$}} 26define 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){{$}} 38define 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){{$}} 50define 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){{$}} 62define 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){{$}} 76define 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){{$}} 87define 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 97define 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{{$}} 111define 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){{$}} 120define 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){{$}} 132define 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){{$}} 144define 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){{$}} 156define 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){{$}} 170define 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: .functype store_i32_no_offset (i32, i32) -> (){{$}} 184; CHECK-NEXT: i32.store 0($0), $1{{$}} 185; CHECK-NEXT: return{{$}} 186define 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{{$}} 195define 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{{$}} 207define 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{{$}} 219define 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{{$}} 231define 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{{$}} 245define 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: i32.const $push0=, 0{{$}} 255; CHECK-NEXT: i32.const $push1=, 0{{$}} 256; CHECK-NEXT: i32.store 42($pop0), $pop1{{$}} 257define 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{{$}} 267define 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{{$}} 280define 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{{$}} 292define 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{{$}} 304define 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{{$}} 316define 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{{$}} 330define 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]+}}{{$}} 340define 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){{$}} 356define 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){{$}} 367define 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){{$}} 380define 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){{$}} 389define 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){{$}} 398define 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]+}}){{$}} 410define 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]+}}){{$}} 421define 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){{$}} 435define 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 446define 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){{$}} 460define 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){{$}} 471define 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){{$}} 484define 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){{$}} 493define 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){{$}} 502define 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){{$}} 514define 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){{$}} 524define 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]]{{$}} 534define 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{{$}} 547define 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{{$}} 558define 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{{$}} 571define 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{{$}} 580define 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{{$}} 589define 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{{$}} 601define 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{{$}} 612define 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{{$}} 636define 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), $pop[[L0]]{{$}} 649; CHECK: i64.const $push[[L1:[0-9]+]]=, 0{{$}} 650; CHECK: i64.store 0($0), $pop[[L1]]{{$}} 651define {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]]{{$}} 667define {i64,i32,i16,i8} @aggregate_return_without_merge() { 668 ret {i64,i32,i16,i8} zeroinitializer 669} 670