//===-- RISCVInstrInfoXsf.td - SiFive custom 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 vendor extensions defined by SiFive. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // XSFVCP extension instructions. //===----------------------------------------------------------------------===// def VCIXVS2 : RISCVVConstraint; def VCIXVS2VS1 : RISCVVConstraint; class VCIXType val> { bits<4> Val = val; } def VCIX_X : VCIXType<0b0000>; def VCIX_XV : VCIXType<0b0010>; def VCIX_XVV : VCIXType<0b1010>; def VCIX_XVW : VCIXType<0b1111>; // The payload and timm5 operands are all marked as ImmArg in the IR // intrinsic and will be target constant, so use TImmLeaf rather than ImmLeaf. def payload1 : Operand, TImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<1>; let DecoderMethod = "decodeUImmOperand<1>"; let OperandType = "OPERAND_UIMM1"; let OperandNamespace = "RISCVOp"; } def payload2 : Operand, TImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<2>; let DecoderMethod = "decodeUImmOperand<2>"; let OperandType = "OPERAND_UIMM2"; let OperandNamespace = "RISCVOp"; } def payload5 : Operand, TImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<5>; let DecoderMethod = "decodeUImmOperand<5>"; let OperandType = "OPERAND_UIMM5"; let OperandNamespace = "RISCVOp"; } def timm5 : Operand, TImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<5>; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<5>"; let MCOperandPredicate = [{ int64_t Imm; if (MCOp.evaluateAsConstantImm(Imm)) return isInt<5>(Imm); return MCOp.isBareSymbolRef(); }]; } class SwapVCIXIns { dag Ins = !con(funct6, !if(swap, rs2, rd), !if(swap, rd, rs2), rs1); } class RVInstVCCustom2 funct6_hi4, bits<3> funct3, dag outs, dag ins, string opcodestr, string argstr> : RVInst { bits<5> rs2; bits<5> rs1; bits<5> rd; bits<2> funct6_lo2; bit vm; let Inst{31-28} = funct6_hi4; let Inst{27-26} = funct6_lo2; let Inst{25} = vm; let Inst{24-20} = rs2; let Inst{19-15} = rs1; let Inst{14-12} = funct3; let Inst{11-7} = rd; let Inst{6-0} = OPC_CUSTOM_2.Value; let Uses = [VTYPE, VL]; let RVVConstraint = NoConstraint; } class RVInstVCFCustom2 funct6_hi4, bits<3> funct3, dag outs, dag ins, string opcodestr, string argstr> : RVInst { bits<5> rs2; bits<5> rs1; bits<5> rd; bit funct6_lo1; bit vm; let Inst{31-28} = funct6_hi4; let Inst{27} = 1; let Inst{26} = funct6_lo1; let Inst{25} = vm; let Inst{24-20} = rs2; let Inst{19-15} = rs1; let Inst{14-12} = funct3; let Inst{11-7} = rd; let Inst{6-0} = OPC_CUSTOM_2.Value; let Uses = [VTYPE, VL]; let RVVConstraint = NoConstraint; } class GetFTypeInfo { ValueType Scalar = !cond(!eq(sew, 16): f16, !eq(sew, 32): f32, !eq(sew, 64): f64); RegisterClass ScalarRegClass = !cond(!eq(sew, 16): FPR16, !eq(sew, 32): FPR32, !eq(sew, 64): FPR64); } class VCIXInfo { string OpcodeStr = !if(HaveOutputDst, "sf.vc.v." # suffix, "sf.vc." # suffix); bits<4> Funct6_hi4 = type.Val; bits<3> Funct3 = !cond(!eq(TyRs1, VR): 0b000, !eq(TyRs1, GPR): 0b100, !eq(TyRs1, FPR32): 0b101, !eq(TyRs1, simm5): 0b011); dag Outs = !if(!not(HaveOutputDst), (outs), !if(!or(!eq(type, VCIX_XVV), !eq(type, VCIX_XVW)), (outs TyRd:$rd_wb), (outs TyRd:$rd))); dag Ins = SwapVCIXIns.Ins; string Prototype = !if(!eq(type, VCIX_X), "$funct6_lo2, $rs2, $rd, $rs1", !if(!ne(TyRs1, FPR32), "$funct6_lo2, $rd, $rs2, $rs1", "$funct6_lo1, $rd, $rs2, $rs1")); string Constraints = !if(!not(HaveOutputDst), "", !if(!or(!eq(type, VCIX_XVV), !eq(type, VCIX_XVW)), "$rd = $rd_wb", "")); RISCVVConstraint RVVConstraint = !if(!or(!not(HaveOutputDst), !ne(type, VCIX_XVW)), NoConstraint, !if(!eq(TyRs1, VR), VCIXVS2VS1, VCIXVS2)); } class CustomSiFiveVCIX : RVInstVCCustom2 { let Constraints = info.Constraints; let RVVConstraint = info.RVVConstraint; } class CustomSiFiveVCIF : RVInstVCFCustom2 { let Constraints = info.Constraints; let RVVConstraint = info.RVVConstraint; } multiclass CustomSiFiveVCIXorVCIF { defvar info = VCIXInfo; if !eq(TyRs1, FPR32) then { def NAME : CustomSiFiveVCIF; } else { def NAME : CustomSiFiveVCIX; } } multiclass CustomSiFiveVCIX { let vm = 1 in defm VC_ # NAME : CustomSiFiveVCIXorVCIF; let vm = 0 in defm VC_V_ # NAME : CustomSiFiveVCIXorVCIF; } let Predicates = [HasVendorXSfvcp], mayLoad = 0, mayStore = 0, hasSideEffects = 1, hasNoSchedulingInfo = 1, DecoderNamespace = "XSfvcp" in { defm X : CustomSiFiveVCIX<"x", VCIX_X, uimm5, uimm5, GPR>, Sched<[]>; defm I : CustomSiFiveVCIX<"i", VCIX_X, uimm5, uimm5, simm5>, Sched<[]>; defm XV : CustomSiFiveVCIX<"xv", VCIX_XV, uimm5, VR, GPR>, Sched<[]>; defm IV : CustomSiFiveVCIX<"iv", VCIX_XV, uimm5, VR, simm5>, Sched<[]>; defm VV : CustomSiFiveVCIX<"vv", VCIX_XV, uimm5, VR, VR>, Sched<[]>; defm FV : CustomSiFiveVCIX<"fv", VCIX_XV, uimm5, VR, FPR32>, Sched<[]>; defm XVV : CustomSiFiveVCIX<"xvv", VCIX_XVV, VR, VR, GPR>, Sched<[]>; defm IVV : CustomSiFiveVCIX<"ivv", VCIX_XVV, VR, VR, simm5>, Sched<[]>; defm VVV : CustomSiFiveVCIX<"vvv", VCIX_XVV, VR, VR, VR>, Sched<[]>; defm FVV : CustomSiFiveVCIX<"fvv", VCIX_XVV, VR, VR, FPR32>, Sched<[]>; defm XVW : CustomSiFiveVCIX<"xvw", VCIX_XVW, VR, VR, GPR>, Sched<[]>; defm IVW : CustomSiFiveVCIX<"ivw", VCIX_XVW, VR, VR, simm5>, Sched<[]>; defm VVW : CustomSiFiveVCIX<"vvw", VCIX_XVW, VR, VR, VR>, Sched<[]>; defm FVW : CustomSiFiveVCIX<"fvw", VCIX_XVW, VR, VR, FPR32>, Sched<[]>; } class VPseudoVC_X : Pseudo<(outs), (ins OpClass:$op1, payload5:$rs2, payload5:$rd, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } class VPseudoVC_XV : Pseudo<(outs), (ins OpClass:$op1, payload5:$rd, RS2Class:$rs2, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } class VPseudoVC_XVV : Pseudo<(outs), (ins OpClass:$op1, RDClass:$rd, RS2Class:$rs2, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } class VPseudoVC_V_X : Pseudo<(outs RDClass:$rd), (ins OpClass:$op1, payload5:$rs2, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } class VPseudoVC_V_XV : Pseudo<(outs RDClass:$rd), (ins OpClass:$op1, RS2Class:$rs2, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } class VPseudoVC_V_XVV : Pseudo<(outs RDClass:$rd), (ins OpClass:$op1, RDClass:$rs3, RS2Class:$rs2, RS1Class:$r1, AVL:$vl, ixlenimm:$sew), []>, RISCVVPseudo { let mayLoad = 0; let mayStore = 0; let HasVLOp = 1; let HasSEWOp = 1; let hasSideEffects = HasSideEffect; let BaseInstr = !cast(PseudoToVInst.VInst); } multiclass VPseudoVC_X { let VLMul = m.value in { def "PseudoVC_" # NAME # "_SE_" # m.MX : VPseudoVC_X; def "PseudoVC_V_" # NAME # "_SE_" # m.MX : VPseudoVC_V_X; def "PseudoVC_V_" # NAME # "_" # m.MX : VPseudoVC_V_X; } } multiclass VPseudoVC_XV { let VLMul = m.value in { def "PseudoVC_" # NAME # "_SE_" # m.MX : VPseudoVC_XV; def "PseudoVC_V_" # NAME # "_SE_" # m.MX : VPseudoVC_V_XV; def "PseudoVC_V_" # NAME # "_" # m.MX : VPseudoVC_V_XV; } } multiclass VPseudoVC_XVV { let VLMul = m.value in { def "PseudoVC_" # NAME # "_SE_" # m.MX : VPseudoVC_XVV; def "PseudoVC_V_" # NAME # "_SE_" # m.MX : VPseudoVC_V_XVV; def "PseudoVC_V_" # NAME # "_" # m.MX : VPseudoVC_V_XVV; } } multiclass VPseudoVC_XVW { let VLMul = m.value in { def "PseudoVC_" # NAME # "_SE_" # m.MX : VPseudoVC_XVV; let Constraints = "@earlyclobber $rd, $rd = $rs3" in { def "PseudoVC_V_" # NAME # "_SE_" # m.MX : VPseudoVC_V_XVV; def "PseudoVC_V_" # NAME # "_" # m.MX : VPseudoVC_V_XVV; } } } let Predicates = [HasVendorXSfvcp] in { foreach m = MxList in { defm X : VPseudoVC_X; defm I : VPseudoVC_X; defm XV : VPseudoVC_XV; defm IV : VPseudoVC_XV; defm VV : VPseudoVC_XV; defm XVV : VPseudoVC_XVV; defm IVV : VPseudoVC_XVV; defm VVV : VPseudoVC_XVV; } foreach f = FPList in { foreach m = f.MxList in { defm f.FX # "V" : VPseudoVC_XV; defm f.FX # "VV" : VPseudoVC_XVV; } } foreach m = MxListW in { defm XVW : VPseudoVC_XVW; defm IVW : VPseudoVC_XVW; defm VVW : VPseudoVC_XVW; } foreach f = FPListW in { foreach m = f.MxList in defm f.FX # "VW" : VPseudoVC_XVW; } } class VPatVC_OP4 : Pat<(!cast(intrinsic_name) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), (op4_type op4_kind:$op4), VLOpFrag), (!cast(inst) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), (op4_type op4_kind:$op4), GPR:$vl, sew)>; class VPatVC_V_OP4 : Pat<(result_type (!cast(intrinsic_name) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), (op4_type op4_kind:$op4), VLOpFrag)), (!cast(inst) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), (op4_type op4_kind:$op4), GPR:$vl, sew)>; class VPatVC_V_OP3 : Pat<(result_type (!cast(intrinsic_name) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), VLOpFrag)), (!cast(inst) (XLenVT op1_kind:$op1), (op2_type op2_kind:$op2), (op3_type op3_kind:$op3), GPR:$vl, sew)>; multiclass VPatVC_X { def : VPatVC_OP4<"int_riscv_sf_vc_" # intrinsic_suffix # "_se_e" # vti.SEW # !tolower(vti.LMul.MX), "PseudoVC_" # instruction_suffix # "_SE_" # vti.LMul.MX, XLenVT, XLenVT, type, vti.Log2SEW, payload5, payload5, kind>; def : VPatVC_V_OP3<"int_riscv_sf_vc_v_" # intrinsic_suffix # "_se", "PseudoVC_V_" # instruction_suffix # "_SE_" # vti.LMul.MX, vti.Vector, XLenVT, type, vti.Log2SEW, payload5, kind>; def : VPatVC_V_OP3<"int_riscv_sf_vc_v_" # intrinsic_suffix, "PseudoVC_V_" # instruction_suffix # "_" # vti.LMul.MX, vti.Vector, XLenVT, type, vti.Log2SEW, payload5, kind>; } multiclass VPatVC_XV { def : VPatVC_OP4<"int_riscv_sf_vc_" # intrinsic_suffix # "_se", "PseudoVC_" # instruction_suffix # "_SE_" # vti.LMul.MX, XLenVT, vti.Vector, type, vti.Log2SEW, payload5, vti.RegClass, kind, op1_kind>; def : VPatVC_V_OP3<"int_riscv_sf_vc_v_" # intrinsic_suffix # "_se", "PseudoVC_V_" # instruction_suffix # "_SE_" # vti.LMul.MX, vti.Vector, vti.Vector, type, vti.Log2SEW, vti.RegClass, kind, op1_kind>; def : VPatVC_V_OP3<"int_riscv_sf_vc_v_" # intrinsic_suffix, "PseudoVC_V_" # instruction_suffix # "_" # vti.LMul.MX, vti.Vector, vti.Vector, type, vti.Log2SEW, vti.RegClass, kind, op1_kind>; } multiclass VPatVC_XVV { def : VPatVC_OP4<"int_riscv_sf_vc_" # intrinsic_suffix # "_se", "PseudoVC_" # instruction_suffix # "_SE_" # vti.LMul.MX, wti.Vector, vti.Vector, type, vti.Log2SEW, wti.RegClass, vti.RegClass, kind, op1_kind>; def : VPatVC_V_OP4<"int_riscv_sf_vc_v_" # intrinsic_suffix # "_se", "PseudoVC_V_" # instruction_suffix # "_SE_" # vti.LMul.MX, wti.Vector, wti.Vector, vti.Vector, type, vti.Log2SEW, wti.RegClass, vti.RegClass, kind, op1_kind>; def : VPatVC_V_OP4<"int_riscv_sf_vc_v_" # intrinsic_suffix, "PseudoVC_V_" # instruction_suffix # "_" # vti.LMul.MX, wti.Vector, wti.Vector, vti.Vector, type, vti.Log2SEW, wti.RegClass, vti.RegClass, kind, op1_kind>; } let Predicates = [HasVendorXSfvcp] in { foreach vti = AllIntegerVectors in { defm : VPatVC_X<"x", "X", vti, vti.Scalar, vti.ScalarRegClass>; defm : VPatVC_X<"i", "I", vti, XLenVT, timm5>; defm : VPatVC_XV<"xv", "XV", vti, vti.Scalar, vti.ScalarRegClass>; defm : VPatVC_XV<"iv", "IV", vti, XLenVT, timm5>; defm : VPatVC_XV<"vv", "VV", vti, vti.Vector, vti.RegClass>; defm : VPatVC_XVV<"xvv", "XVV", vti, vti, vti.Scalar, vti.ScalarRegClass>; defm : VPatVC_XVV<"ivv", "IVV", vti, vti, XLenVT, timm5>; defm : VPatVC_XVV<"vvv", "VVV", vti, vti, vti.Vector, vti.RegClass>; if !ge(vti.SEW, 16) then { defm : VPatVC_XV<"fv", "F" # vti.SEW # "V", vti, GetFTypeInfo.Scalar, GetFTypeInfo.ScalarRegClass, payload1>; defm : VPatVC_XVV<"fvv", "F" # vti.SEW # "VV", vti, vti, GetFTypeInfo.Scalar, GetFTypeInfo.ScalarRegClass, payload1>; } } foreach VtiToWti = AllWidenableIntVectors in { defvar vti = VtiToWti.Vti; defvar wti = VtiToWti.Wti; defm : VPatVC_XVV<"xvw", "XVW", wti, vti, vti.Scalar, vti.ScalarRegClass>; defm : VPatVC_XVV<"ivw", "IVW", wti, vti, XLenVT, timm5>; defm : VPatVC_XVV<"vvw", "VVW", wti, vti, vti.Vector, vti.RegClass>; if !ge(vti.SEW, 16) then { defm : VPatVC_XVV<"fvw", "F" # vti.SEW # "VW", wti, vti, GetFTypeInfo.Scalar, GetFTypeInfo.ScalarRegClass, payload1>; } } } let Predicates = [HasVendorXSfcie] in { let hasSideEffects = 1, mayLoad = 0, mayStore = 0, DecoderNamespace = "XSfcie" in { def SF_CFLUSH_D_L1 : RVInstI<0b000, OPC_SYSTEM, (outs), (ins GPR:$rs1), "cflush.d.l1","$rs1">, Sched<[]> { let rd = 0; let imm12 = {0b1111,0b1100,0b0000}; } def SF_CDISCARD_D_L1 : RVInstI<0b000, OPC_SYSTEM, (outs), (ins GPR:$rs1), "cdiscard.d.l1","$rs1">, Sched<[]> { let rd = 0; let imm12 = {0b1111,0b1100,0b0010}; } def SF_CEASE : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "cease","">, Sched<[]> { let rs1 = 0; let rd = 0; let imm12 = {0b0011,0b0000,0b0101}; } } def : InstAlias<"cflush.d.l1", (SF_CFLUSH_D_L1 X0)>; def : InstAlias<"cdiscard.d.l1", (SF_CDISCARD_D_L1 X0)>; } // Predicates = [HasVendorXScie]