[llvm] IR: Add attribute negated (PR #121027)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 23 20:53:38 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-llvm-selectiondag
Author: YunQiang Su (wzssyqa)
<details>
<summary>Changes</summary>
For floating point operation `c-a*b` and `c+(-a)*b` may be different with `upward` or `downward` rounding.
Now we have only `fmuladd`, so Clang converts both of these 2 cases into
```
%neg = fneg double %a
%0 = tail call double @<!-- -->llvm.experimental.constrained.fmuladd.f64(double %neg, double %b, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
```
Let's introduce the attribute `negated` for the case `c-a*b` to mark the `%neg` is negated by the frontend instead of the user code itself. So that we can lowering `c-a*b` to `fmul` and `fsub`.
See: https://discourse.llvm.org/t/rfc-c-a-b-vs-a-b-c-for-strict-mode/83745/1
---
Full diff: https://github.com/llvm/llvm-project/pull/121027.diff
8 Files Affected:
- (modified) llvm/docs/LangRef.rst (+8)
- (modified) llvm/include/llvm/Bitcode/LLVMBitCodes.h (+1)
- (modified) llvm/include/llvm/IR/Attributes.td (+3)
- (modified) llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (+2)
- (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+19-1)
- (modified) llvm/lib/Transforms/Utils/CodeExtractor.cpp (+1)
- (added) llvm/test/CodeGen/Mips/attribute-negated.ll (+54)
- (added) llvm/test/CodeGen/X86/attribute-negated.ll (+72)
``````````diff
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7e01331b20c570..9e5f39530b1679 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1573,6 +1573,14 @@ Currently, only the following parameter attributes are defined:
| pinf | Positive infinity | 512 |
+-------+----------------------+---------------+
+``negated``
+ The function parameter marked with this attribute is negated from
+ its opposite number by the frontend like Clang. The middle end or
+ backend should convert it back if possible. For example, `c-a*b`
+ is different with `c+(-a)*b`. Since we have only `fmuladd`,
+ this attribute on `a` is to mark that we are working on `c-a*b`.
+ So that we can convert `c+(-a)*b` to `fmsub` instruction
+ or `fmul`/`fsub`.
``alignstack(<n>)``
This indicates the alignment that should be considered by the backend when
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 21fd27d9838db7..7e9d174db22026 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -788,6 +788,7 @@ enum AttributeKindCodes {
ATTR_KIND_NO_EXT = 99,
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
ATTR_KIND_SANITIZE_TYPE = 101,
+ ATTR_KIND_NEGATED = 102,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 61955cf883c3f1..baeca5d53f3c46 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -162,6 +162,9 @@ def Memory : IntAttr<"memory", IntersectCustom, [FnAttr]>;
/// Forbidden floating-point classes.
def NoFPClass : IntAttr<"nofpclass", IntersectCustom, [ParamAttr, RetAttr]>;
+/// Converted from the opposite number
+def Negated : EnumAttr<"negated", IntersectAnd, [ParamAttr, RetAttr]>;
+
/// Function must be optimized for size first.
def MinSize : EnumAttr<"minsize", IntersectPreserve, [FnAttr]>;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index b4efd3928a2e6f..e87c9d2e13883d 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -755,6 +755,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_MEMORY;
case Attribute::NoFPClass:
return bitc::ATTR_KIND_NOFPCLASS;
+ case Attribute::Negated:
+ return bitc::ATTR_KIND_NEGATED;
case Attribute::Naked:
return bitc::ATTR_KIND_NAKED;
case Attribute::Nest:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f8d7c3ef7bbe71..a9de7e25a4eb6a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -8360,10 +8360,28 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
// Break fmuladd into fmul and fadd.
if (TM.Options.AllowFPOpFusion == FPOpFusion::Strict ||
!TLI.isFMAFasterThanFMulAndFAdd(DAG.getMachineFunction(), VT)) {
+ auto PrevNode = FPI.getPrevNode();
+ bool convertToFMULSUB = false;
+ if (PrevNode && PrevNode->getOpcode() == Instruction::FNeg) {
+ if (PrevNode->getName() == FPI.getOperand(0)->getName() &&
+ FPI.getAttributes().getParamAttrs(0).hasAttribute(
+ Attribute::Negated)) {
+ Opers[1] = DAG.getNode(ISD::FNEG, sdl, VT, Opers[1]).getValue(0);
+ convertToFMULSUB = true;
+ } else if (PrevNode->getName() == FPI.getOperand(1)->getName() &&
+ FPI.getAttributes().getParamAttrs(1).hasAttribute(
+ Attribute::Negated)) {
+ Opers[2] = DAG.getNode(ISD::FNEG, sdl, VT, Opers[2]).getValue(0);
+ convertToFMULSUB = true;
+ }
+ }
Opers.pop_back();
SDValue Mul = DAG.getNode(ISD::STRICT_FMUL, sdl, VTs, Opers, Flags);
pushOutChain(Mul, EB);
- Opcode = ISD::STRICT_FADD;
+ if (convertToFMULSUB)
+ Opcode = ISD::STRICT_FSUB;
+ else
+ Opcode = ISD::STRICT_FADD;
Opers.clear();
Opers.push_back(Mul.getValue(1));
Opers.push_back(Mul.getValue(0));
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 7ddb9e22c83441..4e1a8c560078aa 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -918,6 +918,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::PresplitCoroutine:
case Attribute::Memory:
case Attribute::NoFPClass:
+ case Attribute::Negated:
case Attribute::CoroDestroyOnlyWhenComplete:
case Attribute::CoroElideSafe:
case Attribute::NoDivergenceSource:
diff --git a/llvm/test/CodeGen/Mips/attribute-negated.ll b/llvm/test/CodeGen/Mips/attribute-negated.ll
new file mode 100644
index 00000000000000..04f7257e446f9a
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/attribute-negated.ll
@@ -0,0 +1,54 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=mipsel -mattr=+fp64,+mips32r2 < %s \
+; RUN: | FileCheck %s --check-prefixes=CHECK
+
+define dso_local double @x1(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mul.d $f0, $f12, $f14
+; CHECK-NEXT: ldc1 $f1, 16($sp)
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: sub.d $f0, $f0, $f1
+entry:
+ %neg = fneg double %a
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double negated %neg, double %b, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x2(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x2:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mul.d $f0, $f12, $f14
+; CHECK-NEXT: ldc1 $f1, 16($sp)
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: sub.d $f0, $f0, $f1
+entry:
+ %neg = fneg double %b
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %a, double negated %neg, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x3(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x3:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: neg.d $f0, $f12
+; CHECK-NEXT: mul.d $f0, $f0, $f14
+; CHECK-NEXT: ldc1 $f1, 16($sp)
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: add.d $f0, $f0, $f1
+entry:
+ %neg = fneg double %a
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %neg, double %b, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x4(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x4:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: neg.d $f0, $f14
+; CHECK-NEXT: mul.d $f0, $f12, $f0
+; CHECK-NEXT: ldc1 $f1, 16($sp)
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: add.d $f0, $f0, $f1
+entry:
+ %neg = fneg double %b
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %a, double %neg, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
diff --git a/llvm/test/CodeGen/X86/attribute-negated.ll b/llvm/test/CodeGen/X86/attribute-negated.ll
new file mode 100644
index 00000000000000..b54b4b6f3c8bab
--- /dev/null
+++ b/llvm/test/CodeGen/X86/attribute-negated.ll
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=x86_64-- -mattr=-fma < %s \
+; RUN: | FileCheck %s --check-prefixes=CHECK
+; RUN: llc -mtriple=x86_64-- -mattr=+fma < %s \
+; RUN: | FileCheck %s --check-prefixes=CHECK-FMA
+
+define dso_local double @x1(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mulsd %xmm1, %xmm0
+; CHECK-NEXT: subsd %xmm2, %xmm0
+; CHECK-NEXT: retq
+;
+; CHECK-FMA-LABEL: x1:
+; CHECK-FMA: # %bb.0: # %entry
+; CHECK-FMA-NEXT: vfnmadd213sd {{.*#+}} xmm0 = -(xmm1 * xmm0) + xmm2
+; CHECK-FMA-NEXT: retq
+entry:
+ %neg = fneg double %a
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double negated %neg, double %b, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x2(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x2:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mulsd %xmm1, %xmm0
+; CHECK-NEXT: subsd %xmm2, %xmm0
+; CHECK-NEXT: retq
+;
+; CHECK-FMA-LABEL: x2:
+; CHECK-FMA: # %bb.0: # %entry
+; CHECK-FMA-NEXT: vfnmadd213sd {{.*#+}} xmm0 = -(xmm1 * xmm0) + xmm2
+; CHECK-FMA-NEXT: retq
+entry:
+ %neg = fneg double %b
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %a, double negated %neg, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x3(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x3:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xorpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-NEXT: mulsd %xmm1, %xmm0
+; CHECK-NEXT: addsd %xmm2, %xmm0
+; CHECK-NEXT: retq
+;
+; CHECK-FMA-LABEL: x3:
+; CHECK-FMA: # %bb.0: # %entry
+; CHECK-FMA-NEXT: vfnmadd213sd {{.*#+}} xmm0 = -(xmm1 * xmm0) + xmm2
+; CHECK-FMA-NEXT: retq
+entry:
+ %neg = fneg double %a
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %neg, double %b, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
+define dso_local double @x4(double noundef %a, double noundef %b, double noundef %c) local_unnamed_addr #0 {
+; CHECK-LABEL: x4:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xorpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; CHECK-NEXT: mulsd %xmm1, %xmm0
+; CHECK-NEXT: addsd %xmm2, %xmm0
+; CHECK-NEXT: retq
+;
+; CHECK-FMA-LABEL: x4:
+; CHECK-FMA: # %bb.0: # %entry
+; CHECK-FMA-NEXT: vfnmadd213sd {{.*#+}} xmm0 = -(xmm1 * xmm0) + xmm2
+; CHECK-FMA-NEXT: retq
+entry:
+ %neg = fneg double %b
+ %0 = tail call double @llvm.experimental.constrained.fmuladd.f64(double %a, double %neg, double %c, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+ ret double %0
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/121027
More information about the llvm-commits
mailing list