diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h index d99817dc43e5b..376ce28a96413 100644 --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -470,6 +470,14 @@ struct KnownBits { LLVM_ABI static KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero = false, bool Exact = false); + /// Compute known bits for fshl(LHS, RHS, Amt). + LLVM_ABI static KnownBits fshl(const KnownBits &LHS, const KnownBits &RHS, + const APInt &Amt); + + /// Compute known bits for fshr(LHS, RHS, Amt). + LLVM_ABI static KnownBits fshr(const KnownBits &LHS, const KnownBits &RHS, + const APInt &Amt); + /// Compute known bits for clmul(LHS, RHS). LLVM_ABI static KnownBits clmul(const KnownBits &LHS, const KnownBits &RHS); diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index a0fb28612c534..8abb6bf4bdd17 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2082,18 +2082,12 @@ static void computeKnownBitsFromOperator(const Operator *I, if (!match(I->getOperand(2), m_APInt(SA))) break; - // Normalize to funnel shift left. - uint64_t ShiftAmt = SA->urem(BitWidth); - if (II->getIntrinsicID() == Intrinsic::fshr) - ShiftAmt = BitWidth - ShiftAmt; - KnownBits Known3(BitWidth); computeKnownBits(I->getOperand(0), DemandedElts, Known2, Q, Depth + 1); computeKnownBits(I->getOperand(1), DemandedElts, Known3, Q, Depth + 1); - - Known2 <<= ShiftAmt; - Known3 >>= BitWidth - ShiftAmt; - Known = Known2.unionWith(Known3); + Known = II->getIntrinsicID() == Intrinsic::fshl + ? KnownBits::fshl(Known2, Known3, *SA) + : KnownBits::fshr(Known2, Known3, *SA); break; } case Intrinsic::clmul: diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index f0b455fbdc7d0..b18a657e02081 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -560,6 +560,23 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known, Known.One = Known.One.rotr(Amt); break; } + case TargetOpcode::G_FSHL: + case TargetOpcode::G_FSHR: { + MachineInstr *AmtOpMI = MRI.getVRegDef(MI.getOperand(3).getReg()); + auto MaybeAmtOp = isConstantOrConstantSplatVector(*AmtOpMI, MRI); + if (!MaybeAmtOp) + break; + + const APInt Amt = *MaybeAmtOp; + computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts, + Depth + 1); + computeKnownBitsImpl(MI.getOperand(2).getReg(), Known2, DemandedElts, + Depth + 1); + Known = Opcode == TargetOpcode::G_FSHL + ? KnownBits::fshl(Known, Known2, Amt) + : KnownBits::fshr(Known, Known2, Amt); + break; + } case TargetOpcode::G_INTTOPTR: case TargetOpcode::G_PTRTOINT: if (DstTy.isVector()) diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 137922aa62557..523ff2e55aa0e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -3852,16 +3852,11 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, // fshl: (X << (Z % BW)) | (Y >> (BW - (Z % BW))) // fshr: (X << (BW - (Z % BW))) | (Y >> (Z % BW)) + const APInt ShAmt(BitWidth, Amt); Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); - if (Opcode == ISD::FSHL) { - Known <<= Amt; - Known2 >>= BitWidth - Amt; - } else { - Known <<= BitWidth - Amt; - Known2 >>= Amt; - } - Known = Known.unionWith(Known2); + Known = Opcode == ISD::FSHL ? KnownBits::fshl(Known, Known2, ShAmt) + : KnownBits::fshr(Known, Known2, ShAmt); } break; case ISD::SHL_PARTS: diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp index 07e7781d0839d..b1b985b80cffd 100644 --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -603,6 +603,18 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS, return Known; } +KnownBits KnownBits::fshl(const KnownBits &LHS, const KnownBits &RHS, + const APInt &Amt) { + return KnownBits(APIntOps::fshl(LHS.Zero, RHS.Zero, Amt), + APIntOps::fshl(LHS.One, RHS.One, Amt)); +} + +KnownBits KnownBits::fshr(const KnownBits &LHS, const KnownBits &RHS, + const APInt &Amt) { + return KnownBits(APIntOps::fshr(LHS.Zero, RHS.Zero, Amt), + APIntOps::fshr(LHS.One, RHS.One, Amt)); +} + KnownBits KnownBits::clmul(const KnownBits &LHS, const KnownBits &RHS) { KnownBits Res = makeConstant(APIntOps::clmul(LHS.getMinValue(), RHS.getMinValue())); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-fshl-fshr.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-fshl-fshr.mir new file mode 100644 index 0000000000000..202a40831145e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-fshl-fshr.mir @@ -0,0 +1,295 @@ +# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 6 +# RUN: llc -mtriple aarch64 -passes="print" %s -o - 2>&1 | FileCheck %s + +--- +name: Cst +body: | + bb.1: + ; CHECK-LABEL: name: @Cst + ; CHECK-NEXT: %0:_ KnownBits:11100000 SignBits:3 + ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 + ; CHECK-NEXT: %2:_ KnownBits:00000010 SignBits:6 + ; CHECK-NEXT: %3:_ KnownBits:10000000 SignBits:1 + %0:_(s8) = G_CONSTANT i8 224 + %1:_(s8) = G_CONSTANT i8 15 + %2:_(s8) = G_CONSTANT i8 2 + %3:_(s8) = G_FSHL %0, %1, %2 +... +--- +name: CstBig +body: | + bb.1: + ; CHECK-LABEL: name: @CstBig + ; CHECK-NEXT: %0:_ KnownBits:11111001 SignBits:5 + ; CHECK-NEXT: %1:_ KnownBits:11100000 SignBits:3 + ; CHECK-NEXT: %2:_ KnownBits:00000110 SignBits:5 + ; CHECK-NEXT: %3:_ KnownBits:01111000 SignBits:1 + %0:_(s8) = G_CONSTANT i8 249 + %1:_(s8) = G_CONSTANT i8 224 + %2:_(s8) = G_CONSTANT i8 6 + %3:_(s8) = G_FSHL %0, %1, %2 +... +--- +name: CstSext +body: | + bb.1: + ; CHECK-LABEL: name: @CstSext + ; CHECK-NEXT: %0:_ KnownBits:10000001 SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5 + ; CHECK-NEXT: %2:_ KnownBits:11111000 SignBits:5 + ; CHECK-NEXT: %3:_ KnownBits:11100000 SignBits:3 + ; CHECK-NEXT: %4:_ KnownBits:00000011 SignBits:6 + ; CHECK-NEXT: %5:_ KnownBits:11000111 SignBits:2 + %0:_(s8) = G_CONSTANT i8 129 + %1:_(s8) = G_CONSTANT i8 4 + %2:_(s8) = G_ASHR %0, %1 + %3:_(s8) = G_CONSTANT i8 224 + %4:_(s8) = G_CONSTANT i8 3 + %5:_(s8) = G_FSHL %2, %3, %4 +... +--- +name: CstSextBig +body: | + bb.1: + ; CHECK-LABEL: name: @CstSextBig + ; CHECK-NEXT: %0:_ KnownBits:10000001 SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5 + ; CHECK-NEXT: %2:_ KnownBits:11111000 SignBits:5 + ; CHECK-NEXT: %3:_ KnownBits:11100000 SignBits:3 + ; CHECK-NEXT: %4:_ KnownBits:00000110 SignBits:5 + ; CHECK-NEXT: %5:_ KnownBits:00111000 SignBits:2 + %0:_(s8) = G_CONSTANT i8 129 + %1:_(s8) = G_CONSTANT i8 4 + %2:_(s8) = G_ASHR %0, %1 + %3:_(s8) = G_CONSTANT i8 224 + %4:_(s8) = G_CONSTANT i8 6 + %5:_(s8) = G_FSHL %2, %3, %4 +... +--- +name: ScalarVar +body: | + bb.1: + ; CHECK-LABEL: name: @ScalarVar + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s8) = G_FSHL %0, %0, %1 +... +--- +name: ScalarCst +body: | + bb.1: + ; CHECK-LABEL: name: @ScalarCst + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:00000011 SignBits:6 + ; CHECK-NEXT: %3:_ KnownBits:???????? SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s8) = G_CONSTANT i8 3 + %3:_(s8) = G_FSHL %0, %1, %2 +... +--- +name: VectorSimple +body: | + bb.1: + ; CHECK-LABEL: name: @VectorSimple + ; CHECK-NEXT: %0:_ KnownBits:0000000000010011 SignBits:11 + ; CHECK-NEXT: %1:_ KnownBits:1111111100000000 SignBits:8 + ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %3:_ KnownBits:0000000000010011 SignBits:11 + ; CHECK-NEXT: %4:_ KnownBits:1111111100000000 SignBits:8 + ; CHECK-NEXT: %5:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %6:_ KnownBits:0000000010011111 SignBits:8 + %0:_(s16) = G_CONSTANT i16 19 + %1:_(s16) = G_CONSTANT i16 65280 + %2:_(s16) = G_CONSTANT i16 3 + %3:_(<4 x s16>) = G_BUILD_VECTOR %0, %0, %0, %0 + %4:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1 + %5:_(<4 x s16>) = G_BUILD_VECTOR %2, %2, %2, %2 + %6:_(<4 x s16>) = G_FSHL %3, %4, %5 +... +--- +name: VectorCst +body: | + bb.1: + ; CHECK-LABEL: name: @VectorCst + ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %3:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1 + %0:_(<4 x s16>) = COPY $d0 + %1:_(<4 x s16>) = COPY $d1 + %2:_(s16) = G_CONSTANT i16 3 + %3:_(<4 x s16>) = G_BUILD_VECTOR %2, %2, %2, %2 + %4:_(<4 x s16>) = G_FSHL %0, %1, %3 +... +--- +name: VectorCst36 +body: | + bb.1: + ; CHECK-LABEL: name: @VectorCst36 + ; CHECK-NEXT: %0:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %1:_ KnownBits:0000000000000110 SignBits:13 + ; CHECK-NEXT: %2:_ KnownBits:0000000000000?1? SignBits:13 + ; CHECK-NEXT: %3:_ KnownBits:0000000000000?1? SignBits:13 + ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1 + %0:_(s16) = G_CONSTANT i16 3 + %1:_(s16) = G_CONSTANT i16 6 + %2:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0 + %3:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0 + %4:_(<4 x s16>) = G_FSHL %2, %2, %3 +... +--- +name: VectorCst3unknown +body: | + bb.1: + ; CHECK-LABEL: name: @VectorCst3unknown + ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %3:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1 + ; CHECK-NEXT: %5:_ KnownBits:???????????????? SignBits:1 + %0:_(<4 x s16>) = COPY $d0 + %1:_(<4 x s16>) = COPY $d1 + %2:_(s16) = COPY $h0 + %3:_(s16) = G_CONSTANT i16 3 + %4:_(<4 x s16>) = G_BUILD_VECTOR %2, %3, %3, %2 + %5:_(<4 x s16>) = G_FSHL %0, %1, %4 +... +--- +name: VectorSext +body: | + bb.1: + ; CHECK-LABEL: name: @VectorSext + ; CHECK-NEXT: %0:_ KnownBits:11101110 SignBits:3 + ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 + ; CHECK-NEXT: %2:_ KnownBits:1111111111101110 SignBits:11 + ; CHECK-NEXT: %3:_ KnownBits:0000000000001111 SignBits:12 + ; CHECK-NEXT: %4:_ KnownBits:1111111111101110 SignBits:11 + ; CHECK-NEXT: %5:_ KnownBits:0000000000001111 SignBits:12 + ; CHECK-NEXT: %6:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %7:_ KnownBits:0000000000000110 SignBits:13 + ; CHECK-NEXT: %8:_ KnownBits:0000000000000?1? SignBits:13 + ; CHECK-NEXT: %9:_ KnownBits:???????????????? SignBits:1 + %0:_(s8) = G_CONSTANT i8 238 + %1:_(s8) = G_CONSTANT i8 15 + %2:_(s16) = G_SEXT %0(s8) + %3:_(s16) = G_SEXT %1(s8) + %4:_(<4 x s16>) = G_BUILD_VECTOR %2, %2, %2, %2 + %5:_(<4 x s16>) = G_BUILD_VECTOR %3, %3, %3, %3 + %6:_(s16) = G_CONSTANT i16 3 + %7:_(s16) = G_CONSTANT i16 6 + %8:_(<4 x s16>) = G_BUILD_VECTOR %6, %7, %7, %6 + %9:_(<4 x s16>) = G_FSHL %4, %5, %8 +... +--- +name: FSHLless +body: | + bb.1: + ; CHECK-LABEL: name: @FSHLless + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %4:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %5:_ KnownBits:???????????????? SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s16) = G_SEXT %0(s8) + %3:_(s16) = G_SEXT %1(s8) + %4:_(s16) = G_CONSTANT i16 3 + %5:_(s16) = G_FSHL %2, %3, %4 +... +--- +name: FSHLeq +body: | + bb.1: + ; CHECK-LABEL: name: @FSHLeq + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %4:_ KnownBits:0000000000001000 SignBits:12 + ; CHECK-NEXT: %5:_ KnownBits:???????????????? SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s16) = G_SEXT %0(s8) + %3:_(s16) = G_SEXT %1(s8) + %4:_(s16) = G_CONSTANT i16 8 + %5:_(s16) = G_FSHL %2, %3, %4 +... +--- +name: FSHLmore +body: | + bb.1: + ; CHECK-LABEL: name: @FSHLmore + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:9 + ; CHECK-NEXT: %4:_ KnownBits:0000000000001101 SignBits:12 + ; CHECK-NEXT: %5:_ KnownBits:???????????????? SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s16) = G_SEXT %0(s8) + %3:_(s16) = G_SEXT %1(s8) + %4:_(s16) = G_CONSTANT i16 13 + %5:_(s16) = G_FSHL %2, %3, %4 +... +--- +name: SignBitsThroughZext +body: | + bb.1: + ; CHECK-LABEL: name: @SignBitsThroughZext + ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1 + ; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14 + ; CHECK-NEXT: %3:_ KnownBits:???????? SignBits:4 + ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:4 + ; CHECK-NEXT: %5:_ KnownBits:00000000???????? SignBits:8 + ; CHECK-NEXT: %6:_ KnownBits:00000000???????? SignBits:8 + ; CHECK-NEXT: %7:_ KnownBits:0000000000001000 SignBits:12 + ; CHECK-NEXT: %8:_ KnownBits:????????00000000 SignBits:1 + %0:_(s8) = COPY $b0 + %1:_(s8) = COPY $b1 + %2:_(s16) = G_CONSTANT i16 3 + %3:_(s8) = G_ASHR %0, %2 + %4:_(s8) = G_ASHR %1, %2 + %5:_(s16) = G_ZEXT %3 + %6:_(s16) = G_ZEXT %4 + %7:_(s16) = G_CONSTANT i16 8 + %8:_(s16) = G_FSHL %5, %6, %7 +... +--- +name: FSHLZeroAmt +body: | + bb.1: + ; CHECK-LABEL: name: @FSHLZeroAmt + ; CHECK-NEXT: %0:_ KnownBits:11100010 SignBits:3 + ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 + ; CHECK-NEXT: %2:_ KnownBits:00000000 SignBits:8 + ; CHECK-NEXT: %3:_ KnownBits:11100010 SignBits:3 + %0:_(s8) = G_CONSTANT i8 226 + %1:_(s8) = G_CONSTANT i8 15 + %2:_(s8) = G_CONSTANT i8 0 + %3:_(s8) = G_FSHL %0, %1, %2 +... +--- +name: FSHRZeroAmt +body: | + bb.1: + ; CHECK-LABEL: name: @FSHRZeroAmt + ; CHECK-NEXT: %0:_ KnownBits:11100010 SignBits:3 + ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4 + ; CHECK-NEXT: %2:_ KnownBits:00000000 SignBits:8 + ; CHECK-NEXT: %3:_ KnownBits:00001111 SignBits:4 + %0:_(s8) = G_CONSTANT i8 226 + %1:_(s8) = G_CONSTANT i8 15 + %2:_(s8) = G_CONSTANT i8 0 + %3:_(s8) = G_FSHR %0, %1, %2 +... diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll index 4fefef5e66155..7737f3c0510fd 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll @@ -1766,15 +1766,14 @@ define amdgpu_ps i48 @s_fshl_v2i24(i48 inreg %lhs.arg, i48 inreg %rhs.arg, i48 i ; GFX6-NEXT: s_lshr_b32 s7, s1, 8 ; GFX6-NEXT: s_or_b32 s8, s8, s9 ; GFX6-NEXT: s_and_b32 s6, s6, 0xff -; GFX6-NEXT: s_and_b32 s1, s1, 0xff -; GFX6-NEXT: v_mov_b32_e32 v0, s0 ; GFX6-NEXT: s_and_b32 s8, 0xffff, s8 ; GFX6-NEXT: s_lshl_b32 s6, s6, 16 -; GFX6-NEXT: v_alignbit_b32 v0, s1, v0, 24 +; GFX6-NEXT: s_and_b32 s1, s1, 0xff +; GFX6-NEXT: v_mov_b32_e32 v0, s0 ; GFX6-NEXT: s_and_b32 s0, s7, 0xff ; GFX6-NEXT: v_not_b32_e32 v3, 23 ; GFX6-NEXT: s_or_b32 s6, s8, s6 -; GFX6-NEXT: v_and_b32_e32 v0, 0xffff, v0 +; GFX6-NEXT: v_alignbit_b32 v0, s1, v0, 24 ; GFX6-NEXT: s_lshl_b32 s0, s0, 16 ; GFX6-NEXT: s_bfe_u32 s8, s2, 0x80008 ; GFX6-NEXT: v_mul_lo_u32 v4, v2, v3 @@ -1785,14 +1784,13 @@ define amdgpu_ps i48 @s_fshl_v2i24(i48 inreg %lhs.arg, i48 inreg %rhs.arg, i48 i ; GFX6-NEXT: s_lshr_b32 s1, s3, 8 ; GFX6-NEXT: s_or_b32 s7, s7, s8 ; GFX6-NEXT: s_and_b32 s0, s0, 0xff -; GFX6-NEXT: s_and_b32 s3, s3, 0xff -; GFX6-NEXT: v_mov_b32_e32 v1, s2 ; GFX6-NEXT: s_and_b32 s7, 0xffff, s7 ; GFX6-NEXT: s_lshl_b32 s0, s0, 16 -; GFX6-NEXT: v_alignbit_b32 v1, s3, v1, 24 +; GFX6-NEXT: s_and_b32 s3, s3, 0xff +; GFX6-NEXT: v_mov_b32_e32 v1, s2 ; GFX6-NEXT: s_and_b32 s1, s1, 0xff ; GFX6-NEXT: s_or_b32 s0, s7, s0 -; GFX6-NEXT: v_and_b32_e32 v1, 0xffff, v1 +; GFX6-NEXT: v_alignbit_b32 v1, s3, v1, 24 ; GFX6-NEXT: s_lshl_b32 s1, s1, 16 ; GFX6-NEXT: s_bfe_u32 s7, s4, 0x80008 ; GFX6-NEXT: v_mul_hi_u32 v4, v2, v4 @@ -1810,9 +1808,8 @@ define amdgpu_ps i48 @s_fshl_v2i24(i48 inreg %lhs.arg, i48 inreg %rhs.arg, i48 i ; GFX6-NEXT: s_lshr_b32 s2, s5, 8 ; GFX6-NEXT: s_and_b32 s3, s5, 0xff ; GFX6-NEXT: v_mov_b32_e32 v5, s4 -; GFX6-NEXT: v_alignbit_b32 v5, s3, v5, 24 ; GFX6-NEXT: s_and_b32 s2, s2, 0xff -; GFX6-NEXT: v_and_b32_e32 v5, 0xffff, v5 +; GFX6-NEXT: v_alignbit_b32 v5, s3, v5, 24 ; GFX6-NEXT: v_mul_lo_u32 v4, v4, 24 ; GFX6-NEXT: s_lshl_b32 s2, s2, 16 ; GFX6-NEXT: v_or_b32_e32 v5, s2, v5 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/fshr.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/fshr.ll index 6b8fc8675e8ac..df74cd4545e9e 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/fshr.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/fshr.ll @@ -1880,45 +1880,43 @@ define amdgpu_ps i48 @s_fshr_v2i24(i48 inreg %lhs.arg, i48 inreg %rhs.arg, i48 i ; GFX6-NEXT: v_readfirstlane_b32 s2, v0 ; GFX6-NEXT: v_cvt_f32_ubyte0_e32 v0, 24 ; GFX6-NEXT: v_rcp_iflag_f32_e32 v0, v0 +; GFX6-NEXT: s_and_b32 s3, s9, 0xff ; GFX6-NEXT: s_lshl_b32 s11, s11, 8 ; GFX6-NEXT: s_and_b32 s7, s7, 0xff -; GFX6-NEXT: s_and_b32 s3, s9, 0xff +; GFX6-NEXT: s_and_b32 s3, 0xffff, s3 ; GFX6-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0 -; GFX6-NEXT: v_cvt_u32_f32_e32 v0, v0 ; GFX6-NEXT: s_or_b32 s10, s10, s11 ; GFX6-NEXT: s_and_b32 s7, 0xffff, s7 -; GFX6-NEXT: s_and_b32 s3, 0xffff, s3 +; GFX6-NEXT: s_lshl_b32 s3, s3, 16 +; GFX6-NEXT: v_cvt_u32_f32_e32 v0, v0 ; GFX6-NEXT: s_and_b32 s10, 0xffff, s10 ; GFX6-NEXT: s_lshl_b32 s7, s7, 16 -; GFX6-NEXT: s_and_b32 s2, 0xffff, s2 -; GFX6-NEXT: s_lshl_b32 s3, s3, 16 -; GFX6-NEXT: s_or_b32 s7, s10, s7 ; GFX6-NEXT: s_or_b32 s2, s2, s3 ; GFX6-NEXT: s_lshr_b32 s3, s4, 16 -; GFX6-NEXT: s_lshr_b32 s9, s5, 8 -; GFX6-NEXT: s_and_b32 s10, s4, 0xff ; GFX6-NEXT: s_bfe_u32 s11, s4, 0x80008 -; GFX6-NEXT: s_and_b32 s5, s5, 0xff -; GFX6-NEXT: v_mov_b32_e32 v1, s4 -; GFX6-NEXT: v_readfirstlane_b32 s4, v0 -; GFX6-NEXT: v_alignbit_b32 v1, s5, v1, 24 -; GFX6-NEXT: s_mul_i32 s5, s4, 0xffffffe8 -; GFX6-NEXT: v_mul_hi_u32 v0, v0, s5 +; GFX6-NEXT: s_or_b32 s7, s10, s7 +; GFX6-NEXT: s_and_b32 s10, s4, 0xff ; GFX6-NEXT: s_lshl_b32 s11, s11, 8 ; GFX6-NEXT: s_and_b32 s3, s3, 0xff ; GFX6-NEXT: s_or_b32 s10, s10, s11 ; GFX6-NEXT: s_and_b32 s3, 0xffff, s3 ; GFX6-NEXT: s_and_b32 s10, 0xffff, s10 ; GFX6-NEXT: s_lshl_b32 s3, s3, 16 +; GFX6-NEXT: v_mov_b32_e32 v1, s4 +; GFX6-NEXT: v_readfirstlane_b32 s4, v0 ; GFX6-NEXT: s_or_b32 s3, s10, s3 +; GFX6-NEXT: s_mul_i32 s10, s4, 0xffffffe8 +; GFX6-NEXT: v_mul_hi_u32 v0, v0, s10 +; GFX6-NEXT: s_lshr_b32 s9, s5, 8 +; GFX6-NEXT: s_and_b32 s5, s5, 0xff +; GFX6-NEXT: s_and_b32 s9, s9, 0xff ; GFX6-NEXT: v_readfirstlane_b32 s10, v0 ; GFX6-NEXT: s_add_i32 s4, s4, s10 ; GFX6-NEXT: v_mov_b32_e32 v0, s4 ; GFX6-NEXT: v_mul_hi_u32 v0, s3, v0 -; GFX6-NEXT: s_and_b32 s9, s9, 0xff -; GFX6-NEXT: v_readfirstlane_b32 s5, v1 +; GFX6-NEXT: v_alignbit_b32 v1, s5, v1, 24 ; GFX6-NEXT: s_and_b32 s9, 0xffff, s9 -; GFX6-NEXT: s_and_b32 s5, 0xffff, s5 +; GFX6-NEXT: v_readfirstlane_b32 s5, v1 ; GFX6-NEXT: s_lshl_b32 s9, s9, 16 ; GFX6-NEXT: s_or_b32 s5, s5, s9 ; GFX6-NEXT: v_readfirstlane_b32 s9, v0 @@ -1926,7 +1924,6 @@ define amdgpu_ps i48 @s_fshr_v2i24(i48 inreg %lhs.arg, i48 inreg %rhs.arg, i48 i ; GFX6-NEXT: s_mul_i32 s9, s9, 24 ; GFX6-NEXT: s_and_b32 s8, 0xffff, s8 ; GFX6-NEXT: s_and_b32 s6, 0xffff, s6 -; GFX6-NEXT: s_and_b32 s0, 0xffff, s0 ; GFX6-NEXT: s_and_b32 s1, 0xffff, s1 ; GFX6-NEXT: s_sub_i32 s3, s3, s9 ; GFX6-NEXT: s_cmp_ge_u32 s3, 24 diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp index dc4a47d7cc562..0303b2f121c3b 100644 --- a/llvm/unittests/Support/KnownBitsTest.cpp +++ b/llvm/unittests/Support/KnownBitsTest.cpp @@ -673,6 +673,41 @@ TEST(KnownBitsTest, UnaryExhaustive) { [](const APInt &N) { return N * N; }, /*CheckOptimality=*/false); } +TEST(KnownBitsTest, FunnelShiftExhaustive) { + unsigned Bits = 4; + ForeachKnownBits(Bits, [&](const KnownBits &Known1) { + ForeachKnownBits(Bits, [&](const KnownBits &Known2) { + if (Known1.hasConflict() || Known2.hasConflict()) + return; + + for (unsigned ShAmt = 0; ShAmt < Bits; ShAmt++) { + KnownBits FSHLResult(Bits), FSHRResult(Bits); + FSHLResult.setAllConflict(); + FSHRResult.setAllConflict(); + + ForeachNumInKnownBits(Known1, [&](const APInt &N1) { + ForeachNumInKnownBits(Known2, [&](const APInt &N2) { + APInt FSHL = APIntOps::fshl(N1, N2, APInt(Bits, ShAmt)); + FSHLResult.One &= FSHL; + FSHLResult.Zero &= ~FSHL; + APInt FSHR = APIntOps::fshr(N1, N2, APInt(Bits, ShAmt)); + FSHRResult.One &= FSHR; + FSHRResult.Zero &= ~FSHR; + }); + }); + + const APInt Amt(Bits, ShAmt); + KnownBits ComputeFSHL = KnownBits::fshl(Known1, Known2, Amt); + KnownBits ComputeFSHR = KnownBits::fshr(Known1, Known2, Amt); + EXPECT_TRUE(FSHLResult.Zero.isSubsetOf(ComputeFSHL.Zero) && + FSHLResult.One.isSubsetOf(ComputeFSHL.One)); + EXPECT_TRUE(FSHRResult.Zero.isSubsetOf(ComputeFSHR.Zero) && + FSHRResult.One.isSubsetOf(ComputeFSHR.One)); + } + }); + }); +} + TEST(KnownBitsTest, WideShifts) { unsigned BitWidth = 128; KnownBits Unknown(BitWidth);