756 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s3 4; First, a simple example from Clang. The registers could plausibly be5; different, but probably won't be.6 7%struct.foo = type { i8, [2 x i8], i8 }8 9define [1 x i64] @from_clang([1 x i64] %f.coerce, i32 %n) nounwind readnone {10; CHECK-LABEL: from_clang:11; CHECK: // %bb.0: // %entry12; CHECK-NEXT: mov w8, #135 // =0x8713; CHECK-NEXT: and x9, x0, #0xffffff0014; CHECK-NEXT: and w8, w0, w815; CHECK-NEXT: bfi w8, w1, #3, #416; CHECK-NEXT: orr x0, x8, x917; CHECK-NEXT: ret18entry:19 %f.coerce.fca.0.extract = extractvalue [1 x i64] %f.coerce, 020 %tmp.sroa.0.0.extract.trunc = trunc i64 %f.coerce.fca.0.extract to i3221 %bf.value = shl i32 %n, 322 %0 = and i32 %bf.value, 12023 %f.sroa.0.0.insert.ext.masked = and i32 %tmp.sroa.0.0.extract.trunc, 13524 %1 = or i32 %f.sroa.0.0.insert.ext.masked, %025 %f.sroa.0.0.extract.trunc = zext i32 %1 to i6426 %tmp1.sroa.1.1.insert.insert = and i64 %f.coerce.fca.0.extract, 429496704027 %tmp1.sroa.0.0.insert.insert = or i64 %f.sroa.0.0.extract.trunc, %tmp1.sroa.1.1.insert.insert28 %.fca.0.insert = insertvalue [1 x i64] undef, i64 %tmp1.sroa.0.0.insert.insert, 029 ret [1 x i64] %.fca.0.insert30}31 32define void @test_whole32(ptr %existing, ptr %new) {33; CHECK-LABEL: test_whole32:34; CHECK: // %bb.0:35; CHECK-NEXT: ldr w8, [x0]36; CHECK-NEXT: ldr w9, [x1]37; CHECK-NEXT: bfi w8, w9, #26, #538; CHECK-NEXT: str w8, [x0]39; CHECK-NEXT: ret40 %oldval = load volatile i32, ptr %existing41 %oldval_keep = and i32 %oldval, 2214592511 ; =0x83ffffff42 43 %newval = load volatile i32, ptr %new44 %newval_shifted = shl i32 %newval, 2645 %newval_masked = and i32 %newval_shifted, 2080374784 ; = 0x7c00000046 47 %combined = or i32 %oldval_keep, %newval_masked48 store volatile i32 %combined, ptr %existing49 50 ret void51}52 53define void @test_whole64(ptr %existing, ptr %new) {54; CHECK-LABEL: test_whole64:55; CHECK: // %bb.0:56; CHECK-NEXT: ldr x8, [x0]57; CHECK-NEXT: ldr x9, [x1]58; CHECK-NEXT: bfi x8, x9, #26, #1459; CHECK-NEXT: str x8, [x0]60; CHECK-NEXT: ret61 %oldval = load volatile i64, ptr %existing62 %oldval_keep = and i64 %oldval, 18446742974265032703 ; = 0xffffff0003ffffffL63 64 %newval = load volatile i64, ptr %new65 %newval_shifted = shl i64 %newval, 2666 %newval_masked = and i64 %newval_shifted, 1099444518912 ; = 0xfffc00000067 68 %combined = or i64 %oldval_keep, %newval_masked69 store volatile i64 %combined, ptr %existing70 71 ret void72}73 74define void @test_whole32_from64(ptr %existing, ptr %new) {75; CHECK-LABEL: test_whole32_from64:76; CHECK: // %bb.0:77; CHECK-NEXT: ldr x8, [x0]78; CHECK-NEXT: ldr x9, [x1]79; CHECK-NEXT: and x8, x8, #0xffff000080; CHECK-NEXT: bfxil x8, x9, #0, #1681; CHECK-NEXT: str x8, [x0]82; CHECK-NEXT: ret83 %oldval = load volatile i64, ptr %existing84 %oldval_keep = and i64 %oldval, 4294901760 ; = 0xffff000085 86 %newval = load volatile i64, ptr %new87 %newval_masked = and i64 %newval, 65535 ; = 0xffff88 89 %combined = or i64 %oldval_keep, %newval_masked90 store volatile i64 %combined, ptr %existing91 92 ret void93}94 95define void @test_32bit_masked(ptr %existing, ptr %new) {96; CHECK-LABEL: test_32bit_masked:97; CHECK: // %bb.0:98; CHECK-NEXT: ldr w9, [x0]99; CHECK-NEXT: mov w8, #135 // =0x87100; CHECK-NEXT: ldr w10, [x1]101; CHECK-NEXT: and w8, w9, w8102; CHECK-NEXT: bfi w8, w10, #3, #4103; CHECK-NEXT: str w8, [x0]104; CHECK-NEXT: ret105 %oldval = load volatile i32, ptr %existing106 %oldval_keep = and i32 %oldval, 135 ; = 0x87107 108 %newval = load volatile i32, ptr %new109 %newval_shifted = shl i32 %newval, 3110 %newval_masked = and i32 %newval_shifted, 120 ; = 0x78111 112 %combined = or i32 %oldval_keep, %newval_masked113 store volatile i32 %combined, ptr %existing114 115 ret void116}117 118define void @test_64bit_masked(ptr %existing, ptr %new) {119; CHECK-LABEL: test_64bit_masked:120; CHECK: // %bb.0:121; CHECK-NEXT: ldr x8, [x0]122; CHECK-NEXT: ldr x9, [x1]123; CHECK-NEXT: and x8, x8, #0xff00000000124; CHECK-NEXT: bfi x8, x9, #40, #8125; CHECK-NEXT: str x8, [x0]126; CHECK-NEXT: ret127 %oldval = load volatile i64, ptr %existing128 %oldval_keep = and i64 %oldval, 1095216660480 ; = 0xff_0000_0000129 130 %newval = load volatile i64, ptr %new131 %newval_shifted = shl i64 %newval, 40132 %newval_masked = and i64 %newval_shifted, 280375465082880 ; = 0xff00_0000_0000133 134 %combined = or i64 %newval_masked, %oldval_keep135 store volatile i64 %combined, ptr %existing136 137 ret void138}139 140; Mask is too complicated for literal ANDwwi, make sure other avenues are tried.141define void @test_32bit_complexmask(ptr %existing, ptr %new) {142; CHECK-LABEL: test_32bit_complexmask:143; CHECK: // %bb.0:144; CHECK-NEXT: ldr w9, [x0]145; CHECK-NEXT: mov w8, #647 // =0x287146; CHECK-NEXT: ldr w10, [x1]147; CHECK-NEXT: and w8, w9, w8148; CHECK-NEXT: bfi w8, w10, #3, #4149; CHECK-NEXT: str w8, [x0]150; CHECK-NEXT: ret151 %oldval = load volatile i32, ptr %existing152 %oldval_keep = and i32 %oldval, 647 ; = 0x287153 154 %newval = load volatile i32, ptr %new155 %newval_shifted = shl i32 %newval, 3156 %newval_masked = and i32 %newval_shifted, 120 ; = 0x278157 158 %combined = or i32 %oldval_keep, %newval_masked159 store volatile i32 %combined, ptr %existing160 161 ret void162}163 164; Neither mask is a contiguous set of 1s. BFI can't be used165define void @test_32bit_badmask(ptr %existing, ptr %new) {166; CHECK-LABEL: test_32bit_badmask:167; CHECK: // %bb.0:168; CHECK-NEXT: ldr w8, [x0]169; CHECK-NEXT: ldr w9, [x1]170; CHECK-NEXT: mov w10, #632 // =0x278171; CHECK-NEXT: mov w11, #135 // =0x87172; CHECK-NEXT: and w9, w10, w9, lsl #3173; CHECK-NEXT: and w8, w8, w11174; CHECK-NEXT: orr w8, w8, w9175; CHECK-NEXT: str w8, [x0]176; CHECK-NEXT: ret177 %oldval = load volatile i32, ptr %existing178 %oldval_keep = and i32 %oldval, 135 ; = 0x87179 180 %newval = load volatile i32, ptr %new181 %newval_shifted = shl i32 %newval, 3182 %newval_masked = and i32 %newval_shifted, 632 ; = 0x278183 184 %combined = or i32 %oldval_keep, %newval_masked185 store volatile i32 %combined, ptr %existing186 187 ret void188}189 190; Ditto191define void @test_64bit_badmask(ptr %existing, ptr %new) {192; CHECK-LABEL: test_64bit_badmask:193; CHECK: // %bb.0:194; CHECK-NEXT: ldr x8, [x0]195; CHECK-NEXT: ldr x9, [x1]196; CHECK-NEXT: mov w10, #664 // =0x298197; CHECK-NEXT: mov w11, #135 // =0x87198; CHECK-NEXT: and x9, x10, x9, lsl #3199; CHECK-NEXT: and x8, x8, x11200; CHECK-NEXT: orr x8, x8, x9201; CHECK-NEXT: str x8, [x0]202; CHECK-NEXT: ret203 %oldval = load volatile i64, ptr %existing204 %oldval_keep = and i64 %oldval, 135 ; = 0x87205 206 %newval = load volatile i64, ptr %new207 %newval_shifted = shl i64 %newval, 3208 %newval_masked = and i64 %newval_shifted, 664 ; = 0x278209 210 %combined = or i64 %oldval_keep, %newval_masked211 store volatile i64 %combined, ptr %existing212 213 ret void214}215 216; Bitfield insert where there's a left-over shr needed at the beginning217; (e.g. result of str.bf1 = str.bf2)218define void @test_32bit_with_shr(ptr %existing, ptr %new) {219; CHECK-LABEL: test_32bit_with_shr:220; CHECK: // %bb.0:221; CHECK-NEXT: ldr w8, [x0]222; CHECK-NEXT: ldr w9, [x1]223; CHECK-NEXT: lsr w9, w9, #14224; CHECK-NEXT: bfi w8, w9, #26, #5225; CHECK-NEXT: str w8, [x0]226; CHECK-NEXT: ret227 %oldval = load volatile i32, ptr %existing228 %oldval_keep = and i32 %oldval, 2214592511 ; =0x83ffffff229 230 %newval = load i32, ptr %new231 %newval_shifted = shl i32 %newval, 12232 %newval_masked = and i32 %newval_shifted, 2080374784 ; = 0x7c000000233 234 %combined = or i32 %oldval_keep, %newval_masked235 store volatile i32 %combined, ptr %existing236 237 ret void238}239 240; Bitfield insert where the second or operand is a better match to be folded into the BFM241define void @test_32bit_opnd1_better(ptr %existing, ptr %new) {242; CHECK-LABEL: test_32bit_opnd1_better:243; CHECK: // %bb.0:244; CHECK-NEXT: ldr w8, [x0]245; CHECK-NEXT: ldr w9, [x1]246; CHECK-NEXT: and w8, w8, #0xffff247; CHECK-NEXT: bfi w8, w9, #16, #8248; CHECK-NEXT: str w8, [x0]249; CHECK-NEXT: ret250 %oldval = load volatile i32, ptr %existing251 %oldval_keep = and i32 %oldval, 65535 ; 0x0000ffff252 253 %newval = load i32, ptr %new254 %newval_shifted = shl i32 %newval, 16255 %newval_masked = and i32 %newval_shifted, 16711680 ; 0x00ff0000256 257 %combined = or i32 %oldval_keep, %newval_masked258 store volatile i32 %combined, ptr %existing259 260 ret void261}262 263; Tests when all the bits from one operand are not useful264define i32 @test_nouseful_bits(i8 %a, i32 %b) {265; CHECK-LABEL: test_nouseful_bits:266; CHECK: // %bb.0:267; CHECK-NEXT: and w8, w0, #0xff268; CHECK-NEXT: lsl w8, w8, #8269; CHECK-NEXT: mov w9, w8270; CHECK-NEXT: bfxil w9, w0, #0, #8271; CHECK-NEXT: orr w0, w8, w9, lsl #16272; CHECK-NEXT: ret273 %conv = zext i8 %a to i32 ; 0 0 0 A274 %shl = shl i32 %b, 8 ; B2 B1 B0 0275 %or = or i32 %conv, %shl ; B2 B1 B0 A276 %shl.1 = shl i32 %or, 8 ; B1 B0 A 0277 %or.1 = or i32 %conv, %shl.1 ; B1 B0 A A278 %shl.2 = shl i32 %or.1, 8 ; B0 A A 0279 %or.2 = or i32 %conv, %shl.2 ; B0 A A A280 %shl.3 = shl i32 %or.2, 8 ; A A A 0281 %or.3 = or i32 %conv, %shl.3 ; A A A A282 %shl.4 = shl i32 %or.3, 8 ; A A A 0283 ret i32 %shl.4284}285 286define void @test_nouseful_strb(ptr %ptr32, ptr %ptr8, i32 %x) {287; CHECK-LABEL: test_nouseful_strb:288; CHECK: // %bb.0: // %entry289; CHECK-NEXT: ldr w8, [x0]290; CHECK-NEXT: bfxil w8, w2, #16, #3291; CHECK-NEXT: strb w8, [x1]292; CHECK-NEXT: ret293entry:294 %0 = load i32, ptr %ptr32, align 8295 %and = and i32 %0, -8296 %shr = lshr i32 %x, 16297 %and1 = and i32 %shr, 7298 %or = or i32 %and, %and1299 %trunc = trunc i32 %or to i8300 store i8 %trunc, ptr %ptr8301 ret void302}303 304define void @test_nouseful_strh(ptr %ptr32, ptr %ptr16, i32 %x) {305; CHECK-LABEL: test_nouseful_strh:306; CHECK: // %bb.0: // %entry307; CHECK-NEXT: ldr w8, [x0]308; CHECK-NEXT: bfxil w8, w2, #16, #4309; CHECK-NEXT: strh w8, [x1]310; CHECK-NEXT: ret311entry:312 %0 = load i32, ptr %ptr32, align 8313 %and = and i32 %0, -16314 %shr = lshr i32 %x, 16315 %and1 = and i32 %shr, 15316 %or = or i32 %and, %and1317 %trunc = trunc i32 %or to i16318 store i16 %trunc, ptr %ptr16319 ret void320}321 322define void @test_nouseful_sturb(ptr %ptr32, ptr %ptr8, i32 %x) {323; CHECK-LABEL: test_nouseful_sturb:324; CHECK: // %bb.0: // %entry325; CHECK-NEXT: ldr w8, [x0]326; CHECK-NEXT: bfxil w8, w2, #16, #3327; CHECK-NEXT: sturb w8, [x1, #-1]328; CHECK-NEXT: ret329entry:330 %0 = load i32, ptr %ptr32, align 8331 %and = and i32 %0, -8332 %shr = lshr i32 %x, 16333 %and1 = and i32 %shr, 7334 %or = or i32 %and, %and1335 %trunc = trunc i32 %or to i8336 %gep = getelementptr i8, ptr %ptr8, i64 -1337 store i8 %trunc, ptr %gep338 ret void339}340 341define void @test_nouseful_sturh(ptr %ptr32, ptr %ptr16, i32 %x) {342; CHECK-LABEL: test_nouseful_sturh:343; CHECK: // %bb.0: // %entry344; CHECK-NEXT: ldr w8, [x0]345; CHECK-NEXT: bfxil w8, w2, #16, #4346; CHECK-NEXT: sturh w8, [x1, #-2]347; CHECK-NEXT: ret348entry:349 %0 = load i32, ptr %ptr32, align 8350 %and = and i32 %0, -16351 %shr = lshr i32 %x, 16352 %and1 = and i32 %shr, 15353 %or = or i32 %and, %and1354 %trunc = trunc i32 %or to i16355 %gep = getelementptr i16, ptr %ptr16, i64 -1356 store i16 %trunc, ptr %gep357 ret void358}359 360; The next set of tests generate a BFXIL from 'or (and X, Mask0Imm),361; (and Y, Mask1Imm)' iff Mask0Imm and ~Mask1Imm are equivalent and one of the362; MaskImms is a shifted mask (e.g., 0x000ffff0).363 364define i32 @test_or_and_and1(i32 %a, i32 %b) {365; CHECK-LABEL: test_or_and_and1:366; CHECK: // %bb.0: // %entry367; CHECK-NEXT: lsr w8, w1, #4368; CHECK-NEXT: bfi w0, w8, #4, #12369; CHECK-NEXT: ret370entry:371 %and = and i32 %a, -65521 ; 0xffff000f372 %and1 = and i32 %b, 65520 ; 0x0000fff0373 %or = or i32 %and1, %and374 ret i32 %or375}376 377define i32 @test_or_and_and2(i32 %a, i32 %b) {378; CHECK-LABEL: test_or_and_and2:379; CHECK: // %bb.0: // %entry380; CHECK-NEXT: lsr w8, w0, #4381; CHECK-NEXT: mov w0, w1382; CHECK-NEXT: bfi w0, w8, #4, #12383; CHECK-NEXT: ret384entry:385 %and = and i32 %a, 65520 ; 0x0000fff0386 %and1 = and i32 %b, -65521 ; 0xffff000f387 %or = or i32 %and1, %and388 ret i32 %or389}390 391define i64 @test_or_and_and3(i64 %a, i64 %b) {392; CHECK-LABEL: test_or_and_and3:393; CHECK: // %bb.0: // %entry394; CHECK-NEXT: lsr x8, x1, #16395; CHECK-NEXT: bfi x0, x8, #16, #32396; CHECK-NEXT: ret397entry:398 %and = and i64 %a, -281474976645121 ; 0xffff00000000ffff399 %and1 = and i64 %b, 281474976645120 ; 0x0000ffffffff0000400 %or = or i64 %and1, %and401 ret i64 %or402}403 404; Don't convert 'and' with multiple uses.405define i32 @test_or_and_and4(i32 %a, i32 %b, ptr %ptr) {406; CHECK-LABEL: test_or_and_and4:407; CHECK: // %bb.0: // %entry408; CHECK-NEXT: and w8, w0, #0xffff000f409; CHECK-NEXT: and w9, w1, #0xfff0410; CHECK-NEXT: orr w0, w9, w8411; CHECK-NEXT: str w8, [x2]412; CHECK-NEXT: ret413entry:414 %and = and i32 %a, -65521415 store i32 %and, ptr %ptr, align 4416 %and2 = and i32 %b, 65520417 %or = or i32 %and2, %and418 ret i32 %or419}420 421; Don't convert 'and' with multiple uses.422define i32 @test_or_and_and5(i32 %a, i32 %b, ptr %ptr) {423; CHECK-LABEL: test_or_and_and5:424; CHECK: // %bb.0: // %entry425; CHECK-NEXT: and w8, w1, #0xfff0426; CHECK-NEXT: and w9, w0, #0xffff000f427; CHECK-NEXT: orr w0, w8, w9428; CHECK-NEXT: str w8, [x2]429; CHECK-NEXT: ret430entry:431 %and = and i32 %b, 65520432 store i32 %and, ptr %ptr, align 4433 %and1 = and i32 %a, -65521434 %or = or i32 %and, %and1435 ret i32 %or436}437 438define i32 @test1(i32 %a) {439; CHECK-LABEL: test1:440; CHECK: // %bb.0:441; CHECK-NEXT: mov w8, #5 // =0x5442; CHECK-NEXT: bfxil w0, w8, #0, #4443; CHECK-NEXT: ret444 %1 = and i32 %a, -16 ; 0xfffffff0445 %2 = or i32 %1, 5 ; 0x00000005446 ret i32 %2447}448 449define i32 @test2(i32 %a) {450; CHECK-LABEL: test2:451; CHECK: // %bb.0:452; CHECK-NEXT: mov w8, #10 // =0xa453; CHECK-NEXT: bfi w0, w8, #22, #4454; CHECK-NEXT: ret455 %1 = and i32 %a, -62914561 ; 0xfc3fffff456 %2 = or i32 %1, 41943040 ; 0x06400000457 ret i32 %2458}459 460define i64 @test3(i64 %a) {461; CHECK-LABEL: test3:462; CHECK: // %bb.0:463; CHECK-NEXT: mov x8, #5 // =0x5464; CHECK-NEXT: bfxil x0, x8, #0, #3465; CHECK-NEXT: ret466 %1 = and i64 %a, -8 ; 0xfffffffffffffff8467 %2 = or i64 %1, 5 ; 0x0000000000000005468 ret i64 %2469}470 471define i64 @test4(i64 %a) {472; CHECK-LABEL: test4:473; CHECK: // %bb.0:474; CHECK-NEXT: mov x8, #9 // =0x9475; CHECK-NEXT: bfi x0, x8, #1, #7476; CHECK-NEXT: ret477 %1 = and i64 %a, -255 ; 0xffffffffffffff01478 %2 = or i64 %1, 18 ; 0x0000000000000012479 ret i64 %2480}481 482; Don't generate BFI/BFXIL if the immediate can be encoded in the ORR.483define i32 @test5(i32 %a) {484; CHECK-LABEL: test5:485; CHECK: // %bb.0:486; CHECK-NEXT: and w8, w0, #0xfffffff0487; CHECK-NEXT: orr w0, w8, #0x6488; CHECK-NEXT: ret489 %1 = and i32 %a, 4294967280 ; 0xfffffff0490 %2 = or i32 %1, 6 ; 0x00000006491 ret i32 %2492}493 494; BFXIL will use the same constant as the ORR, so we don't care how the constant495; is materialized (it's an equal cost either way).496define i32 @test6(i32 %a) {497; CHECK-LABEL: test6:498; CHECK: // %bb.0:499; CHECK-NEXT: mov w8, #23250 // =0x5ad2500; CHECK-NEXT: movk w8, #11, lsl #16501; CHECK-NEXT: bfxil w0, w8, #0, #20502; CHECK-NEXT: ret503 %1 = and i32 %a, 4293918720 ; 0xfff00000504 %2 = or i32 %1, 744146 ; 0x000b5ad2505 ret i32 %2506}507 508; BFIs that require the same number of instruction to materialize the constant509; as the original ORR are okay.510define i32 @test7(i32 %a) {511; CHECK-LABEL: test7:512; CHECK: // %bb.0:513; CHECK-NEXT: mov w8, #44393 // =0xad69514; CHECK-NEXT: movk w8, #5, lsl #16515; CHECK-NEXT: bfi w0, w8, #1, #19516; CHECK-NEXT: ret517 %1 = and i32 %a, 4293918721 ; 0xfff00001518 %2 = or i32 %1, 744146 ; 0x000b5ad2519 ret i32 %2520}521 522; BFIs that require more instructions to materialize the constant as compared523; to the original ORR are not okay. In this case we would be replacing the524; 'and' with a 'movk', which would decrease ILP while using the same number of525; instructions.526define i64 @test8(i64 %a) {527; CHECK-LABEL: test8:528; CHECK: // %bb.0:529; CHECK-NEXT: mov x8, #2035482624 // =0x79530000530; CHECK-NEXT: and x9, x0, #0xff000000000000ff531; CHECK-NEXT: movk x8, #36694, lsl #32532; CHECK-NEXT: orr x0, x9, x8533; CHECK-NEXT: ret534 %1 = and i64 %a, -72057594037927681 ; 0xff000000000000ff535 %2 = or i64 %1, 157601565442048 ; 0x00008f5679530000536 ret i64 %2537}538 539; This test exposed an issue with an overly aggressive assert. The bit of code540; that is expected to catch this case is unable to deal with the trunc, which541; results in a failing check due to a mismatch between the BFI opcode and542; the expected value type of the OR.543define i32 @test9(i64 %b, i32 %e) {544; CHECK-LABEL: test9:545; CHECK: // %bb.0:546; CHECK-NEXT: lsr x0, x0, #12547; CHECK-NEXT: lsr w8, w1, #23548; CHECK-NEXT: bfi w0, w8, #23, #9549; CHECK-NEXT: // kill: def $w0 killed $w0 killed $x0550; CHECK-NEXT: ret551 %c = lshr i64 %b, 12552 %d = trunc i64 %c to i32553 %f = and i32 %d, 8388607554 %g = and i32 %e, -8388608555 %h = or i32 %g, %f556 ret i32 %h557}558 559define <2 x i32> @test_complex_type(ptr %addr, i64 %in, ptr %bf ) {560; CHECK-LABEL: test_complex_type:561; CHECK: // %bb.0:562; CHECK-NEXT: ldr d0, [x0], #8563; CHECK-NEXT: orr x8, x0, x1, lsl #32564; CHECK-NEXT: str x8, [x2]565; CHECK-NEXT: ret566 %vec = load <2 x i32>, ptr %addr567 568 %vec.next = getelementptr <2 x i32>, ptr %addr, i32 1569 %lo = ptrtoint ptr %vec.next to i64570 571 %hi = shl i64 %in, 32572 %both = or i64 %lo, %hi573 store i64 %both, ptr %bf574 575 ret <2 x i32> %vec576}577 578define i64 @test_truncated_shift(i64 %x, i64 %y) {579; CHECK-LABEL: test_truncated_shift:580; CHECK: // %bb.0: // %entry581; CHECK-NEXT: bfi x0, x1, #25, #5582; CHECK-NEXT: ret583entry:584 %and = and i64 %x, -1040187393585 %shl4 = shl i64 %y, 25586 %and5 = and i64 %shl4, 1040187392587 %or = or i64 %and5, %and588 ret i64 %or589}590 591define i64 @test_and_extended_shift_with_imm(i64 %0) {592; CHECK-LABEL: test_and_extended_shift_with_imm:593; CHECK: // %bb.0:594; CHECK-NEXT: ubfiz x0, x0, #7, #8595; CHECK-NEXT: ret596 %2 = shl i64 %0, 7597 %3 = and i64 %2, 32640 ; #0x7f80598 ret i64 %3599}600 601; orr with left-shifted operand is better than bfi, since it improves data602; dependency, and orr has a smaller latency and higher throughput than bfm on603; some AArch64 processors (for the rest, orr is at least as good as bfm)604;605; ubfx x8, x0, #8, #7606; and x9, x0, #0x7f607; orr x0, x9, x8, lsl #7608define i64 @test_orr_not_bfxil_i64(i64 %0) {609; CHECK-LABEL: test_orr_not_bfxil_i64:610; CHECK: // %bb.0:611; CHECK-NEXT: ubfx x8, x0, #8, #7612; CHECK-NEXT: and x9, x0, #0x7f613; CHECK-NEXT: orr x0, x9, x8, lsl #7614; CHECK-NEXT: ret615 %2 = and i64 %0, 127616 %3 = lshr i64 %0, 1617 %4 = and i64 %3, 16256 ; 0x3f80618 %5 = or i64 %4, %2619 ret i64 %5620}621 622; The 32-bit test for `test_orr_not_bfxil_i64`.623define i32 @test_orr_not_bfxil_i32(i32 %0) {624; CHECK-LABEL: test_orr_not_bfxil_i32:625; CHECK: // %bb.0:626; CHECK-NEXT: ubfx w8, w0, #8, #7627; CHECK-NEXT: and w9, w0, #0x7f628; CHECK-NEXT: orr w0, w9, w8, lsl #7629; CHECK-NEXT: ret630 %2 = and i32 %0, 127631 %3 = lshr i32 %0, 1632 %4 = and i32 %3, 16256 ; 0x3f80633 %5 = or i32 %4, %2634 ret i32 %5635}636 637; For or operation, one operand is a left shift of another operand.638; So orr with a left-shifted operand is generated (not bfi).639define i64 @test_orr_not_bfi_i64(i64 %0) {640; CHECK-LABEL: test_orr_not_bfi_i64:641; CHECK: // %bb.0:642; CHECK-NEXT: and x8, x0, #0xff643; CHECK-NEXT: orr x0, x8, x8, lsl #8644; CHECK-NEXT: ret645 %2 = and i64 %0, 255646 %3 = shl i64 %2, 8647 %4 = or i64 %2, %3648 ret i64 %4649}650 651; bfi is better than orr, since it would simplify away two instructions652; (%mask and %bit-field-pos-op).653define i32 @test_bfi_not_orr_i32(i32 %0, i32 %1) {654; CHECK-LABEL: test_bfi_not_orr_i32:655; CHECK: // %bb.0:656; CHECK-NEXT: and w8, w1, #0xff657; CHECK-NEXT: bfi w8, w0, #8, #8658; CHECK-NEXT: mov w0, w8659; CHECK-NEXT: ret660 %bfi_dst = and i32 %1, 255661 %mask = and i32 %0, 255662 %bit-field-pos-op = shl i32 %mask, 8663 %or_res = or i32 %bit-field-pos-op, %bfi_dst664 ret i32 %or_res665}666 667; orr is generated (not bfi), since both simplify away one instruction (%3)668; while orr has shorter latency and higher throughput.669define i32 @test_orr_not_bfi_i32(i32 %0) {670; CHECK-LABEL: test_orr_not_bfi_i32:671; CHECK: // %bb.0:672; CHECK-NEXT: and w8, w0, #0xff673; CHECK-NEXT: orr w0, w8, w8, lsl #8674; CHECK-NEXT: ret675 %2 = and i32 %0, 255676 %3 = shl i32 %2, 8677 %4 = or i32 %2, %3678 ret i32 %4679}680 681; bfxil is better than orr, since it would simplify away two instructions682; (%mask and %bit-field-extract-op).683define i64 @test_bfxil_not_orr_i64(i64 %0, i64 %1) {684; CHECK-LABEL: test_bfxil_not_orr_i64:685; CHECK: // %bb.0:686; CHECK-NEXT: and x0, x0, #0xff000687; CHECK-NEXT: bfxil x0, x1, #12, #8688; CHECK-NEXT: ret689 %shifted-mask = and i64 %1, 1044480690 %bfi-dst = and i64 %0, 1044480691 %bit-field-extract-op = lshr i64 %shifted-mask, 12692 %or_res = or i64 %bit-field-extract-op, %bfi-dst693 ret i64 %or_res694}695 696; orr is generated (not bfxil), since one operand is the right shift of another697; operand.698define i64 @orr_not_bfxil_test2_i64(i64 %0) {699; CHECK-LABEL: orr_not_bfxil_test2_i64:700; CHECK: // %bb.0:701; CHECK-NEXT: and x8, x0, #0xff000702; CHECK-NEXT: orr x0, x8, x8, lsr #12703; CHECK-NEXT: ret704 %2 = and i64 %0, 1044480 ; 0xff000705 %3 = lshr i64 %2, 12706 %4 = or i64 %2, %3707 ret i64 %4708}709 710; bfxil simplifies away two instructions (that computes %shifted-mask and711; %bit-field-extract-op respectively), so it's better than orr (which712; simplifies away at most one shift).713define i32 @test_bfxil_not_orr_i32(i32 %0, i32 %1) {714; CHECK-LABEL: test_bfxil_not_orr_i32:715; CHECK: // %bb.0:716; CHECK-NEXT: and w0, w0, #0xff000717; CHECK-NEXT: bfxil w0, w1, #12, #8718; CHECK-NEXT: ret719 %shifted-mask = and i32 %1, 1044480720 %bfxil-dst = and i32 %0, 1044480721 %bit-field-extract-op = lshr i32 %shifted-mask, 12722 %or_res = or i32 %bit-field-extract-op, %bfxil-dst723 ret i32 %or_res724}725 726; one operand is the shift of another operand, so orr is generated (not bfxil).727define i32 @orr_not_bfxil_test2_i32(i32 %0) {728; CHECK-LABEL: orr_not_bfxil_test2_i32:729; CHECK: // %bb.0:730; CHECK-NEXT: and w8, w0, #0xff000731; CHECK-NEXT: orr w0, w8, w8, lsr #12732; CHECK-NEXT: ret733 %2 = and i32 %0, 1044480 ; 0xff000734 %3 = lshr i32 %2, 12735 %4 = or i32 %2, %3736 ret i32 %4737}738 739define i16 @implicit_trunc_of_imm(ptr %p, i16 %a, i16 %b) {740; CHECK-LABEL: implicit_trunc_of_imm:741; CHECK: // %bb.0: // %entry742; CHECK-NEXT: and w8, w1, #0xffffe000743; CHECK-NEXT: mov x9, x0744; CHECK-NEXT: mov w10, w8745; CHECK-NEXT: mov w0, w8746; CHECK-NEXT: bfxil w10, w2, #0, #1747; CHECK-NEXT: strh w10, [x9]748; CHECK-NEXT: ret749entry:750 %and1 = and i16 %a, -8192751 %and2 = and i16 %b, 1752 %or = or i16 %and2, %and1753 store i16 %or, ptr %p754 ret i16 %and1755}756