-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[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
Created using spr 1.3.5
@llvm/pr-subscribers-backend-sparc Author: Koakuma (koachan) ChangesFull diff: https://github.com/llvm/llvm-project/pull/135717.diff 2 Files Affected:
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
+}
|
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)>; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
ora*-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()
?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
Created using spr 1.3.5
%mul = fmul double %conv.i, %conv1.i | ||
%fneg = fneg double %mul | ||
ret double %fneg | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
Created using spr 1.3.5
Created using spr 1.3.5
Hmm, changing my approach here. |
Ping? |
There was a problem hiding this 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
bool SparcTargetLowering::isFNegFree(EVT VT) const { | ||
if (Subtarget->isVIS3()) | ||
return VT == MVT::f32 || VT == MVT::f64; | ||
return false; | ||
} |
There was a problem hiding this comment.
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
It prevents the multiplication tests from being rewritten into |
6bedda9
into
users/koachan/spr/main.sparc-use-op-then-neg-instructions-when-we-have-vis3
Wait did this get hand-merged? This PR was made by |
In any case, manually merged it just now. |
I just hit the button. This also doesn't have the SPR generated comments in the description |
No description provided.