Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[llvm] Add KnownBits implementations for avgFloor and avgCeil #86445

Merged
merged 36 commits into from
May 19, 2024

Conversation

changkhothuychung
Copy link
Contributor

This PR is to address the issue #84640

@llvmbot
Copy link
Collaborator

llvmbot commented Mar 24, 2024

@llvm/pr-subscribers-llvm-selectiondag

@llvm/pr-subscribers-llvm-support

Author: Nhat Nguyen (changkhothuychung)

Changes

This PR is to address the issue #84640


Full diff: https://github.com/llvm/llvm-project/pull/86445.diff

1 Files Affected:

  • (modified) llvm/lib/Support/KnownBits.cpp (+40)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index d72355dab6f1d3..07c7ad0882387a 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -762,6 +762,46 @@ KnownBits KnownBits::usub_sat(const KnownBits &LHS, const KnownBits &RHS) {
   return computeForSatAddSub(/*Add*/ false, /*Signed*/ false, LHS, RHS);
 }
 
+KnownBits KnownBits::avgFloorS(const KnownBits &LHS, const KnownBits &RHS) {
+  // (C1 & C2) + (C1 ^ C2).ashr(1)
+  KnownBits andResult = LHS & RHS;
+  KnownBits xorResult = LHS ^ RHS;
+  xorResult.Zero.ashrInPlace(1);
+  xorResult.One.ashrInPlace(1);
+  return computeForSatAddSub(/*Add*/ true, /*Signed*/ true, andResult,
+                             xorResult);
+}
+
+KnownBits KnownBits::avgFloorU(const KnownBits &LHS, const KnownBits &RHS) {
+  // (C1 & C2) + (C1 ^ C2).lshr(1)
+  KnownBits andResult = LHS & RHS;
+  KnownBits xorResult = LHS ^ RHS;
+  xorResult.Zero.lshrInPlace(1);
+  xorResult.One.lshrInPlace(1);
+  return computeForSatAddSub(/*Add*/ true, /*Signed*/ false, andResult,
+                             xorResult);
+}
+
+KnownBits KnownBits::avgCeilS(const KnownBits &LHS, const KnownBits &RHS) {
+  // (C1 | C2) - (C1 ^ C2).ashr(1)
+  KnownBits andResult = LHS & RHS;
+  KnownBits xorResult = LHS ^ RHS;
+  xorResult.Zero.ashrInPlace(1);
+  xorResult.One.ashrInPlace(1);
+  return computeForSatAddSub(/*Add*/ false, /*Signed*/ true, andResult,
+                             xorResult);
+}
+
+KnownBits KnownBits::avgCeilU(const KnownBits &LHS, const KnownBits &RHS) {
+  // (C1 | C2) - (C1 ^ C2).lshr(1)
+  KnownBits andResult = LHS & RHS;
+  KnownBits xorResult = LHS ^ RHS;
+  xorResult.Zero.lshrInPlace(1);
+  xorResult.One.lshrInPlace(1);
+  return computeForSatAddSub(/*Add*/ false, /*Signed*/ false, andResult,
+                             xorResult);
+}
+
 KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
                          bool NoUndefSelfMultiply) {
   unsigned BitWidth = LHS.getBitWidth();

Copy link

✅ With the latest revision this PR passed the Python code formatter.

Copy link

github-actions bot commented Mar 24, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@changkhothuychung
Copy link
Contributor Author

@RKSimon RkSim
What type of test should I add, should it be similar to this test ?

TEST(KnownBitsTest, CommonBitsSet) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
bool HasCommonBitsSet = false;
ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
HasCommonBitsSet |= N1.intersects(N2);
});
});
EXPECT_EQ(!HasCommonBitsSet,
KnownBits::haveNoCommonBitsSet(Known1, Known2));
});
});
}

@changkhothuychung
Copy link
Contributor Author

@RKSimon Rkso
just following up on this!

@goldsteinn
Copy link
Contributor

goldsteinn commented Apr 1, 2024

@RKSimon RkSim What type of test should I add, should it be similar to this test ?

TEST(KnownBitsTest, CommonBitsSet) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
bool HasCommonBitsSet = false;
ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
HasCommonBitsSet |= N1.intersects(N2);
});
});
EXPECT_EQ(!HasCommonBitsSet,
KnownBits::haveNoCommonBitsSet(Known1, Known2));
});
});
}

Your unit tests should look something like:

  testBinaryOpExhaustive(KnownBits::abds, APIntOps::abds,
                         checkCorrectnessOnlyBinary);

