1//===-- RISCVInstrInfoF.td - RISC-V 'F' instructions -------*- tablegen -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file describes the RISC-V instructions from the standard 'F', 10// Single-Precision Floating-Point instruction set extension. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15// RISC-V specific DAG Nodes. 16//===----------------------------------------------------------------------===// 17 18def SDT_RISCVFMV_W_X_RV64 19 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>; 20def SDT_RISCVFMV_X_ANYEXTW_RV64 21 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>; 22def SDT_RISCVFCVT_W_RV64 23 : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisFP<1>, 24 SDTCisVT<2, i64>]>; 25def SDT_RISCVFCVT_X 26 : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, SDTCisFP<1>, 27 SDTCisVT<2, XLenVT>]>; 28 29def riscv_fmv_w_x_rv64 30 : SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>; 31def riscv_fmv_x_anyextw_rv64 32 : SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>; 33def riscv_fcvt_w_rv64 34 : SDNode<"RISCVISD::FCVT_W_RV64", SDT_RISCVFCVT_W_RV64>; 35def riscv_fcvt_wu_rv64 36 : SDNode<"RISCVISD::FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64>; 37def riscv_fcvt_x 38 : SDNode<"RISCVISD::FCVT_X", SDT_RISCVFCVT_X>; 39def riscv_fcvt_xu 40 : SDNode<"RISCVISD::FCVT_XU", SDT_RISCVFCVT_X>; 41 42def riscv_strict_fcvt_w_rv64 43 : SDNode<"RISCVISD::STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64, 44 [SDNPHasChain]>; 45def riscv_strict_fcvt_wu_rv64 46 : SDNode<"RISCVISD::STRICT_FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64, 47 [SDNPHasChain]>; 48 49def riscv_any_fcvt_w_rv64 : PatFrags<(ops node:$src, node:$frm), 50 [(riscv_strict_fcvt_w_rv64 node:$src, node:$frm), 51 (riscv_fcvt_w_rv64 node:$src, node:$frm)]>; 52def riscv_any_fcvt_wu_rv64 : PatFrags<(ops node:$src, node:$frm), 53 [(riscv_strict_fcvt_wu_rv64 node:$src, node:$frm), 54 (riscv_fcvt_wu_rv64 node:$src, node:$frm)]>; 55 56//===----------------------------------------------------------------------===// 57// Operand and SDNode transformation definitions. 58//===----------------------------------------------------------------------===// 59 60// Zfinx 61 62def GPRAsFPR : AsmOperandClass { 63 let Name = "GPRAsFPR"; 64 let ParserMethod = "parseGPRAsFPR"; 65 let RenderMethod = "addRegOperands"; 66} 67 68def FPR32INX : RegisterOperand<GPRF32> { 69 let ParserMatchClass = GPRAsFPR; 70 let DecoderMethod = "DecodeGPRRegisterClass"; 71} 72 73// inx = 0 : f, d, zfh, zfhmin 74// = 1 : zfinx, zdinx, zhinx, zhinxmin 75// = 2 : zdinx_rv32 76class ExtInfo<bits<2> inx, list<Predicate> pres> { 77 string Suffix = !cond(!eq(inx, 0): "", 78 !eq(inx, 1): "_INX", 79 !eq(inx, 2): "_IN32X"); 80 list<Predicate> Predicates = pres; 81 string Space = !cond(!eq(inx, 0): "", 82 !eq(inx, 1): "RVZfinx", 83 !eq(inx, 2): "RV32Zdinx"); 84} 85 86class ExtInfo_r<ExtInfo ext, DAGOperand reg> { 87 string Suffix = ext.Suffix; 88 list<Predicate> Predicates = ext.Predicates; 89 string Space = ext.Space; 90 DAGOperand Reg = reg; 91} 92 93class ExtInfo_rr<ExtInfo ext, DAGOperand rdty, DAGOperand rs1ty> { 94 string Suffix = ext.Suffix; 95 list<Predicate> Predicates = ext.Predicates; 96 string Space = ext.Space; 97 DAGOperand RdTy = rdty; 98 DAGOperand Rs1Ty = rs1ty; 99} 100 101def FExt : ExtInfo<0, [HasStdExtF]>; 102def F64Ext : ExtInfo<0, [HasStdExtF, IsRV64]>; 103def ZfinxExt : ExtInfo<1, [HasStdExtZfinx]>; 104def Zfinx64Ext : ExtInfo<1, [HasStdExtZfinx, IsRV64]>; 105 106def F : ExtInfo_r<FExt, FPR32>; 107def F_INX : ExtInfo_r<ZfinxExt, FPR32INX>; 108 109def FF : ExtInfo_rr<FExt, FPR32, FPR32>; 110def FF_INX : ExtInfo_rr<ZfinxExt, FPR32INX, FPR32INX>; 111def FX : ExtInfo_rr<FExt, FPR32, GPR>; 112def FX_INX : ExtInfo_rr<ZfinxExt, FPR32INX, GPR>; 113def FX_64 : ExtInfo_rr<F64Ext, FPR32, GPR>; 114def FX_INX_64 : ExtInfo_rr<Zfinx64Ext, FPR32INX, GPR>; 115def XF : ExtInfo_rr<FExt, GPR, FPR32>; 116def XF_64 : ExtInfo_rr<F64Ext, GPR, FPR32>; 117def XF_INX : ExtInfo_rr<ZfinxExt, GPR, FPR32INX>; 118def XF_INX_64 : ExtInfo_rr<Zfinx64Ext, GPR, FPR32INX>; 119 120defvar FINX = [F, F_INX]; 121defvar FFINX = [FF, FF_INX]; 122defvar FXINX = [FX, FX_INX]; 123defvar XFINX = [XF, XF_INX]; 124defvar XFIN64X = [XF_64, XF_INX_64]; 125defvar FXIN64X = [FX_64, FX_INX_64]; 126 127// Floating-point rounding mode 128 129def FRMArg : AsmOperandClass { 130 let Name = "FRMArg"; 131 let RenderMethod = "addFRMArgOperands"; 132 let DiagnosticType = "InvalidFRMArg"; 133} 134 135def frmarg : Operand<XLenVT> { 136 let ParserMatchClass = FRMArg; 137 let PrintMethod = "printFRMArg"; 138 let DecoderMethod = "decodeFRMArg"; 139} 140 141//===----------------------------------------------------------------------===// 142// Instruction class templates 143//===----------------------------------------------------------------------===// 144 145let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 146class FPLoad_r<bits<3> funct3, string opcodestr, RegisterClass rty, 147 SchedWrite sw> 148 : RVInstI<funct3, OPC_LOAD_FP, (outs rty:$rd), 149 (ins GPR:$rs1, simm12:$imm12), 150 opcodestr, "$rd, ${imm12}(${rs1})">, 151 Sched<[sw, ReadFMemBase]>; 152 153let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in 154class FPStore_r<bits<3> funct3, string opcodestr, RegisterClass rty, 155 SchedWrite sw> 156 : RVInstS<funct3, OPC_STORE_FP, (outs), 157 (ins rty:$rs2, GPR:$rs1, simm12:$imm12), 158 opcodestr, "$rs2, ${imm12}(${rs1})">, 159 Sched<[sw, ReadStoreData, ReadFMemBase]>; 160 161let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 162 UseNamedOperandTable = 1, hasPostISelHook = 1 in 163class FPFMA_rrr_frm<RISCVOpcode opcode, bits<2> funct2, string opcodestr, 164 DAGOperand rty> 165 : RVInstR4Frm<funct2, opcode, (outs rty:$rd), 166 (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$frm), 167 opcodestr, "$rd, $rs1, $rs2, $rs3, $frm">; 168 169multiclass FPFMA_rrr_frm_m<RISCVOpcode opcode, bits<2> funct2, 170 string opcodestr, list<ExtInfo_r> Exts> { 171 foreach Ext = Exts in 172 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 173 def Ext.Suffix : FPFMA_rrr_frm<opcode, funct2, opcodestr, Ext.Reg>; 174} 175 176class FPFMADynFrmAlias<FPFMA_rrr_frm Inst, string OpcodeStr, 177 DAGOperand rty> 178 : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3", 179 (Inst rty:$rd, rty:$rs1, rty:$rs2, rty:$rs3, 0b111)>; 180multiclass FPFMADynFrmAlias_m<FPFMA_rrr_frm Inst, string OpcodeStr, 181 list<ExtInfo_r> Exts> { 182 foreach Ext = Exts in 183 let Predicates = Ext.Predicates in 184 def : FPFMADynFrmAlias<!cast<FPFMA_rrr_frm>(Inst#Ext.Suffix), OpcodeStr, 185 Ext.Reg>; 186} 187 188let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in 189class FPALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr, 190 DAGOperand rty> 191 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rty:$rd), 192 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2">; 193multiclass FPALU_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr, 194 list<ExtInfo_r> Exts> { 195 foreach Ext = Exts in 196 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 197 def Ext.Suffix : FPALU_rr<funct7, funct3, opcodestr, Ext.Reg>; 198} 199 200let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 201 UseNamedOperandTable = 1, hasPostISelHook = 1 in 202class FPALU_rr_frm<bits<7> funct7, string opcodestr, DAGOperand rty> 203 : RVInstRFrm<funct7, OPC_OP_FP, (outs rty:$rd), 204 (ins rty:$rs1, rty:$rs2, frmarg:$frm), opcodestr, 205 "$rd, $rs1, $rs2, $frm">; 206 207multiclass FPALU_rr_frm_m<bits<7> funct7, string opcodestr, 208 list<ExtInfo_r> Exts> { 209 foreach Ext = Exts in 210 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 211 def Ext.Suffix : FPALU_rr_frm<funct7, opcodestr, Ext.Reg>; 212} 213 214class FPALUDynFrmAlias<FPALU_rr_frm Inst, string OpcodeStr, 215 DAGOperand rty> 216 : InstAlias<OpcodeStr#" $rd, $rs1, $rs2", 217 (Inst rty:$rd, rty:$rs1, rty:$rs2, 0b111)>; 218multiclass FPALUDynFrmAlias_m<FPALU_rr_frm Inst, string OpcodeStr, 219 list<ExtInfo_r> Exts> { 220 foreach Ext = Exts in 221 let Predicates = Ext.Predicates in 222 def : FPALUDynFrmAlias<!cast<FPALU_rr_frm>(Inst#Ext.Suffix), OpcodeStr, 223 Ext.Reg>; 224} 225 226let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in 227class FPUnaryOp_r<bits<7> funct7, bits<5> rs2val, bits<3> funct3, 228 DAGOperand rdty, DAGOperand rs1ty, string opcodestr> 229 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd), (ins rs1ty:$rs1), 230 opcodestr, "$rd, $rs1"> { 231 let rs2 = rs2val; 232} 233multiclass FPUnaryOp_r_m<bits<7> funct7, bits<5> rs2val, bits<3> funct3, 234 list<ExtInfo_rr> Exts, string opcodestr> { 235 foreach Ext = Exts in 236 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 237 def Ext.Suffix : FPUnaryOp_r<funct7, rs2val, funct3, Ext.RdTy, Ext.Rs1Ty, 238 opcodestr>; 239} 240 241let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 242 UseNamedOperandTable = 1, hasPostISelHook = 1 in 243class FPUnaryOp_r_frm<bits<7> funct7, bits<5> rs2val, DAGOperand rdty, 244 DAGOperand rs1ty, string opcodestr> 245 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd), 246 (ins rs1ty:$rs1, frmarg:$frm), opcodestr, 247 "$rd, $rs1, $frm"> { 248 let rs2 = rs2val; 249} 250multiclass FPUnaryOp_r_frm_m<bits<7> funct7, bits<5> rs2val, 251 list<ExtInfo_rr> Exts, string opcodestr> { 252 foreach Ext = Exts in 253 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 254 def Ext.Suffix : FPUnaryOp_r_frm<funct7, rs2val, Ext.RdTy, Ext.Rs1Ty, 255 opcodestr>; 256} 257 258class FPUnaryOpDynFrmAlias<FPUnaryOp_r_frm Inst, string OpcodeStr, 259 DAGOperand rdty, DAGOperand rs1ty> 260 : InstAlias<OpcodeStr#" $rd, $rs1", 261 (Inst rdty:$rd, rs1ty:$rs1, 0b111)>; 262multiclass FPUnaryOpDynFrmAlias_m<FPUnaryOp_r_frm Inst, string OpcodeStr, 263 list<ExtInfo_rr> Exts> { 264 foreach Ext = Exts in 265 let Predicates = Ext.Predicates in 266 def : FPUnaryOpDynFrmAlias<!cast<FPUnaryOp_r_frm>(Inst#Ext.Suffix), 267 OpcodeStr, Ext.RdTy, Ext.Rs1Ty>; 268} 269 270let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in 271class FPCmp_rr<bits<7> funct7, bits<3> funct3, string opcodestr, 272 DAGOperand rty> 273 : RVInstR<funct7, funct3, OPC_OP_FP, (outs GPR:$rd), 274 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2">; 275multiclass FPCmp_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr, 276 list<ExtInfo_r> Exts> { 277 foreach Ext = Exts in 278 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 279 def Ext.Suffix : FPCmp_rr<funct7, funct3, opcodestr, Ext.Reg>; 280} 281 282//===----------------------------------------------------------------------===// 283// Instructions 284//===----------------------------------------------------------------------===// 285 286let Predicates = [HasStdExtF] in { 287def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>; 288 289// Operands for stores are in the order srcreg, base, offset rather than 290// reflecting the order these fields are specified in the instruction 291// encoding. 292def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>; 293} // Predicates = [HasStdExtF] 294 295let SchedRW = [WriteFMA32, ReadFMA32, ReadFMA32, ReadFMA32] in { 296defm FMADD_S : FPFMA_rrr_frm_m<OPC_MADD, 0b00, "fmadd.s", FINX>; 297defm FMSUB_S : FPFMA_rrr_frm_m<OPC_MSUB, 0b00, "fmsub.s", FINX>; 298defm FNMSUB_S : FPFMA_rrr_frm_m<OPC_NMSUB, 0b00, "fnmsub.s", FINX>; 299defm FNMADD_S : FPFMA_rrr_frm_m<OPC_NMADD, 0b00, "fnmadd.s", FINX>; 300} 301 302defm : FPFMADynFrmAlias_m<FMADD_S, "fmadd.s", FINX>; 303defm : FPFMADynFrmAlias_m<FMSUB_S, "fmsub.s", FINX>; 304defm : FPFMADynFrmAlias_m<FNMSUB_S, "fnmsub.s", FINX>; 305defm : FPFMADynFrmAlias_m<FNMADD_S, "fnmadd.s", FINX>; 306 307let SchedRW = [WriteFALU32, ReadFALU32, ReadFALU32] in { 308defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", FINX>; 309defm FSUB_S : FPALU_rr_frm_m<0b0000100, "fsub.s", FINX>; 310} 311let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in 312defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", FINX>; 313 314let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in 315defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", FINX>; 316 317defm : FPALUDynFrmAlias_m<FADD_S, "fadd.s", FINX>; 318defm : FPALUDynFrmAlias_m<FSUB_S, "fsub.s", FINX>; 319defm : FPALUDynFrmAlias_m<FMUL_S, "fmul.s", FINX>; 320defm : FPALUDynFrmAlias_m<FDIV_S, "fdiv.s", FINX>; 321 322defm FSQRT_S : FPUnaryOp_r_frm_m<0b0101100, 0b00000, FFINX, "fsqrt.s">, 323 Sched<[WriteFSqrt32, ReadFSqrt32]>; 324defm : FPUnaryOpDynFrmAlias_m<FSQRT_S, "fsqrt.s", FFINX>; 325 326let SchedRW = [WriteFSGNJ32, ReadFSGNJ32, ReadFSGNJ32], 327 mayRaiseFPException = 0 in { 328defm FSGNJ_S : FPALU_rr_m<0b0010000, 0b000, "fsgnj.s", FINX>; 329defm FSGNJN_S : FPALU_rr_m<0b0010000, 0b001, "fsgnjn.s", FINX>; 330defm FSGNJX_S : FPALU_rr_m<0b0010000, 0b010, "fsgnjx.s", FINX>; 331} 332 333let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in { 334defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", FINX>; 335defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", FINX>; 336} 337 338defm FCVT_W_S : FPUnaryOp_r_frm_m<0b1100000, 0b00000, XFINX, "fcvt.w.s">, 339 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>; 340defm : FPUnaryOpDynFrmAlias_m<FCVT_W_S, "fcvt.w.s", XFINX>; 341 342defm FCVT_WU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00001, XFINX, "fcvt.wu.s">, 343 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>; 344defm : FPUnaryOpDynFrmAlias_m<FCVT_WU_S, "fcvt.wu.s", XFINX>; 345 346let mayRaiseFPException = 0 in 347def FMV_X_W : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR32, "fmv.x.w">, 348 Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>; 349 350let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in { 351defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", FINX>; 352defm FLT_S : FPCmp_rr_m<0b1010000, 0b001, "flt.s", FINX>; 353defm FLE_S : FPCmp_rr_m<0b1010000, 0b000, "fle.s", FINX>; 354} 355 356let mayRaiseFPException = 0 in 357defm FCLASS_S : FPUnaryOp_r_m<0b1110000, 0b00000, 0b001, XFINX, "fclass.s">, 358 Sched<[WriteFClass32, ReadFClass32]>; 359 360defm FCVT_S_W : FPUnaryOp_r_frm_m<0b1101000, 0b00000, FXINX, "fcvt.s.w">, 361 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>; 362defm : FPUnaryOpDynFrmAlias_m<FCVT_S_W, "fcvt.s.w", FXINX>; 363 364defm FCVT_S_WU : FPUnaryOp_r_frm_m<0b1101000, 0b00001, FXINX, "fcvt.s.wu">, 365 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>; 366defm : FPUnaryOpDynFrmAlias_m<FCVT_S_WU, "fcvt.s.wu", FXINX>; 367 368let mayRaiseFPException = 0 in 369def FMV_W_X : FPUnaryOp_r<0b1111000, 0b00000, 0b000, FPR32, GPR, "fmv.w.x">, 370 Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>; 371 372defm FCVT_L_S : FPUnaryOp_r_frm_m<0b1100000, 0b00010, XFIN64X, "fcvt.l.s">, 373 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>; 374defm : FPUnaryOpDynFrmAlias_m<FCVT_L_S, "fcvt.l.s", XFIN64X>; 375 376defm FCVT_LU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00011, XFIN64X, "fcvt.lu.s">, 377 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>; 378defm : FPUnaryOpDynFrmAlias_m<FCVT_LU_S, "fcvt.lu.s", XFIN64X>; 379 380defm FCVT_S_L : FPUnaryOp_r_frm_m<0b1101000, 0b00010, FXIN64X, "fcvt.s.l">, 381 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>; 382defm : FPUnaryOpDynFrmAlias_m<FCVT_S_L, "fcvt.s.l", FXIN64X>; 383 384defm FCVT_S_LU : FPUnaryOp_r_frm_m<0b1101000, 0b00011, FXIN64X, "fcvt.s.lu">, 385 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>; 386defm : FPUnaryOpDynFrmAlias_m<FCVT_S_LU, "fcvt.s.lu", FXIN64X>; 387 388//===----------------------------------------------------------------------===// 389// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) 390//===----------------------------------------------------------------------===// 391 392let Predicates = [HasStdExtF] in { 393def : InstAlias<"flw $rd, (${rs1})", (FLW FPR32:$rd, GPR:$rs1, 0), 0>; 394def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>; 395 396def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 397def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 398def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 399 400// fgt.s/fge.s are recognised by the GNU assembler but the canonical 401// flt.s/fle.s forms will always be printed. Therefore, set a zero weight. 402def : InstAlias<"fgt.s $rd, $rs, $rt", 403 (FLT_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>; 404def : InstAlias<"fge.s $rd, $rs, $rt", 405 (FLE_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>; 406 407// The following csr instructions actually alias instructions from the base ISA. 408// However, it only makes sense to support them when the F extension is enabled. 409// NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr". 410def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 2>; 411def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs)>; 412def : InstAlias<"fscsr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 2>; 413 414// frsr, fssr are obsolete aliases replaced by frcsr, fscsr, so give them 415// zero weight. 416def : InstAlias<"frsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 0>; 417def : InstAlias<"fssr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs), 0>; 418def : InstAlias<"fssr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 0>; 419 420def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, SysRegFRM.Encoding, X0), 2>; 421def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, SysRegFRM.Encoding, GPR:$rs)>; 422def : InstAlias<"fsrm $rs", (CSRRW X0, SysRegFRM.Encoding, GPR:$rs), 2>; 423def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, SysRegFRM.Encoding, uimm5:$imm)>; 424def : InstAlias<"fsrmi $imm", (CSRRWI X0, SysRegFRM.Encoding, uimm5:$imm), 2>; 425 426def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, SysRegFFLAGS.Encoding, X0), 2>; 427def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, SysRegFFLAGS.Encoding, GPR:$rs)>; 428def : InstAlias<"fsflags $rs", (CSRRW X0, SysRegFFLAGS.Encoding, GPR:$rs), 2>; 429def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, SysRegFFLAGS.Encoding, uimm5:$imm)>; 430def : InstAlias<"fsflagsi $imm", (CSRRWI X0, SysRegFFLAGS.Encoding, uimm5:$imm), 2>; 431 432// fmv.w.x and fmv.x.w were previously known as fmv.s.x and fmv.x.s. Both 433// spellings should be supported by standard tools. 434def : MnemonicAlias<"fmv.s.x", "fmv.w.x">; 435def : MnemonicAlias<"fmv.x.s", "fmv.x.w">; 436 437def PseudoFLW : PseudoFloatLoad<"flw", FPR32>; 438def PseudoFSW : PseudoStore<"fsw", FPR32>; 439let usesCustomInserter = 1 in { 440def PseudoQuietFLE_S : PseudoQuietFCMP<FPR32>; 441def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>; 442} 443} // Predicates = [HasStdExtF] 444 445let Predicates = [HasStdExtZfinx] in { 446def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>; 447def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>; 448 449def : InstAlias<"fgt.s $rd, $rs, $rt", 450 (FLT_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>; 451def : InstAlias<"fge.s $rd, $rs, $rt", 452 (FLE_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>; 453} // Predicates = [HasStdExtZfinx] 454 455//===----------------------------------------------------------------------===// 456// Pseudo-instructions and codegen patterns 457//===----------------------------------------------------------------------===// 458 459/// Floating point constants 460def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; 461def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; 462 463/// Generic pattern classes 464class PatSetCC<RegisterClass Ty, SDPatternOperator OpNode, CondCode Cond, RVInst Inst> 465 : Pat<(OpNode Ty:$rs1, Ty:$rs2, Cond), (Inst $rs1, $rs2)>; 466 467class PatFpr32Fpr32<SDPatternOperator OpNode, RVInstR Inst> 468 : Pat<(OpNode FPR32:$rs1, FPR32:$rs2), (Inst $rs1, $rs2)>; 469 470class PatFpr32Fpr32DynFrm<SDPatternOperator OpNode, RVInstRFrm Inst> 471 : Pat<(OpNode FPR32:$rs1, FPR32:$rs2), (Inst $rs1, $rs2, 0b111)>; 472 473let Predicates = [HasStdExtF] in { 474 475/// Float constants 476def : Pat<(f32 (fpimm0)), (FMV_W_X X0)>; 477def : Pat<(f32 (fpimmneg0)), (FSGNJN_S (FMV_W_X X0), (FMV_W_X X0))>; 478 479/// Float conversion operations 480 481// [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so 482// are defined later. 483 484/// Float arithmetic operations 485 486def : PatFpr32Fpr32DynFrm<any_fadd, FADD_S>; 487def : PatFpr32Fpr32DynFrm<any_fsub, FSUB_S>; 488def : PatFpr32Fpr32DynFrm<any_fmul, FMUL_S>; 489def : PatFpr32Fpr32DynFrm<any_fdiv, FDIV_S>; 490 491def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, 0b111)>; 492 493def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>; 494def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>; 495 496def : PatFpr32Fpr32<fcopysign, FSGNJ_S>; 497def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>; 498 499// fmadd: rs1 * rs2 + rs3 500def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3), 501 (FMADD_S $rs1, $rs2, $rs3, 0b111)>; 502 503// fmsub: rs1 * rs2 - rs3 504def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)), 505 (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; 506 507// fnmsub: -rs1 * rs2 + rs3 508def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3), 509 (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; 510 511// fnmadd: -rs1 * rs2 - rs3 512def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)), 513 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; 514 515// The ratified 20191213 ISA spec defines fmin and fmax in a way that matches 516// LLVM's fminnum and fmaxnum 517// <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>. 518def : PatFpr32Fpr32<fminnum, FMIN_S>; 519def : PatFpr32Fpr32<fmaxnum, FMAX_S>; 520 521/// Setcc 522// FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for 523// strict versions of those. 524 525// Match non-signaling FEQ_S 526def : PatSetCC<FPR32, any_fsetcc, SETEQ, FEQ_S>; 527def : PatSetCC<FPR32, any_fsetcc, SETOEQ, FEQ_S>; 528def : PatSetCC<FPR32, strict_fsetcc, SETLT, PseudoQuietFLT_S>; 529def : PatSetCC<FPR32, strict_fsetcc, SETOLT, PseudoQuietFLT_S>; 530def : PatSetCC<FPR32, strict_fsetcc, SETLE, PseudoQuietFLE_S>; 531def : PatSetCC<FPR32, strict_fsetcc, SETOLE, PseudoQuietFLE_S>; 532 533// Match signaling FEQ_S 534def : Pat<(strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETEQ), 535 (AND (FLE_S $rs1, $rs2), 536 (FLE_S $rs2, $rs1))>; 537def : Pat<(strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETOEQ), 538 (AND (FLE_S $rs1, $rs2), 539 (FLE_S $rs2, $rs1))>; 540// If both operands are the same, use a single FLE. 541def : Pat<(strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETEQ), 542 (FLE_S $rs1, $rs1)>; 543def : Pat<(strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETOEQ), 544 (FLE_S $rs1, $rs1)>; 545 546def : PatSetCC<FPR32, any_fsetccs, SETLT, FLT_S>; 547def : PatSetCC<FPR32, any_fsetccs, SETOLT, FLT_S>; 548def : PatSetCC<FPR32, any_fsetccs, SETLE, FLE_S>; 549def : PatSetCC<FPR32, any_fsetccs, SETOLE, FLE_S>; 550 551def Select_FPR32_Using_CC_GPR : SelectCC_rrirr<FPR32, GPR>; 552 553/// Loads 554 555defm : LdPat<load, FLW, f32>; 556 557/// Stores 558 559defm : StPat<store, FSW, FPR32, f32>; 560 561} // Predicates = [HasStdExtF] 562 563let Predicates = [HasStdExtF, IsRV32] in { 564// Moves (no conversion) 565def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>; 566def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>; 567 568// float->[u]int. Round-to-zero must be used. 569def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, 0b001)>; 570def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, 0b001)>; 571 572// Saturating float->[u]int32. 573def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>; 574def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>; 575 576// float->int32 with current rounding mode. 577def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, 0b111)>; 578 579// float->int32 rounded to nearest with ties rounded away from zero. 580def : Pat<(i32 (any_lround FPR32:$rs1)), (FCVT_W_S $rs1, 0b100)>; 581 582// [u]int->float. Match GCC and default to using dynamic rounding mode. 583def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, 0b111)>; 584def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>; 585} // Predicates = [HasStdExtF, IsRV32] 586 587let Predicates = [HasStdExtF, IsRV64] in { 588// Moves (no conversion) 589def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>; 590def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>; 591def : Pat<(sext_inreg (riscv_fmv_x_anyextw_rv64 FPR32:$src), i32), 592 (FMV_X_W FPR32:$src)>; 593 594// Use target specific isd nodes to help us remember the result is sign 595// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be 596// duplicated if it has another user that didn't need the sign_extend. 597def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm), (FCVT_W_S $rs1, timm:$frm)>; 598def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>; 599 600// float->[u]int64. Round-to-zero must be used. 601def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, 0b001)>; 602def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, 0b001)>; 603 604// Saturating float->[u]int64. 605def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>; 606def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>; 607 608// float->int64 with current rounding mode. 609def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, 0b111)>; 610def : Pat<(i64 (any_llrint FPR32:$rs1)), (FCVT_L_S $rs1, 0b111)>; 611 612// float->int64 rounded to neartest with ties rounded away from zero. 613def : Pat<(i64 (any_lround FPR32:$rs1)), (FCVT_L_S $rs1, 0b100)>; 614def : Pat<(i64 (any_llround FPR32:$rs1)), (FCVT_L_S $rs1, 0b100)>; 615 616// [u]int->fp. Match GCC and default to using dynamic rounding mode. 617def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, 0b111)>; 618def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, 0b111)>; 619def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L $rs1, 0b111)>; 620def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, 0b111)>; 621} // Predicates = [HasStdExtF, IsRV64] 622