Skip to content

[SPARC] Use op-then-neg instructions when we have VIS3 #135717

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

Conversation

koachan
Copy link
Contributor

@koachan koachan commented Apr 15, 2025

No description provided.

Created using spr 1.3.5
@llvmbot
Copy link
Member

llvmbot commented Apr 15, 2025

@llvm/pr-subscribers-backend-sparc

Author: Koakuma (koachan)

Changes

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

2 Files Affected:

  • (modified) llvm/lib/Target/Sparc/SparcInstrVIS.td (+13)
  • (added) llvm/test/CodeGen/SPARC/float-vis3.ll (+59)
diff --git a/llvm/lib/Target/Sparc/SparcInstrVIS.td b/llvm/lib/Target/Sparc/SparcInstrVIS.td
index b806f0c413899..27f8358576789 100644
--- a/llvm/lib/Target/Sparc/SparcInstrVIS.td
+++ b/llvm/lib/Target/Sparc/SparcInstrVIS.td
@@ -316,4 +316,17 @@ def : Pat<(i64 (sext (i32 (bitconvert f32:$src)))), (MOVSTOSW $src)>;
 def : Pat<(f32 (bitconvert i32:$src)), (MOVWTOS $src)>;
 def : Pat<(i64 (bitconvert f64:$src)), (MOVDTOX $src)>;
 def : Pat<(f64 (bitconvert i64:$src)), (MOVXTOD $src)>;
+
+// OP-then-neg FP operations.
+def : Pat<(f32 (fneg (fadd f32:$rs1, f32:$rs2))), (FNADDS $rs1, $rs2)>;
+def : Pat<(f64 (fneg (fadd f64:$rs1, f64:$rs2))), (FNADDD $rs1, $rs2)>;
+def : Pat<(f32 (fneg (fmul f32:$rs1, f32:$rs2))), (FNMULS $rs1, $rs2)>;
+def : Pat<(f32 (fmul (fneg f32:$rs1), f32:$rs2)), (FNMULS $rs1, $rs2)>;
+def : Pat<(f32 (fmul f32:$rs1, (fneg f32:$rs2))), (FNMULS $rs1, $rs2)>;
+def : Pat<(f64 (fneg (fmul f64:$rs1, f64:$rs2))), (FNMULD $rs1, $rs2)>;
+def : Pat<(f64 (fmul (fneg f64:$rs1), f64:$rs2)), (FNMULD $rs1, $rs2)>;
+def : Pat<(f64 (fmul f64:$rs1, (fneg f64:$rs2))), (FNMULD $rs1, $rs2)>;
+def : Pat<(f64 (fneg (fmul (fpextend f32:$rs1), (fpextend f32:$rs2)))), (FNSMULD $rs1, $rs2)>;
+def : Pat<(f64 (fmul (fneg (fpextend f32:$rs1)), (fpextend f32:$rs2))), (FNSMULD $rs1, $rs2)>;
+def : Pat<(f64 (fmul (fpextend f32:$rs1), (fneg (fpextend f32:$rs2)))), (FNSMULD $rs1, $rs2)>;
 } // Predicates = [HasVIS3]
diff --git a/llvm/test/CodeGen/SPARC/float-vis3.ll b/llvm/test/CodeGen/SPARC/float-vis3.ll
new file mode 100644
index 0000000000000..bc9904dfa356a
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/float-vis3.ll
@@ -0,0 +1,59 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=sparc64 -mattr=+vis3 < %s | FileCheck %s
+
+define float @fnadds(float %a, float %b) nounwind {
+; CHECK-LABEL: fnadds:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    fnadds %f1, %f3, %f0
+entry:
+  %add = fadd float %a, %b
+  %fneg = fneg float %add
+  ret float %fneg
+}
+
+define double @fnaddd(double %a, double %b) nounwind {
+; CHECK-LABEL: fnaddd:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    fnaddd %f0, %f2, %f0
+entry:
+  %add = fadd double %a, %b
+  %fneg = fneg double %add
+  ret double %fneg
+}
+
+define float @fnmuls(float %a, float %b) nounwind {
+; CHECK-LABEL: fnmuls:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    fnmuls %f1, %f3, %f0
+entry:
+  %mul = fmul float %a, %b
+  %fneg = fneg float %mul
+  ret float %fneg
+}
+
+define double @fnmuld(double %a, double %b) nounwind {
+; CHECK-LABEL: fnmuld:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    fnmuld %f0, %f2, %f0
+entry:
+  %mul = fmul double %a, %b
+  %fneg = fneg double %mul
+  ret double %fneg
+}
+
+define double @fnsmuld(float %a, float %b) nounwind {
+; CHECK-LABEL: fnsmuld:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    fnsmuld %f1, %f3, %f0
+entry:
+  %conv.i = fpext float %a to double
+  %conv1.i = fpext float %b to double
+  %mul = fmul double %conv.i, %conv1.i
+  %fneg = fneg double %mul
+  ret double %fneg
+}