The first argument is a function pointer to the knownbits function we are testing.
The second argument is a function pointer to the reference implementation on an APInt.
edit: both of the function pointers can be lambda's i.e:

  testBinaryOpExhaustive(
      [](const KnownBits &Known1, const KnownBits &Known2) {
        return KnownBits::udiv(Known1, Known2);
      },
      [](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
        if (N2.isZero())
          return std::nullopt;
        return N1.udiv(N2);
      },
      checkCorrectnessOnlyBinary);

The third is optional. If your implementation is complete (i.e proves all knowable bits) you can
drop it, otherwise just use what you see above. We like to strive for exhaustive, so if yours is not,
can you provide a few values that is fails for and explain a bit why its not really feasible?

Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#86754 has now landed so please can you update the SelectionDAG::computeKnownBits AVG cases to use KnowBits implementations

@llvmbot llvmbot added the llvm:SelectionDAG SelectionDAGISel as well label Apr 5, 2024
Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the KnownBitsTests failures

llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved
llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved

KnownBits KnownBits::avgCeilS(const KnownBits &LHS, const KnownBits &RHS) {
// (C1 | C2) - (C1 ^ C2).ashr(1)
KnownBits andResult = LHS | RHS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change name to OrResult. Variable names should be capitalised throughout.

/// Compute knownbits resulting from APIntOps::avgFloorU
static KnownBits avgFloorU(const KnownBits &LHS, const KnownBits &RHS);

/// Compute knownbits resulting from APIntOps::avgCelS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "Cel" here and below

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avgCel -> avgCeil

llvm/include/llvm/Support/KnownBits.h Outdated Show resolved Hide resolved
llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved
llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved
llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved
llvm/unittests/Support/KnownBitsTest.cpp Show resolved Hide resolved
Copy link
Contributor

@jayfoad jayfoad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me now except for the remaining cosmetic issues.

llvm/lib/Support/KnownBits.cpp Show resolved Hide resolved
llvm/lib/Support/KnownBits.cpp Outdated Show resolved Hide resolved
@goldsteinn
Copy link
Contributor

This LGTM, wait one 1 more approval to push.

@@ -475,7 +475,7 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
Known.Zero.setAllBits();
Known.One.setAllBits();
for (unsigned ShiftAmt = MinShiftAmount; ShiftAmt <= MaxShiftAmount;
++ShiftAmt) {
++ShiftAmt) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like spurious reformatting.

@changkhothuychung
Copy link
Contributor Author

changkhothuychung commented May 17, 2024

@jayfoad f
looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Link to failed CI: https://buildkite.com/llvm-project/github-pull-requests/builds/65024#018f86e0-35f7-4c66-bb68-14cd36220d70

@jayfoad
Copy link
Contributor

jayfoad commented May 17, 2024

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.

Patch LGTM anyway.

@jayfoad
Copy link
Contributor

jayfoad commented May 17, 2024

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.

Having looked into it, the unsigned functions are optimal. The signed ones are not because LHS/RHS.sext(BitWidth + 1) does not preserve the knowledge that the top two bits are the same.

We can look into improving that later. For now, it's fine to commit the patch with optimality checking removed.

@changkhothuychung
Copy link
Contributor Author

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.

Patch LGTM anyway.

I am assuming I need to put back the flag to disable optimality check ?

@goldsteinn
Copy link
Contributor

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.
Patch LGTM anyway.

I am assuming I need to put back the flag to disable optimality check ?

You already do. Its the bool argument.

@jayfoad
Copy link
Contributor

jayfoad commented May 19, 2024

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.

Patch LGTM anyway.

I am assuming I need to put back the flag to disable optimality check ?

Yes (at least for the signed functions CeilS and FloorS) because you can't commit with failing tests.

Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@changkhothuychung
Copy link
Contributor Author

looks like the BinaryExhaustive test fails when I remove the bool flag to enable Optimal check?

Oh, I thought this implementation was supposed to be optimal, but maybe I got that wrong.
Patch LGTM anyway.

I am assuming I need to put back the flag to disable optimality check ?

You already do. Its the bool argument.

I made a push to put it back after I made that comment.

@changkhothuychung
Copy link
Contributor Author

Thanks everyon! looks like I got 2 approves already, I will merge this PR shortly if there is no other concern.

@changkhothuychung changkhothuychung merged commit eab92cb into llvm:main May 19, 2024
4 checks passed
@changkhothuychung
Copy link
Contributor Author

@RKSimon RK
it looks like there is a failed build in later stages after the PR was merged - https://lab.llvm.org/buildbot/#/builders/185/builds/6813

Should we revert the changes?

@RKSimon
Copy link
Collaborator

RKSimon commented May 19, 2024

wait until the current build has finished to see if it was an intermittent fail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:SelectionDAG SelectionDAGISel as well llvm:support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants