Skip to content

Commit c641b61

Browse files
authored
MIPSr6: Add llvm.is.fpclasss intrinsic support (#107857)
MIPSr6 has class.s/class.d instructions. Let's use them for llvm.is.fpclass intrinsic.
1 parent 69ed733 commit c641b61

File tree

4 files changed

+303
-2
lines changed

4 files changed

+303
-2
lines changed

llvm/lib/Target/Mips/Mips32r6InstrInfo.td

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,43 @@ let AdditionalPredicates = [NotInMicroMips] in {
11391139
ISA_MIPS32R6;
11401140
}
11411141

1142+
// llvm.is_fpclass operations.
1143+
def to_fclass_mask: SDNodeXForm<imm, [{
1144+
unsigned Check = N->getZExtValue();
1145+
unsigned Mask = 0;
1146+
if (Check & fcSNan)
1147+
Mask |= Mips::FClassMaskSignalingNaN;
1148+
if (Check & fcQNan)
1149+
Mask |= Mips::FClassMaskQuietNaN;
1150+
if (Check & fcPosInf)
1151+
Mask |= Mips::FClassMaskPositiveInfinity;
1152+
if (Check & fcNegInf)
1153+
Mask |= Mips::FClassMaskNegativeInfinity;
1154+
if (Check & fcPosNormal)
1155+
Mask |= Mips::FClassMaskPositiveNormal;
1156+
if (Check & fcNegNormal)
1157+
Mask |= Mips::FClassMaskNegativeNormal;
1158+
if (Check & fcPosSubnormal)
1159+
Mask |= Mips::FClassMaskPositiveSubnormal;
1160+
if (Check & fcNegSubnormal)
1161+
Mask |= Mips::FClassMaskNegativeSubnormal;
1162+
if (Check & fcPosZero)
1163+
Mask |= Mips::FClassMaskPositiveZero;
1164+
if (Check & fcNegZero)
1165+
Mask |= Mips::FClassMaskNegativeZero;
1166+
return CurDAG->getTargetConstant(Mask, SDLoc(N), MVT::i32);
1167+
}]>;
1168+
let AdditionalPredicates = [NotInMicroMips] in {
1169+
def : MipsPat<(is_fpclass f32:$lhs, i32:$imm),
1170+
(SLTu ZERO, (ANDi (MFC1 (CLASS_S f32:$lhs)),
1171+
(to_fclass_mask imm:$imm)))>,
1172+
ISA_MIPS32R6;
1173+
def : MipsPat<(is_fpclass f64:$lhs, i32:$imm),
1174+
(SLTu ZERO, (ANDi (MFC1_D64 (CLASS_D f64:$lhs)),
1175+
(to_fclass_mask imm:$imm)))>,
1176+
ISA_MIPS32R6;
1177+
}
1178+
11421179
// Pseudo instructions
11431180
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
11441181
hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT], hasPostISelHook = 1 in {

llvm/lib/Target/Mips/MipsISelLowering.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,7 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
359359
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom);
360360
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
361361