@koachan koachan requested review from brad0, rorth and s-barannikov April 15, 2025 00:52
Comment on lines 321 to 331
def : Pat<(f32 (fneg (fadd f32:$rs1, f32:$rs2))), (FNADDS $rs1, $rs2)>;
def : Pat<(f64 (fneg (fadd f64:$rs1, f64:$rs2))), (FNADDD $rs1, $rs2)>;
def : Pat<(f32 (fneg (fmul f32:$rs1, f32:$rs2))), (FNMULS $rs1, $rs2)>;
def : Pat<(f32 (fmul (fneg f32:$rs1), f32:$rs2)), (FNMULS $rs1, $rs2)>;
def : Pat<(f32 (fmul f32:$rs1, (fneg f32:$rs2))), (FNMULS $rs1, $rs2)>;
def : Pat<(f64 (fneg (fmul f64:$rs1, f64:$rs2))), (FNMULD $rs1, $rs2)>;
def : Pat<(f64 (fmul (fneg f64:$rs1), f64:$rs2)), (FNMULD $rs1, $rs2)>;
def : Pat<(f64 (fmul f64:$rs1, (fneg f64:$rs2))), (FNMULD $rs1, $rs2)>;
def : Pat<(f64 (fneg (fmul (fpextend f32:$rs1), (fpextend f32:$rs2)))), (FNSMULD $rs1, $rs2)>;
def : Pat<(f64 (fmul (fneg (fpextend f32:$rs1)), (fpextend f32:$rs2))), (FNSMULD $rs1, $rs2)>;
def : Pat<(f64 (fmul (fpextend f32:$rs1), (fneg (fpextend f32:$rs2)))), (FNSMULD $rs1, $rs2)>;
Copy link
Contributor Author

@koachan koachan Apr 15, 2025

Choose a reason for hiding this comment

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

A question: is there any sort of canonical form for which -(rs1*rs2)-type expressions will be converted to?
It feels excessive to have to list variants of it in this way.

Copy link
Contributor

Choose a reason for hiding this comment

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

I have little experience with floating point support in ISel yet. Maybe @arsenm can help here

Copy link
Contributor

Choose a reason for hiding this comment

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

fneg/fabs modifier folding is complex. We have both uses-into-defs and defs-into-uses patterns. The generic code has a conservative subset of foldable cases handled in getNegatedExpression, mostly dependent on what isFNegFree/isFAbsFree report. On AMDGPU we have a much more aggressive set of context dependent folds.

In general these are pushed up into the defs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think the backend tries to do anything fancy with FP, so probably it just passes expressions through getNegatedExpression.
That being said, on a quick reading of it:

  • -(a+b) can be turned into -a-b or -b-a, but only if we don't care about signed zeros.
  • -(a*b) will (?) be turned into -a*b or a*-b.

So I guess for multiplies I only need to handle the -a*b and a*-b variants, but for addition... is there a way to enable a pattern conditionally on Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros()?

Copy link
Contributor

Choose a reason for hiding this comment

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

You can write a pattern that checks the flags, but my broader point would be you should probably be implementing isFNegFree so all the default logic works

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I see that isFNegFree only passes the type of the value, I'm not sure how to check for it.
In this case I care less about types (it works for f32 and f64 equally well) and more about expressions (it's only free in the very specific cases of -(a+b) and -(a*b)). Is it still possible to do that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see that implementing isFNegFree makes it so that expressions involving negation doesn't get rewritten, thanks.

@s-barannikov s-barannikov requested a review from arsenm April 15, 2025 01:47
Created using spr 1.3.5
%mul = fmul double %conv.i, %conv1.i
%fneg = fneg double %mul
ret double %fneg
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This set of tests doesn't look like it covers all the patterns here. Should you also cover vectors to see these patterns still work after scalarization?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added some tests for other patterns and vectors, is that enough?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's hard to verify test coverage when so much is in one patch, I would have done this one pattern per patch with precommitted tests so it's trivial to see that it's tested

@brad0 brad0 requested a review from arsenm April 20, 2025 04:44
@koachan
Copy link
Contributor Author

koachan commented Apr 26, 2025

Hmm, changing my approach here.
To make the patch much simpler, instead of trying to handle every combination of operations, this one will only handle the basic cases of literal -(a+b) and -(a*b).
Handling other equivalent patterns will be done in separate patches in the future.

@koachan
Copy link
Contributor Author

koachan commented May 3, 2025

Ping?

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

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

Not sure isFNegFree is doing anything in this patch, would be best to drop it and separately test the combines it enables

Comment on lines +3608 to +3612
bool SparcTargetLowering::isFNegFree(EVT VT) const {
if (Subtarget->isVIS3())
return VT == MVT::f32 || VT == MVT::f64;
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This ideally would be completely separate patch from the patterns. This enables independent combines

@koachan
Copy link
Contributor Author

koachan commented May 5, 2025

Not sure isFNegFree is doing anything in this patch, would be best to drop it and separately test the combines it enables

It prevents the multiplication tests from being rewritten into a*-b, a pattern that we currently don't handle.
Without it, the codegen wouldn't issue fnmuls/fnmuls/fnsmuld instructions.

@arsenm arsenm merged commit 6bedda9 into users/koachan/spr/main.sparc-use-op-then-neg-instructions-when-we-have-vis3 May 5, 2025
14 of 17 checks passed
@arsenm arsenm deleted the users/koachan/spr/sparc-use-op-then-neg-instructions-when-we-have-vis3 branch May 5, 2025 19:02
@koachan
Copy link
Contributor Author

koachan commented May 5, 2025

Wait did this get hand-merged? This PR was made by spr and I thing that made the commit landed in the wrong place, ahah~

@koachan koachan restored the users/koachan/spr/sparc-use-op-then-neg-instructions-when-we-have-vis3 branch May 5, 2025 22:26
@koachan koachan deleted the users/koachan/spr/sparc-use-op-then-neg-instructions-when-we-have-vis3 branch May 5, 2025 22:36
@koachan
Copy link
Contributor Author

koachan commented May 5, 2025

In any case, manually merged it just now.

@arsenm
Copy link
Contributor

arsenm commented May 6, 2025

I just hit the button. This also doesn't have the SPR generated comments in the description

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants