Skip to content

Commit f0c61d2

Browse files
wzssyqaYour Name
and
Your Name
authored
CodeGen: Add ISD::AssertNoFPClass (#135946)
It is used to mark a value that we are sure that it is not some fcType. The examples include: * An arguments of a function is marked with nofpclass * Output value of an intrinsic can be sure to not be some type So that the following operation can make some assumptions. --------- Co-authored-by: Your Name <you@example.com>
1 parent e28616a commit f0c61d2

File tree

10 files changed

+455
-3
lines changed

10 files changed

+455
-3
lines changed

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ enum NodeType {
6767
/// poisoned the assertion will not be true for that value.
6868
AssertAlign,
6969

70+
/// AssertNoFPClass - These nodes record if a register contains a float
71+
/// value that is known to be not some type.
72+
/// This node takes two operands. The first is the node that is known
73+
/// never to be some float types; the second is a constant value with
74+
/// the value of FPClassTest (casted to uint32_t).
75+
/// NOTE: In case of the source value (or any vector element value) is
76+
/// poisoned the assertion will not be true for that value.
77+
AssertNoFPClass,
78+
7079
/// Various leaf nodes.
7180
BasicBlock,
7281
VALUETYPE,

llvm/include/llvm/Target/TargetSelectionDAG.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ def SDT_assert : SDTypeProfile<1, 1,
868868
[SDTCisInt<0>, SDTCisInt<1>, SDTCisSameAs<1, 0>]>;
869869
def assertsext : SDNode<"ISD::AssertSext", SDT_assert>;
870870
def assertzext : SDNode<"ISD::AssertZext", SDT_assert>;
871+
def assertnofpclass : SDNode<"ISD::AssertNoFPClass", SDTFPUnaryOp>;
871872
def assertalign : SDNode<"ISD::AssertAlign", SDT_assert>;
872873

873874
def convergencectrl_anchor : SDNode<"ISD::CONVERGENCECTRL_ANCHOR",

llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
168168
case ISD::POISON:
169169
case ISD::UNDEF: R = SoftenFloatRes_UNDEF(N); break;
170170
case ISD::VAARG: R = SoftenFloatRes_VAARG(N); break;
171+
case ISD::AssertNoFPClass: R = GetSoftenedFloat(N->getOperand(0)); break;
171172
case ISD::VECREDUCE_FADD:
172173
case ISD::VECREDUCE_FMUL:
173174
case ISD::VECREDUCE_FMIN:
@@ -2576,6 +2577,7 @@ bool DAGTypeLegalizer::PromoteFloatOperand(SDNode *N, unsigned OpNo) {
25762577
R = PromoteFloatOp_FAKE_USE(N, OpNo);
25772578
break;
25782579
case ISD::FCOPYSIGN: R = PromoteFloatOp_FCOPYSIGN(N, OpNo); break;
2580+
case ISD::AssertNoFPClass:
25792581
case ISD::FP_TO_SINT:
25802582
case ISD::FP_TO_UINT:
25812583
case ISD::LROUND:
@@ -2803,6 +2805,7 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
28032805
case ISD::FTRUNC:
28042806
case ISD::FTAN:
28052807
case ISD::FTANH:
2808+
case ISD::AssertNoFPClass:
28062809
case ISD::FCANONICALIZE: R = PromoteFloatRes_UnaryOp(N); break;
28072810

28082811
// Binary FP Operations

llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
129129
case ISD::UINT_TO_FP:
130130
case ISD::ZERO_EXTEND:
131131
case ISD::FCANONICALIZE:
132+
case ISD::AssertNoFPClass:
132133
R = ScalarizeVecRes_UnaryOp(N);
133134
break;
134135
case ISD::ADDRSPACECAST:
@@ -1276,6 +1277,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
12761277
case ISD::UINT_TO_FP:
12771278
case ISD::VP_UINT_TO_FP:
12781279
case ISD::FCANONICALIZE:
1280+
case ISD::AssertNoFPClass:
12791281
SplitVecRes_UnaryOp(N, Lo, Hi);
12801282
break;
12811283
case ISD::ADDRSPACECAST:
@@ -4844,6 +4846,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
48444846
case ISD::FREEZE:
48454847
case ISD::ARITH_FENCE:
48464848
case ISD::FCANONICALIZE:
4849+
case ISD::AssertNoFPClass:
48474850
Res = WidenVecRes_Unary(N);
48484851
break;
48494852
case ISD::FMA: case ISD::VP_FMA:

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5832,6 +5832,15 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
58325832
return false;
58335833
return true;
58345834
}
5835+
case ISD::AssertNoFPClass: {
5836+
FPClassTest NoFPClass =
5837+
static_cast<FPClassTest>(Op.getConstantOperandVal(1));
5838+
if ((NoFPClass & fcNan) == fcNan)
5839+
return true;
5840+
if (SNaN && (NoFPClass & fcSNan) == fcSNan)
5841+
return true;
5842+
return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1);
5843+
}
58355844
default:
58365845
if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
58375846
Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
@@ -7486,6 +7495,16 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
74867495
N2.getOpcode() == ISD::TargetConstant && "Invalid FP_ROUND!");
74877496
if (N1.getValueType() == VT) return N1; // noop conversion.
74887497
break;
7498+
case ISD::AssertNoFPClass: {
7499+
assert(N1.getValueType().isFloatingPoint() &&
7500+
"AssertNoFPClass is used for a non-floating type");
7501+
assert(isa<ConstantSDNode>(N2) && "NoFPClass is not Constant");
7502+
FPClassTest NoFPClass = static_cast<FPClassTest>(N2->getAsZExtVal());
7503+
assert(llvm::to_underlying(NoFPClass) <=
7504+
BitmaskEnumDetail::Mask<FPClassTest>() &&
7505+
"FPClassTest value too large");
7506+
break;
7507+
}
74897508
case ISD::AssertSext:
74907509
case ISD::AssertZext: {
74917510
EVT EVT = cast<VTSDNode>(N2)->getVT();

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11829,9 +11829,18 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
1182911829
else if (Arg.hasAttribute(Attribute::ZExt))
1183011830
AssertOp = ISD::AssertZext;
1183111831

11832-
ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
11833-
PartVT, VT, nullptr, NewRoot,
11834-
F.getCallingConv(), AssertOp));
11832+
SDValue OutVal =
11833+
getCopyFromParts(DAG, dl, &InVals[i], NumParts, PartVT, VT, nullptr,
11834+
NewRoot, F.getCallingConv(), AssertOp);
11835+
11836+
FPClassTest NoFPClass = Arg.getNoFPClass();
11837+
if (NoFPClass != fcNone) {
11838+
SDValue SDNoFPClass = DAG.getTargetConstant(
11839+
static_cast<uint64_t>(NoFPClass), dl, MVT::i32);
11840+
OutVal = DAG.getNode(ISD::AssertNoFPClass, dl, OutVal.getValueType(),
11841+
OutVal, SDNoFPClass);
11842+
}
11843+
ArgValues.push_back(OutVal);
1183511844
}
1183611845

