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