1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
//===-- RISCVInstrInfoZfa.td - RISC-V 'Zfa' instructions ---*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file describes the RISC-V instructions from the standard 'Zfa'
// additional floating-point extension, version 1.0.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// RISC-V specific DAG Nodes.
//===----------------------------------------------------------------------===//
def SDT_RISCVFLI
: SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, XLenVT>]>;
// Zfa fli instruction for constant materialization.
def riscv_fli : RVSDNode<"FLI", SDT_RISCVFLI>;
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
//===----------------------------------------------------------------------===//
// 5-bit floating-point immediate encodings.
def LoadFPImmOperand : AsmOperandClass {
let Name = "LoadFPImm";
let ParserMethod = "parseFPImm";
let RenderMethod = "addFPImmOperands";
let DiagnosticType = "InvalidLoadFPImm";
let DiagnosticString = "operand must be a valid floating-point constant";
}
def loadfpimm : Operand<XLenVT> {
let ParserMatchClass = LoadFPImmOperand;
let PrintMethod = "printFPImmOperand";
let OperandType = "OPERAND_UIMM5";
let OperandNamespace = "RISCVOp";
}
def RTZArg : AsmOperandClass {
let Name = "RTZArg";
let RenderMethod = "addFRMArgOperands";
let DiagnosticType = "InvalidRTZArg";
let DiagnosticString = "operand must be 'rtz' floating-point rounding mode";
let ParserMethod = "parseFRMArg";
}
def rtzarg : Operand<XLenVT> {
let ParserMatchClass = RTZArg;
let PrintMethod = "printFRMArg";
let DecoderMethod = "decodeRTZArg";
let OperandType = "OPERAND_RTZARG";
let OperandNamespace = "RISCVOp";
}
//===----------------------------------------------------------------------===//
// Instruction class templates
//===----------------------------------------------------------------------===//
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in
class FPBinaryOp_rr<bits<7> funct7, bits<3> funct3, DAGOperand rdty,
DAGOperand rsty, string opcodestr>
: RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd),
(ins rsty:$rs1, rsty:$rs2), opcodestr, "$rd, $rs1, $rs2">;
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
class FPFLI_r<bits<7> funct7, bits<5> rs2val, bits<3> funct3,
DAGOperand rdty, string opcodestr>
: RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd),
(ins loadfpimm:$imm), opcodestr, "$rd, $imm"> {
bits<5> imm;
let rs2 = rs2val;
let rs1 = imm;
}
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
UseNamedOperandTable = 1, hasPostISelHook = 1 in
class FPUnaryOp_r_rtz<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,
DAGOperand rs1ty, string opcodestr>
: RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),
(ins rs1ty:$rs1, rtzarg:$frm), opcodestr,
"$rd, $rs1$frm"> {
let rs2 = rs2val;
}
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtZfa] in {
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def FLI_S : FPFLI_r<0b1111000, 0b00001, 0b000, FPR32, "fli.s">,
Sched<[WriteFLI32]>;
let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in {
def FMINM_S: FPALU_rr<0b0010100, 0b010, "fminm.s", FPR32, Commutable=1>;
def FMAXM_S: FPALU_rr<0b0010100, 0b011, "fmaxm.s", FPR32, Commutable=1>;
}
def FROUND_S : FPUnaryOp_r_frm<0b0100000, 0b00100, FPR32, FPR32, "fround.s">,
Sched<[WriteFRoundF32, ReadFRoundF32]>;
def FROUNDNX_S : FPUnaryOp_r_frm<0b0100000, 0b00101, FPR32, FPR32, "froundnx.s">,
Sched<[WriteFRoundF32, ReadFRoundF32]>;
let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in {
def FLTQ_S : FPCmp_rr<0b1010000, 0b101, "fltq.s", FPR32>;
def FLEQ_S : FPCmp_rr<0b1010000, 0b100, "fleq.s", FPR32>;
}
} // Predicates = [HasStdExtZfa]
let Predicates = [HasStdExtZfa, HasStdExtD] in {
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def FLI_D : FPFLI_r<0b1111001, 0b00001, 0b000, FPR64, "fli.d">,
Sched<[WriteFLI64]>;
let SchedRW = [WriteFMinMax64, ReadFMinMax64, ReadFMinMax64] in {
def FMINM_D: FPALU_rr<0b0010101, 0b010, "fminm.d", FPR64, Commutable=1>;
def FMAXM_D: FPALU_rr<0b0010101, 0b011, "fmaxm.d", FPR64, Commutable=1>;
}
def FROUND_D : FPUnaryOp_r_frm<0b0100001, 0b00100, FPR64, FPR64, "fround.d">,
Sched<[WriteFRoundF64, ReadFRoundF64]>;
def FROUNDNX_D : FPUnaryOp_r_frm<0b0100001, 0b00101, FPR64, FPR64, "froundnx.d">,
Sched<[WriteFRoundF64, ReadFRoundF64]>;
let IsSignExtendingOpW = 1 in
def FCVTMOD_W_D
: FPUnaryOp_r_rtz<0b1100001, 0b01000, GPR, FPR64, "fcvtmod.w.d">,
Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>;
let SchedRW = [WriteFCmp64, ReadFCmp64, ReadFCmp64] in {
def FLTQ_D : FPCmp_rr<0b1010001, 0b101, "fltq.d", FPR64>;
def FLEQ_D : FPCmp_rr<0b1010001, 0b100, "fleq.d", FPR64>;
}
} // Predicates = [HasStdExtZfa, HasStdExtD]
let Predicates = [HasStdExtZfa, HasStdExtD, IsRV32] in {
let mayRaiseFPException = 0 in {
def FMVH_X_D : FPUnaryOp_r<0b1110001, 0b00001, 0b000, GPR, FPR64, "fmvh.x.d">,
Sched<[WriteFMovF64ToI64, ReadFMovF64ToI64]>;
def FMVP_D_X : FPBinaryOp_rr<0b1011001, 0b000, FPR64, GPR, "fmvp.d.x">,
Sched<[WriteFMovI64ToF64, ReadFMovI64ToF64, ReadFMovI64ToF64]>;
}
let isCodeGenOnly = 1, mayRaiseFPException = 0 in
def FMV_X_W_FPR64 : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR64,
"fmv.x.w">,
Sched<[WriteFMovF64ToI64, ReadFMovF64ToI64]>;
} // Predicates = [HasStdExtZfa, HasStdExtD, IsRV32]
let Predicates = [HasStdExtZfa, HasStdExtZfhOrZvfh] in
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def FLI_H : FPFLI_r<0b1111010, 0b00001, 0b000, FPR16, "fli.h">,
Sched<[WriteFLI16]>;
let Predicates = [HasStdExtZfa, HasStdExtZfh] in {
let SchedRW = [WriteFMinMax16, ReadFMinMax16, ReadFMinMax16] in {
def FMINM_H: FPALU_rr<0b0010110, 0b010, "fminm.h", FPR16, Commutable=1>;
def FMAXM_H: FPALU_rr<0b0010110, 0b011, "fmaxm.h", FPR16, Commutable=1>;
}
def FROUND_H : FPUnaryOp_r_frm<0b0100010, 0b00100, FPR16, FPR16, "fround.h">,
Sched<[WriteFRoundF16, ReadFRoundF16]>;
def FROUNDNX_H : FPUnaryOp_r_frm<0b0100010, 0b00101, FPR16, FPR16, "froundnx.h">,
Sched<[WriteFRoundF16, ReadFRoundF16]>;
let SchedRW = [WriteFCmp16, ReadFCmp16, ReadFCmp16] in {
def FLTQ_H : FPCmp_rr<0b1010010, 0b101, "fltq.h", FPR16>;
def FLEQ_H : FPCmp_rr<0b1010010, 0b100, "fleq.h", FPR16>;
}
} // Predicates = [HasStdExtZfa, HasStdExtZfh]
let Predicates = [HasStdExtZfa, HasStdExtQ] in {
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def FLI_Q : FPFLI_r<0b1111011, 0b00001, 0b000, FPR128, "fli.q">,
Sched<[WriteFLI128]>;
let SchedRW = [WriteFMinMax128, ReadFMinMax128, ReadFMinMax128] in {
def FMINM_Q: FPALU_rr<0b0010111, 0b010, "fminm.q", FPR128, Commutable=1>;
def FMAXM_Q: FPALU_rr<0b0010111, 0b011, "fmaxm.q", FPR128, Commutable=1>;
}
def FROUND_Q : FPUnaryOp_r_frm<0b0100011, 0b00100, FPR128, FPR128, "fround.q">,
Sched<[WriteFRoundF128, ReadFRoundF128]>;
def FROUNDNX_Q : FPUnaryOp_r_frm<0b0100011, 0b00101, FPR128, FPR128,
"froundnx.q">,
Sched<[WriteFRoundF128, ReadFRoundF128]>;
let SchedRW = [WriteFCmp128, ReadFCmp128, ReadFCmp128] in {
def FLTQ_Q : FPCmp_rr<0b1010011, 0b101, "fltq.q", FPR128>;
def FLEQ_Q : FPCmp_rr<0b1010011, 0b100, "fleq.q", FPR128>;
}
} // Predicates = [HasStdExtZfa, HasStdExtQ]
let Predicates = [HasStdExtZfa, HasStdExtQ, IsRV64] in {
let mayRaiseFPException = 0 in {
def FMVH_X_Q : FPUnaryOp_r<0b1110011, 0b00001, 0b000, GPR, FPR128, "fmvh.x.q">;
def FMVP_Q_X : FPBinaryOp_rr<0b1011011, 0b000, FPR128, GPR, "fmvp.q.x">;
}
} // Predicates = [HasStdExtZfa, HasStdExtQ, IsRV64]
//===----------------------------------------------------------------------===//
// Pseudo-instructions and codegen patterns
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtZfa] in {
def : InstAlias<"fgtq.s $rd, $rs, $rt",
(FLTQ_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
def : InstAlias<"fgeq.s $rd, $rs, $rt",
(FLEQ_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
}
let Predicates = [HasStdExtZfa, HasStdExtD] in {
def : InstAlias<"fgtq.d $rd, $rs, $rt",
(FLTQ_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
def : InstAlias<"fgeq.d $rd, $rs, $rt",
(FLEQ_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
}
let Predicates = [HasStdExtZfa, HasStdExtZfh] in {
def : InstAlias<"fgtq.h $rd, $rs, $rt",
(FLTQ_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>;
def : InstAlias<"fgeq.h $rd, $rs, $rt",
(FLEQ_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>;
}
let Predicates = [HasStdExtZfa, HasStdExtQ] in {
def : InstAlias<"fgtq.q $rd, $rs, $rt",
(FLTQ_Q GPR:$rd, FPR128:$rt, FPR128:$rs), 0>;
def : InstAlias<"fgeq.q $rd, $rs, $rt",
(FLEQ_Q GPR:$rd, FPR128:$rt, FPR128:$rs), 0>;
}
//===----------------------------------------------------------------------===//
// Codegen patterns
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtZfa] in {
def: Pat<(f32 (riscv_fli timm:$imm)), (FLI_S timm:$imm)>;
def: PatFprFpr<fminimum, FMINM_S, FPR32, f32>;
def: PatFprFpr<fmaximum, FMAXM_S, FPR32, f32>;
// frint rounds according to the current rounding mode and detects
// inexact conditions.
def: Pat<(any_frint FPR32:$rs1), (FROUNDNX_S FPR32:$rs1, FRM_DYN)>;
// fnearbyint is like frint but does not detect inexact conditions.
def: Pat<(any_fnearbyint FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_DYN)>;
def: Pat<(any_fround FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_RMM)>;
def: Pat<(any_froundeven FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_RNE)>;
def: Pat<(any_ffloor FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_RDN)>;
def: Pat<(any_fceil FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_RUP)>;
def: Pat<(any_ftrunc FPR32:$rs1), (FROUND_S FPR32:$rs1, FRM_RTZ)>;
def: PatSetCC<FPR32, strict_fsetcc, SETLT, FLTQ_S, f32>;
def: PatSetCC<FPR32, strict_fsetcc, SETOLT, FLTQ_S, f32>;
def: PatSetCC<FPR32, strict_fsetcc, SETLE, FLEQ_S, f32>;
def: PatSetCC<FPR32, strict_fsetcc, SETOLE, FLEQ_S, f32>;
} // Predicates = [HasStdExtZfa]
let Predicates = [HasStdExtZfa, HasStdExtD] in {
def: Pat<(f64 (riscv_fli timm:$imm)), (FLI_D timm:$imm)>;
def: PatFprFpr<fminimum, FMINM_D, FPR64, f64>;
def: PatFprFpr<fmaximum, FMAXM_D, FPR64, f64>;
// frint rounds according to the current rounding mode and detects
// inexact conditions.
def: Pat<(any_frint FPR64:$rs1), (FROUNDNX_D FPR64:$rs1, FRM_DYN)>;
// fnearbyint is like frint but does not detect inexact conditions.
def: Pat<(any_fnearbyint FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_DYN)>;
def: Pat<(any_fround FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_RMM)>;
def: Pat<(any_froundeven FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_RNE)>;
def: Pat<(any_ffloor FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_RDN)>;
def: Pat<(any_fceil FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_RUP)>;
def: Pat<(any_ftrunc FPR64:$rs1), (FROUND_D FPR64:$rs1, FRM_RTZ)>;
def: PatSetCC<FPR64, strict_fsetcc, SETLT, FLTQ_D, f64>;
def: PatSetCC<FPR64, strict_fsetcc, SETOLT, FLTQ_D, f64>;
def: PatSetCC<FPR64, strict_fsetcc, SETLE, FLEQ_D, f64>;
def: PatSetCC<FPR64, strict_fsetcc, SETOLE, FLEQ_D, f64>;
} // Predicates = [HasStdExtZfa, HasStdExtD]
let Predicates = [HasStdExtZfa, HasStdExtD, IsRV32] in {
def : Pat<(RISCVBuildPairF64 GPR:$rs1, GPR:$rs2),
(FMVP_D_X GPR:$rs1, GPR:$rs2)>;
}
let Predicates = [HasStdExtZfa, HasStdExtZfh] in {
def: Pat<(f16 (riscv_fli timm:$imm)), (FLI_H timm:$imm)>;
def: PatFprFpr<fminimum, FMINM_H, FPR16, f16>;
def: PatFprFpr<fmaximum, FMAXM_H, FPR16, f16>;
// frint rounds according to the current rounding mode and detects
// inexact conditions.
def: Pat<(f16 (any_frint FPR16:$rs1)), (FROUNDNX_H FPR16:$rs1, FRM_DYN)>;
// fnearbyint is like frint but does not detect inexact conditions.
def: Pat<(f16 (any_fnearbyint FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_DYN)>;
def: Pat<(f16 (any_fround FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_RMM)>;
def: Pat<(f16 (any_froundeven FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_RNE)>;
def: Pat<(f16 (any_ffloor FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_RDN)>;
def: Pat<(f16 (any_fceil FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_RUP)>;
def: Pat<(f16 (any_ftrunc FPR16:$rs1)), (FROUND_H FPR16:$rs1, FRM_RTZ)>;
def: PatSetCC<FPR16, strict_fsetcc, SETLT, FLTQ_H, f16>;
def: PatSetCC<FPR16, strict_fsetcc, SETOLT, FLTQ_H, f16>;
def: PatSetCC<FPR16, strict_fsetcc, SETLE, FLEQ_H, f16>;
def: PatSetCC<FPR16, strict_fsetcc, SETOLE, FLEQ_H, f16>;
} // Predicates = [HasStdExtZfa, HasStdExtZfh]
|