@@ -815,7 +815,7 @@ TEST(KnownBitsTest, ConcatBits) {
815815 }
816816}
817817
818- TEST (KnownBitsTest, MulExhaustive ) {
818+ TEST (KnownBitsTest, MulLowBitsExhaustive ) {
819819 for (unsigned Bits : {1 , 4 }) {
820820 ForeachKnownBits (Bits, [&](const KnownBits &Known1) {
821821 ForeachKnownBits (Bits, [&](const KnownBits &Known2) {
@@ -849,4 +849,54 @@ TEST(KnownBitsTest, MulExhaustive) {
849849 }
850850}
851851
852+ TEST (KnownBitsTest, MulHighBits) {
853+ unsigned Bits = 8 ;
854+ SmallVector<std::pair<int , int >, 4 > TestPairs = {
855+ {2 , 4 }, {-2 , -4 }, {2 , -4 }, {-2 , 4 }};
856+ for (auto [K1, K2] : TestPairs) {
857+ KnownBits Known1 (Bits), Known2 (Bits);
858+ if (K1 > 0 ) {
859+ // If we only set the zeros of ~K1, Known1 could be zero. Avoid this case,
860+ // as we can only set leading ones in the case where LHS and RHS have
861+ // different signs, when the result is known non-zero.
862+ Known1.Zero |= ~(K1 | 1 );
863+ Known1.One |= 1 ;
864+ } else {
865+ Known1.One |= K1;
866+ }
867+ if (K2 > 0 ) {
868+ // If we only set the zeros of ~K1, Known1 could be zero. Avoid this case,
869+ // as we can only set leading ones in the case where LHS and RHS have
870+ // different signs, when the result is known non-zero.
871+ Known2.Zero |= ~(K2 | 1 );
872+ Known2.One |= 1 ;
873+ } else {
874+ Known2.One |= K2;
875+ }
876+ KnownBits Computed = KnownBits::mul (Known1, Known2);
877+ KnownBits Exact (Bits);
878+ Exact.Zero .setAllBits ();
879+ Exact.One .setAllBits ();
880+
881+ ForeachNumInKnownBits (Known1, [&](const APInt &N1) {
882+ ForeachNumInKnownBits (Known2, [&](const APInt &N2) {
883+ APInt Res = N1 * N2;
884+ Exact.One &= Res;
885+ Exact.Zero &= ~Res;
886+ });
887+ });
888+
889+ // Check that the high bits are optimal, with the caveat that mul_ov of LHS
890+ // and RHS doesn't overflow, which is the case for our TestPairs.
891+ APInt Mask = APInt::getHighBitsSet (
892+ Bits, (Exact.Zero | Exact.One ).countLeadingOnes ());
893+ Exact.Zero &= Mask;
894+ Exact.One &= Mask;
895+ Computed.Zero &= Mask;
896+ Computed.One &= Mask;
897+ EXPECT_TRUE (checkResult (" mul" , Exact, Computed, {Known1, Known2},
898+ /* CheckOptimality=*/ true ));
899+ }
900+ }
901+
852902} // end anonymous namespace
0 commit comments