Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[SelectionDAG] Fix incorrect fold condition in foldSetCCWithFunnelShift. #137637

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Ruhung
Copy link
Contributor

@Ruhung Ruhung commented Apr 28, 2025

Proposed by 2ed1598:

fshl X, (or X, Y), C ==/!= 0 --> or (srl Y, BW-C), X ==/!= 0

This transformation is valid when (C%Bitwidth) != 0 , as verified by Alive2.

Fixes #136746

@Ruhung Ruhung marked this pull request as ready for review April 29, 2025 07:40
@llvmbot llvmbot added backend:AArch64 llvm:SelectionDAG SelectionDAGISel as well labels Apr 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 29, 2025

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-llvm-selectiondag

Author: Rux124 (Ruhung)

Changes

Proposed by 2ed1598:

fshl X, (or X, Y), C ==/!= 0 --> or (srl Y, BW-C), X ==/!= 0

This transformation is valid when C != 0, as verified by Alive2.

Fixes #136746


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

2 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (+2-1)
  • (modified) llvm/test/CodeGen/AArch64/setcc-fsh.ll (+12)
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 6930b54ddb14a..1e9fb1aa2ea61 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -4462,7 +4462,8 @@ static SDValue foldSetCCWithFunnelShift(EVT VT, SDValue N0, SDValue N1,
 
   unsigned BitWidth = N0.getScalarValueSizeInBits();
   auto *ShAmtC = isConstOrConstSplat(N0.getOperand(2));
-  if (!ShAmtC || ShAmtC->getAPIntValue().uge(BitWidth))
+  APInt AmtVal = ShAmtC->getAPIntValue();
+  if (!ShAmtC || AmtVal.uge(BitWidth) || AmtVal.isZero())
     return SDValue();
 
   // Canonicalize fshr as fshl to reduce pattern-matching.
diff --git a/llvm/test/CodeGen/AArch64/setcc-fsh.ll b/llvm/test/CodeGen/AArch64/setcc-fsh.ll
index 08bfe282703ff..f0cf775f5c2fa 100644
--- a/llvm/test/CodeGen/AArch64/setcc-fsh.ll
+++ b/llvm/test/CodeGen/AArch64/setcc-fsh.ll
@@ -248,3 +248,15 @@ define i1 @fshl_or_ne_2(i32 %x, i32 %y) {
   %r = icmp ne i32 %f, 2
   ret i1 %r
 }
+
+define i1 @fshr_0_or_eq_0(i16 %x, i16 %y) {
+; CHECK-LABEL: fshr_0_or_eq_0:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    tst w0, #0xffff
+; CHECK-NEXT:    cset w0, eq
+; CHECK-NEXT:    ret
+  %or = or i16 %x, %y
+  %f = call i16 @llvm.fshr.i16(i16 %or, i16 %x, i16 0)
+  %r = icmp eq i16 %f, 0
+  ret i1 %r
+}

Comment on lines 4465 to 4466
APInt AmtVal = ShAmtC->getAPIntValue();
if (!ShAmtC || AmtVal.uge(BitWidth) || AmtVal.isZero())
Copy link
Collaborator

@davemgreen davemgreen Apr 29, 2025

Choose a reason for hiding this comment

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

If can't access ShAmtC (through ShAmtC->getAPIntValue()) before testing that it is valid (through !ShAmtC).

Copy link
Contributor

Choose a reason for hiding this comment

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

A more precise way to implement this check would be to first reduce the shift amount modulo the bitwidth:

  unsigned ShAmt = ShAmtC->getAPIntValue().urem(BitWidth).getZExtValue();

and then bail out if it is zero.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If can't access ShAmtC (through ShAmtC->getAPIntValue()) before testing that it is valid (through !ShAmtC).

@davemgreen Done. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A more precise way to implement this check would be to first reduce the shift amount modulo the bitwidth:

  unsigned ShAmt = ShAmtC->getAPIntValue().urem(BitWidth).getZExtValue();

and then bail out if it is zero.

The shift amount needs to be less than BitWidth, so a modulo operation may not be necessary?

Copy link
Collaborator

Choose a reason for hiding this comment

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

A funnel shift will rotate around (so can be > bitwidth), a shift will produce poison if the shift amount is >= bitwidth. It looks like it might only be fshr that is incorrect, not fshl? We should have canonicalized the constant shift amount so it is probably OK either way so long as we fix the bug in non-canonical forms.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like it might only be fshr that is incorrect

What is "incorrect" here? (I was not pointing out a bug, just a way to make the implementation a bit simpler and handle more cases.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I didn't mean your suggestion was incorrect, just that it was only the fshr by 0 case that was incorrect in the original code (as it turns into a shift by 32-0, which turns into poison). The other cases did not look worth supporting to me as they are more likely to introduce more issues than letting the funnel shift by a constant canonicalize before optimizing it again, but if you want to go that route it sounds OK so long as the other code works with it.

Copy link
Contributor Author

@Ruhung Ruhung May 3, 2025

Choose a reason for hiding this comment

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

@jayfoad Sorry for the initial misunderstanding, it's OK to take the modulo first and then check whether it's zero. I've fixed it. Thanks!

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

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

LGTM if there are no other comments. Thanks

return SDValue();

APInt AmtVal = ShAmtC->getAPIntValue();
if (AmtVal.uge(BitWidth) || AmtVal.isZero())
return SDValue();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not:

uint64_t AmtVal = ShAmtC->getAPIntValue().urem(BitWidth);
if (AmtVal == 0)
  return SDValue();

Copy link
Collaborator

Choose a reason for hiding this comment

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

From my point of view - just because it should not come up from non-canonical code IIUC, and so fixing the bug is the more important issue and trying to handle other cases that could lead to further bugs for little benefit. But it sounds OK so long as the rest of the code handles it correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@RKSimon You're right. It's OK to take the modulo first. I've fixed it. Thanks!

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 - cheers

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

Successfully merging this pull request may close these issues.

fshr-related miscompile by AArch64 backend
6 participants