1183711846
i += NumParts;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
122122
case ISD::TokenFactor: return "TokenFactor";
123123
case ISD::AssertSext: return "AssertSext";
124124
case ISD::AssertZext: return "AssertZext";
125+
case ISD::AssertNoFPClass: return "AssertNoFPClass";
125126
case ISD::AssertAlign: return "AssertAlign";
126127

127128
case ISD::BasicBlock: return "BasicBlock";

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3265,6 +3265,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
32653265
return;
32663266
case ISD::AssertSext:
32673267
case ISD::AssertZext:
3268+
case ISD::AssertNoFPClass:
32683269
case ISD::AssertAlign:
32693270
ReplaceUses(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0));
32703271
CurDAG->RemoveDeadNode(NodeToMatch);
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc --mtriple=aarch64-linux-gnu < %s | FileCheck %s
3+
4+
define float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
5+
; CHECK-LABEL: f:
6+
; CHECK: // %bb.0: // %entry
7+
; CHECK-NEXT: fmaxnm s0, s0, s1
8+
; CHECK-NEXT: ret
9+
entry:
10+
%cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
11+
ret float %cond
12+
}
13+
14+
define <4 x float> @fv4f32(<4 x float> nofpclass(nan) %a, <4 x float> nofpclass(nan) %b) {
15+
; CHECK-LABEL: fv4f32:
16+
; CHECK: // %bb.0: // %entry
17+
; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
18+
; CHECK-NEXT: ret
19+
entry:
20+
%c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
21+
ret <4 x float> %c
22+
}
23+
24+
define {float, float} @m({float, float} nofpclass(nan) %a0, {float, float} nofpclass(nan) %a1) {
25+
; CHECK-LABEL: m:
26+
; CHECK: // %bb.0: // %entry
27+
; CHECK-NEXT: fmaxnm s1, s1, s3
28+
; CHECK-NEXT: fmaxnm s0, s0, s2
29+
; CHECK-NEXT: ret
30+
entry:
31+
%a0f0 = extractvalue {float, float} %a0, 0
32+
%a0f1 = extractvalue {float, float} %a0, 1
33+
%a1f0 = extractvalue {float, float} %a1, 0
34+
%a1f1 = extractvalue {float, float} %a1, 1
35+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
36+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
37+
%ret0 = insertvalue {float, float} poison, float %max0, 0
38+
%ret1 = insertvalue {float, float} %ret0, float %max1, 1
39+
ret {float, float} %ret1
40+
}
41+
42+
define [2 x float] @mA([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
43+
; CHECK-LABEL: mA:
44+
; CHECK: // %bb.0: // %entry
45+
; CHECK-NEXT: fmaxnm s1, s1, s3
46+
; CHECK-NEXT: fmaxnm s0, s0, s2
47+
; CHECK-NEXT: ret
48+
entry:
49+
%a0f0 = extractvalue [2 x float] %a0, 0
50+
%a0f1 = extractvalue [2 x float] %a0, 1
51+
%a1f0 = extractvalue [2 x float] %a1, 0
52+
%a1f1 = extractvalue [2 x float] %a1, 1
53+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
54+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
55+
%ret0 = insertvalue [2 x float] poison, float %max0, 0
56+
%ret1 = insertvalue [2 x float] %ret0, float %max1, 1
57+
ret [2 x float] %ret1
58+
}
59+
60+
define float @fS(float nofpclass(snan) %a, float nofpclass(snan) %b) {
61+
; CHECK-LABEL: fS:
62+
; CHECK: // %bb.0: // %entry
63+
; CHECK-NEXT: fmaxnm s0, s0, s1
64+
; CHECK-NEXT: ret
65+
entry:
66+
%cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
67+
ret float %cond
68+
}
69+
70+
define <4 x float> @fSv4f32(<4 x float> nofpclass(snan) %a, <4 x float> nofpclass(snan) %b) {
71+
; CHECK-LABEL: fSv4f32:
72+
; CHECK: // %bb.0: // %entry
73+
; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
74+
; CHECK-NEXT: ret
75+
entry:
76+
%c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
77+
ret <4 x float> %c
78+
}
79+
80+
define {float, float} @mS({float, float} nofpclass(snan) %a0, {float, float} nofpclass(snan) %a1) {
81+
; CHECK-LABEL: mS:
82+
; CHECK: // %bb.0: // %entry
83+
; CHECK-NEXT: fmaxnm s1, s1, s3
84+
; CHECK-NEXT: fmaxnm s0, s0, s2
85+
; CHECK-NEXT: ret
86+
entry:
87+
%a0f0 = extractvalue {float, float} %a0, 0
88+
%a0f1 = extractvalue {float, float} %a0, 1
89+
%a1f0 = extractvalue {float, float} %a1, 0
90+
%a1f1 = extractvalue {float, float} %a1, 1
91+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
92+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
93+
%ret0 = insertvalue {float, float} poison, float %max0, 0
94+
%ret1 = insertvalue {float, float} %ret0, float %max1, 1
95+
ret {float, float} %ret1
96+
}
97+
98+
define [2 x float] @mAS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
99+
; CHECK-LABEL: mAS:
100+
; CHECK: // %bb.0: // %entry
101+
; CHECK-NEXT: fmaxnm s1, s1, s3
102+
; CHECK-NEXT: fmaxnm s0, s0, s2
103+
; CHECK-NEXT: ret
104+
entry:
105+
%a0f0 = extractvalue [2 x float] %a0, 0
106+
%a0f1 = extractvalue [2 x float] %a0, 1
107+
%a1f0 = extractvalue [2 x float] %a1, 0
108+
%a1f1 = extractvalue [2 x float] %a1, 1
109+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
110+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
111+
%ret0 = insertvalue [2 x float] poison, float %max0, 0
112+
%ret1 = insertvalue [2 x float] %ret0, float %max1, 1
113+
ret [2 x float] %ret1
114+
}
115+
116+
define float @fQ(float nofpclass(qnan) %a, float nofpclass(qnan) %b) {
117+
; CHECK-LABEL: fQ:
118+
; CHECK: // %bb.0: // %entry
119+
; CHECK-NEXT: fminnm s1, s1, s1
120+
; CHECK-NEXT: fminnm s0, s0, s0
121+
; CHECK-NEXT: fmaxnm s0, s0, s1
122+
; CHECK-NEXT: ret
123+
entry:
124+
%cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
125+
ret float %cond
126+
}
127+
128+
define <4 x float> @fQv4f32(<4 x float> nofpclass(qnan) %a, <4 x float> nofpclass(qnan) %b) {
129+
; CHECK-LABEL: fQv4f32:
130+
; CHECK: // %bb.0: // %entry
131+
; CHECK-NEXT: fminnm v1.4s, v1.4s, v1.4s
132+
; CHECK-NEXT: fminnm v0.4s, v0.4s, v0.4s
133+
; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
134+
; CHECK-NEXT: ret
135+
entry:
136+
%c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
137+
ret <4 x float> %c
138+
}
139+
140+
define {float, float} @mQ({float, float} nofpclass(qnan) %a0, {float, float} nofpclass(qnan) %a1) {
141+
; CHECK-LABEL: mQ:
142+
; CHECK: // %bb.0: // %entry
143+
; CHECK-NEXT: fminnm s2, s2, s2
144+
; CHECK-NEXT: fminnm s0, s0, s0
145+
; CHECK-NEXT: fminnm s3, s3, s3
146+
; CHECK-NEXT: fminnm s1, s1, s1
147+
; CHECK-NEXT: fmaxnm s0, s0, s2
148+
; CHECK-NEXT: fmaxnm s1, s1, s3
149+
; CHECK-NEXT: ret
150+
entry:
151+
%a0f0 = extractvalue {float, float} %a0, 0
152+
%a0f1 = extractvalue {float, float} %a0, 1
153+
%a1f0 = extractvalue {float, float} %a1, 0
154+
%a1f1 = extractvalue {float, float} %a1, 1
155+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
156+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
157+
%ret0 = insertvalue {float, float} poison, float %max0, 0
158+
%ret1 = insertvalue {float, float} %ret0, float %max1, 1
159+
ret {float, float} %ret1
160+
}
161+
162+
define [2 x float] @mAQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
163+
; CHECK-LABEL: mAQ:
164+
; CHECK: // %bb.0: // %entry
165+
; CHECK-NEXT: fminnm s2, s2, s2
166+
; CHECK-NEXT: fminnm s0, s0, s0
167+
; CHECK-NEXT: fminnm s3, s3, s3
168+
; CHECK-NEXT: fminnm s1, s1, s1
169+
; CHECK-NEXT: fmaxnm s0, s0, s2
170+
; CHECK-NEXT: fmaxnm s1, s1, s3
171+
; CHECK-NEXT: ret
172+
entry:
173+
%a0f0 = extractvalue [2 x float] %a0, 0
174+
%a0f1 = extractvalue [2 x float] %a0, 1
175+
%a1f0 = extractvalue [2 x float] %a1, 0
176+
%a1f1 = extractvalue [2 x float] %a1, 1
177+
%max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
178+
%max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
179+
%ret0 = insertvalue [2 x float] poison, float %max0, 0
180+
%ret1 = insertvalue [2 x float] %ret0, float %max1, 1
181+
ret [2 x float] %ret1
182+
}

0 commit comments

Comments
 (0)