362-
// Lower fmin and fmax operations for MIPS R6.
363-
// Instructions are defined but never used.
362+
// Lower fmin/fmax/fclass operations for MIPS R6.
364363
if (Subtarget.hasMips32r6()) {
365364
setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
366365
setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
@@ -370,6 +369,8 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
370369
setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
371370
setOperationAction(ISD::FMINNUM, MVT::f64, Expand);
372371
setOperationAction(ISD::FMAXNUM, MVT::f64, Expand);
372+
setOperationAction(ISD::IS_FPCLASS, MVT::f32, Legal);
373+
setOperationAction(ISD::IS_FPCLASS, MVT::f64, Legal);
373374
} else {
374375
setOperationAction(ISD::FCANONICALIZE, MVT::f32, Custom);
375376
setOperationAction(ISD::FCANONICALIZE, MVT::f64, Custom);

llvm/lib/Target/Mips/MipsInstrInfo.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,23 @@ class MipsInstrInfo : public MipsGenInstrInfo {
213213
const MipsInstrInfo *createMips16InstrInfo(const MipsSubtarget &STI);
214214
const MipsInstrInfo *createMipsSEInstrInfo(const MipsSubtarget &STI);
215215

216+
namespace Mips {
217+
// Mask assignments for floating-point.
218+
enum FClassMask {
219+
FClassMaskSignalingNaN = 1 << 0,
220+
FClassMaskQuietNaN = 1 << 1,
221+
FClassMaskNegativeInfinity = 1 << 2,
222+
FClassMaskNegativeNormal = 1 << 3,
223+
FClassMaskNegativeSubnormal = 1 << 4,
224+
FClassMaskNegativeZero = 1 << 5,
225+
FClassMaskPositiveInfinity = 1 << 6,
226+
FClassMaskPositiveNormal = 1 << 7,
227+
FClassMaskPositiveSubnormal = 1 << 8,
228+
FClassMaskPositiveZero = 1 << 9
229+
};
230+
231+
} // namespace Mips
232+
216233
} // end namespace llvm
217234

218235
#endif // LLVM_LIB_TARGET_MIPS_MIPSINSTRINFO_H

llvm/test/CodeGen/Mips/is_fpclass.ll

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=mipsisa32r6-unknown-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s
3+
4+
5+
define i1 @isnan_float(float %x) nounwind {
6+
; CHECK-LABEL: isnan_float:
7+
; CHECK: # %bb.0:
8+
; CHECK-NEXT: class.s $f0, $f12
9+
; CHECK-NEXT: mfc1 $1, $f0
10+
; CHECK-NEXT: andi $1, $1, 3
11+
; CHECK-NEXT: jr $ra
12+
; CHECK-NEXT: sltu $2, $zero, $1
13+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; nan
14+
ret i1 %1
15+
}
16+
17+
define i1 @isnan_double(double %x) nounwind {
18+
; CHECK-LABEL: isnan_double:
19+
; CHECK: # %bb.0:
20+
; CHECK-NEXT: class.d $f0, $f12
21+
; CHECK-NEXT: mfc1 $1, $f0
22+
; CHECK-NEXT: andi $1, $1, 3
23+
; CHECK-NEXT: jr $ra
24+
; CHECK-NEXT: sltu $2, $zero, $1
25+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; nan
26+
ret i1 %1
27+
}
28+
29+
define i1 @isnan_float_strictfp(float %x) strictfp nounwind {
30+
; CHECK-LABEL: isnan_float_strictfp:
31+
; CHECK: # %bb.0:
32+
; CHECK-NEXT: class.s $f0, $f12
33+
; CHECK-NEXT: mfc1 $1, $f0
34+
; CHECK-NEXT: andi $1, $1, 3
35+
; CHECK-NEXT: jr $ra
36+
; CHECK-NEXT: sltu $2, $zero, $1
37+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) strictfp ; nan
38+
ret i1 %1
39+
}
40+
41+
define i1 @isnan_double_strictfp(double %x) strictfp nounwind {
42+
; CHECK-LABEL: isnan_double_strictfp:
43+
; CHECK: # %bb.0:
44+
; CHECK-NEXT: class.d $f0, $f12
45+
; CHECK-NEXT: mfc1 $1, $f0
46+
; CHECK-NEXT: andi $1, $1, 3
47+
; CHECK-NEXT: jr $ra
48+
; CHECK-NEXT: sltu $2, $zero, $1
49+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) strictfp ; nan
50+
ret i1 %1
51+
}
52+
53+
define i1 @isinf_float(float %x) nounwind {
54+
; CHECK-LABEL: isinf_float:
55+
; CHECK: # %bb.0:
56+
; CHECK-NEXT: class.s $f0, $f12
57+
; CHECK-NEXT: mfc1 $1, $f0
58+
; CHECK-NEXT: andi $1, $1, 68
59+
; CHECK-NEXT: jr $ra
60+
; CHECK-NEXT: sltu $2, $zero, $1
61+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 516) ; 0x204 = "inf"
62+
ret i1 %1
63+
}
64+
65+
define i1 @isfinite_float(float %x) nounwind {
66+
; CHECK-LABEL: isfinite_float:
67+
; CHECK: # %bb.0:
68+
; CHECK-NEXT: class.s $f0, $f12
69+
; CHECK-NEXT: mfc1 $1, $f0
70+
; CHECK-NEXT: andi $1, $1, 952
71+
; CHECK-NEXT: jr $ra
72+
; CHECK-NEXT: sltu $2, $zero, $1
73+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite"
74+
ret i1 %1
75+
}
76+
77+
define i1 @isnormal_float(float %x) nounwind {
78+
; CHECK-LABEL: isnormal_float:
79+
; CHECK: # %bb.0:
80+
; CHECK-NEXT: class.s $f0, $f12
81+
; CHECK-NEXT: mfc1 $1, $f0
82+
; CHECK-NEXT: andi $1, $1, 136
83+
; CHECK-NEXT: jr $ra
84+
; CHECK-NEXT: sltu $2, $zero, $1
85+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = "normal"
86+
ret i1 %1
87+
}
88+
89+
define i1 @issubnormal_float(float %x) nounwind {
90+
; CHECK-LABEL: issubnormal_float:
91+
; CHECK: # %bb.0:
92+
; CHECK-NEXT: class.s $f0, $f12
93+
; CHECK-NEXT: mfc1 $1, $f0
94+
; CHECK-NEXT: andi $1, $1, 272
95+
; CHECK-NEXT: jr $ra
96+
; CHECK-NEXT: sltu $2, $zero, $1
97+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 144) ; 0x90 = "subnormal"
98+
ret i1 %1
99+
}
100+
101+
define i1 @iszero_float(float %x) nounwind {
102+
; CHECK-LABEL: iszero_float:
103+
; CHECK: # %bb.0:
104+
; CHECK-NEXT: class.s $f0, $f12
105+
; CHECK-NEXT: mfc1 $1, $f0
106+
; CHECK-NEXT: andi $1, $1, 544
107+
; CHECK-NEXT: jr $ra
108+
; CHECK-NEXT: sltu $2, $zero, $1
109+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; 0x60 = "zero"
110+
ret i1 %1
111+
}
112+
113+
define i1 @issnan_float(float %x) nounwind {
114+
; CHECK-LABEL: issnan_float:
115+
; CHECK: # %bb.0:
116+
; CHECK-NEXT: class.s $f0, $f12
117+
; CHECK-NEXT: mfc1 $1, $f0
118+
; CHECK-NEXT: andi $1, $1, 1
119+
; CHECK-NEXT: jr $ra
120+
; CHECK-NEXT: sltu $2, $zero, $1
121+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 1)
122+
ret i1 %1
123+
}
124+
125+
define i1 @issnan_double(double %x) nounwind {
126+
; CHECK-LABEL: issnan_double:
127+
; CHECK: # %bb.0:
128+
; CHECK-NEXT: class.d $f0, $f12
129+
; CHECK-NEXT: mfc1 $1, $f0
130+
; CHECK-NEXT: andi $1, $1, 1
131+
; CHECK-NEXT: jr $ra
132+
; CHECK-NEXT: sltu $2, $zero, $1
133+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 1)
134+
ret i1 %1
135+
}
136+
137+
define i1 @isqnan_float(float %x) nounwind {
138+
; CHECK-LABEL: isqnan_float:
139+
; CHECK: # %bb.0:
140+
; CHECK-NEXT: class.s $f0, $f12
141+
; CHECK-NEXT: mfc1 $1, $f0
142+
; CHECK-NEXT: andi $1, $1, 2
143+
; CHECK-NEXT: jr $ra
144+
; CHECK-NEXT: sltu $2, $zero, $1
145+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 2)
146+
ret i1 %1
147+
}
148+
149+
define i1 @isqnan_double(double %x) nounwind {
150+
; CHECK-LABEL: isqnan_double:
151+
; CHECK: # %bb.0:
152+
; CHECK-NEXT: class.d $f0, $f12
153+
; CHECK-NEXT: mfc1 $1, $f0
154+
; CHECK-NEXT: andi $1, $1, 2
155+
; CHECK-NEXT: jr $ra
156+
; CHECK-NEXT: sltu $2, $zero, $1
157+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 2)
158+
ret i1 %1
159+
}
160+
161+
define i1 @isposzero_double(double %x) nounwind {
162+
; CHECK-LABEL: isposzero_double:
163+
; CHECK: # %bb.0:
164+
; CHECK-NEXT: class.d $f0, $f12
165+
; CHECK-NEXT: mfc1 $1, $f0
166+
; CHECK-NEXT: andi $1, $1, 512
167+
; CHECK-NEXT: jr $ra
168+
; CHECK-NEXT: sltu $2, $zero, $1
169+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 64)
170+
ret i1 %1
171+
}
172+
173+
define i1 @isnegzero_double(double %x) nounwind {
174+
; CHECK-LABEL: isnegzero_double:
175+
; CHECK: # %bb.0:
176+
; CHECK-NEXT: class.d $f0, $f12
177+
; CHECK-NEXT: mfc1 $1, $f0
178+
; CHECK-NEXT: andi $1, $1, 32
179+
; CHECK-NEXT: jr $ra
180+
; CHECK-NEXT: sltu $2, $zero, $1
181+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 32)
182+
ret i1 %1
183+
}
184+
185+
define i1 @isposnormal_double(double %x) nounwind {
186+
; CHECK-LABEL: isposnormal_double:
187+
; CHECK: # %bb.0:
188+
; CHECK-NEXT: class.d $f0, $f12
189+
; CHECK-NEXT: mfc1 $1, $f0
190+
; CHECK-NEXT: andi $1, $1, 128
191+
; CHECK-NEXT: jr $ra
192+
; CHECK-NEXT: sltu $2, $zero, $1
193+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 256)
194+
ret i1 %1
195+
}
196+
197+
define i1 @isnegnormal_double(double %x) nounwind {
198+
; CHECK-LABEL: isnegnormal_double:
199+
; CHECK: # %bb.0:
200+
; CHECK-NEXT: class.d $f0, $f12
201+
; CHECK-NEXT: mfc1 $1, $f0
202+
; CHECK-NEXT: andi $1, $1, 8
203+
; CHECK-NEXT: jr $ra
204+
; CHECK-NEXT: sltu $2, $zero, $1
205+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 8)
206+
ret i1 %1
207+
}
208+
209+
define i1 @isnormal_double(double %x) nounwind {
210+
; CHECK-LABEL: isnormal_double:
211+
; CHECK: # %bb.0:
212+
; CHECK-NEXT: class.d $f0, $f12
213+
; CHECK-NEXT: mfc1 $1, $f0
214+
; CHECK-NEXT: andi $1, $1, 136
215+
; CHECK-NEXT: jr $ra
216+
; CHECK-NEXT: sltu $2, $zero, $1
217+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 264)
218+
ret i1 %1
219+
}
220+
221+
define i1 @isclass_00d_double(double %x) nounwind {
222+
; CHECK-LABEL: isclass_00d_double:
223+
; CHECK: # %bb.0:
224+
; CHECK-NEXT: class.d $f0, $f12
225+
; CHECK-NEXT: mfc1 $1, $f0
226+
; CHECK-NEXT: andi $1, $1, 13
227+
; CHECK-NEXT: jr $ra
228+
; CHECK-NEXT: sltu $2, $zero, $1
229+
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 13)
230+
ret i1 %1
231+
}
232+
233+
define i1 @isclass_1c0_float(float %x) nounwind {
234+
; CHECK-LABEL: isclass_1c0_float:
235+
; CHECK: # %bb.0:
236+
; CHECK-NEXT: class.s $f0, $f12
237+
; CHECK-NEXT: mfc1 $1, $f0
238+
; CHECK-NEXT: andi $1, $1, 896
239+
; CHECK-NEXT: jr $ra
240+
; CHECK-NEXT: sltu $2, $zero, $1
241+
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 448)
242+
ret i1 %1
243+
}
244+
245+
declare i1 @llvm.is.fpclass.f32(float, i32)
246+
declare i1 @llvm.is.fpclass.f64(double, i32)

0 commit comments

Comments
 (0)