blob: 13c98ce92d148177807d531e98752073faf8c3e8 [file] [log] [blame]
//===-- RISCVInstrInfoZvk.td - RISC-V 'Zvk' 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 'Zvk',
// Vector Cryptography Instructions extension, version 1.0.0-rc1.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
//===----------------------------------------------------------------------===//
def RnumArg_0_7 : AsmOperandClass {
let Name = "RnumArg_0_7";
let RenderMethod = "addImmOperands";
let DiagnosticType = "InvalidRnumArg_0_7";
}
def RnumArg_1_10 : AsmOperandClass {
let Name = "RnumArg_1_10";
let RenderMethod = "addImmOperands";
let DiagnosticType = "InvalidRnumArg_1_10";
}
def RnumArg_2_14 : AsmOperandClass {
let Name = "RnumArg_2_14";
let RenderMethod = "addImmOperands";
let DiagnosticType = "InvalidRnumArg_2_14";
}
def rnum_0_7 : Operand<XLenVT>, ImmLeaf<XLenVT,
[{return (0 <= Imm && Imm <= 7);}]> {
let ParserMatchClass = RnumArg_0_7;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandType = "OPERAND_RVKRNUM_0_7";
let OperandNamespace = "RISCVOp";
}
def rnum_1_10 : Operand<XLenVT>, ImmLeaf<XLenVT,
[{return (1 <= Imm && Imm <= 10);}]> {
let ParserMatchClass = RnumArg_1_10;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandType = "OPERAND_RVKRNUM_1_10";
let OperandNamespace = "RISCVOp";
}
def rnum_2_14 : Operand<XLenVT>, ImmLeaf<XLenVT,
[{return (2 <= Imm && Imm <= 14);}]> {
let ParserMatchClass = RnumArg_2_14;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandType = "OPERAND_RVKRNUM_2_14";
let OperandNamespace = "RISCVOp";
}
//===----------------------------------------------------------------------===//
// Instruction class templates
//===----------------------------------------------------------------------===//
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
multiclass VCLMUL_MV_V_X<string opcodestr, bits<6> funct6> {
def V : VALUVV<funct6, OPMVV, opcodestr # "." # "vv">,
Sched<[WriteVIALUV_WorstCase, ReadVIALUV_WorstCase,
ReadVIALUV_WorstCase, ReadVMask]>;
def X : VALUVX<funct6, OPMVX, opcodestr # "." # "vx">,
Sched<[WriteVIALUX_WorstCase, ReadVIALUV_WorstCase,
ReadVIALUX_WorstCase, ReadVMask]>;
}
class RVInstIVI_VROR<bits<6> funct6, dag outs, dag ins, string opcodestr,
string argstr>
: RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> {
bits<5> vs2;
bits<6> imm;
bits<5> vd;
bit vm;
let Inst{31-27} = funct6{5-1};
let Inst{26} = imm{5};
let Inst{25} = vm;
let Inst{24-20} = vs2;
let Inst{19-15} = imm{4-0};
let Inst{14-12} = OPIVI.Value;
let Inst{11-7} = vd;
let Inst{6-0} = OPC_OP_V.Value;
let Uses = [VTYPE, VL];
let RVVConstraint = VMConstraint;
}
multiclass VROR_IV_V_X_I<string opcodestr, bits<6> funct6>
: VALU_IV_V_X<opcodestr, funct6> {
def I : RVInstIVI_VROR<funct6, (outs VR:$vd),
(ins VR:$vs2, uimm6:$imm, VMaskOp:$vm),
opcodestr # ".vi", "$vd, $vs2, $imm$vm">,
Sched<[WriteVIALUI_WorstCase, ReadVIALUV_WorstCase,
ReadVMask]>;
}
// op vd, vs2, vs1
class PALUVVNoVm<bits<6> funct6, RISCVVFormat opv, string opcodestr>
: VALUVVNoVm<funct6, opv, opcodestr> {
let Inst{6-0} = OPC_OP_P.Value;
}
// op vd, vs2, imm, vm
class PALUVINoVm<bits<6> funct6, string opcodestr, Operand optype = simm5>
: VALUVINoVm<funct6, opcodestr, optype> {
let Inst{6-0} = OPC_OP_P.Value;
let Inst{14-12} = OPMVV.Value;
}
// op vd, vs2 (use vs1 as instruction encoding)
class PALUVs2NoVm<bits<6> funct6, bits<5> vs1, RISCVVFormat opv, string opcodestr>
: VALUVs2NoVm<funct6, vs1, opv, opcodestr> {
let Inst{6-0} = OPC_OP_P.Value;
}
multiclass VAES_MV_V_S<bits<6> funct6_vv, bits<6> funct6_vs, bits<5> vs1,
RISCVVFormat opv, string opcodestr> {
def NAME # _VV : PALUVs2NoVm<funct6_vv, vs1, opv, opcodestr # ".vv">;
def NAME # _VS : PALUVs2NoVm<funct6_vs, vs1, opv, opcodestr # ".vs">;
}
// vaeskf1.vi and vaeskf2.vi uses different opcode and format, we need
// to customize one for them.
class VAESKF_MV_I<bits<6> funct6, string opcodestr, Operand optype>
: VALUVINoVm<funct6, opcodestr, optype> {
let Inst{6-0} = OPC_OP_P.Value;
let Inst{14-12} = OPMVV.Value;
}
} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtZvbb] in {
defm VANDN_V : VALU_IV_V_X<"vandn", 0b000001>;
def VBREV8_V : VALUVs2<0b010010, 0b01000, OPMVV, "vbrev8.v">;
def VBREV_V : VALUVs2<0b010010, 0b01010, OPMVV, "vbrev.v">;
def VCLZ_V : VALUVs2<0b010010, 0b01100, OPMVV, "vclz.v">;
def VCPOP_V : VALUVs2<0b010010, 0b01110, OPMVV, "vcpop.v">;
def VCTZ_V : VALUVs2<0b010010, 0b01101, OPMVV, "vctz.v">;
def VREV8_V : VALUVs2<0b010010, 0b01001, OPMVV, "vrev8.v">;
defm VROL_V : VALU_IV_V_X<"vrol", 0b010101>;
defm VROR_V : VROR_IV_V_X_I<"vror", 0b010100>;
let Constraints = "@earlyclobber $vd", RVVConstraint = WidenV in
defm VWSLL_V : VSHT_IV_V_X_I<"vwsll", 0b110101>;
} // Predicates = [HasStdExtZvbb]
let Predicates = [HasStdExtZvbc] in {
defm VCLMUL_V : VCLMUL_MV_V_X<"vclmul", 0b001100>;
defm VCLMULH_V : VCLMUL_MV_V_X<"vclmulh", 0b001101>;
} // Predicates = [HasStdExtZvbc]
let Predicates = [HasStdExtZvkg], RVVConstraint = NoConstraint in {
def VGHSH_VV : PALUVVNoVm<0b101100, OPMVV, "vghsh.vv">;
def VGMUL_VV : PALUVs2NoVm<0b101000, 0b10001, OPMVV, "vgmul.vv">;
} // Predicates = [HasStdExtZvkg]
let Predicates = [HasStdExtZvknha], RVVConstraint = NoConstraint in {
def VSHA2CH_VV : PALUVVNoVm<0b101110, OPMVV, "vsha2ch.vv">;
def VSHA2CL_VV : PALUVVNoVm<0b101111, OPMVV, "vsha2cl.vv">;
def VSHA2MS_VV : PALUVVNoVm<0b101101, OPMVV, "vsha2ms.vv">;
} // Predicates = [HasStdExtZvknha]
let Predicates = [HasStdExtZvkned], RVVConstraint = NoConstraint in {
defm VAESDF : VAES_MV_V_S<0b101000, 0b101001, 0b00001, OPMVV, "vaesdf">;
defm VAESDM : VAES_MV_V_S<0b101000, 0b101001, 0b00000, OPMVV, "vaesdm">;
defm VAESEF : VAES_MV_V_S<0b101000, 0b101001, 0b00011, OPMVV, "vaesef">;
defm VAESEM : VAES_MV_V_S<0b101000, 0b101001, 0b00010, OPMVV, "vaesem">;
def VAESKF1_VI : VAESKF_MV_I<0b100010, "vaeskf1.vi", uimm5>;
def VAESKF2_VI : VAESKF_MV_I<0b101010, "vaeskf2.vi", uimm5>;
def VAESZ_VS : PALUVs2NoVm<0b101001, 0b00111, OPMVV, "vaesz.vs">;
} // Predicates = [HasStdExtZvkned]
let Predicates = [HasStdExtZvksed], RVVConstraint = NoConstraint in {
def VSM4K_VI : PALUVINoVm<0b100001, "vsm4k.vi", uimm5>;
defm VSM4R : VAES_MV_V_S<0b101000, 0b101001, 0b10000, OPMVV, "vsm4r">;
} // Predicates = [HasStdExtZvksed]
let Predicates = [HasStdExtZvksh], RVVConstraint = NoConstraint in {
def VSM3C_VI : PALUVINoVm<0b101011, "vsm3c.vi", uimm5>;
def VSM3ME_VV : PALUVVNoVm<0b100000, OPMVV, "vsm3me.vv">;
} // Predicates = [HasStdExtZvksh]
//===----------------------------------------------------------------------===//
// Pseudo instructions
//===----------------------------------------------------------------------===//
defm PseudoVANDN : VPseudoVALU_VV_VX;
multiclass VPseudoUnaryV_V {
foreach m = MxList in {
let VLMul = m.value in {
def "_V_" # m.MX : VPseudoUnaryNoMask<m.vrclass, m.vrclass>;
def "_V_" # m.MX # "_MASK" : VPseudoUnaryMask<m.vrclass, m.vrclass>,
RISCVMaskedPseudo<MaskIdx=2>;
}
}
}
defm PseudoVBREV : VPseudoUnaryV_V;
defm PseudoVREV8 : VPseudoUnaryV_V;
defm PseudoVCLZ : VPseudoUnaryV_V;
defm PseudoVCTZ : VPseudoUnaryV_V;
defm PseudoVCPOP : VPseudoUnaryV_V;
defm PseudoVROL : VPseudoVALU_VV_VX;
defm PseudoVROR : VPseudoVALU_VV_VX_VI<uimm6>;
//===----------------------------------------------------------------------===//
// SDNode patterns
//===----------------------------------------------------------------------===//
multiclass VPatUnarySDNode_V<SDPatternOperator op, string instruction_name> {
foreach vti = AllIntegerVectors in {
let Predicates = !listconcat([HasStdExtZvbb],
GetVTypePredicates<vti>.Predicates) in {
def : Pat<(vti.Vector (op (vti.Vector vti.RegClass:$rs1))),
(!cast<Instruction>(instruction_name#"_V_"#vti.LMul.MX)
(vti.Vector (IMPLICIT_DEF)),
vti.RegClass:$rs1,
vti.AVL, vti.Log2SEW, TA_MA)>;
}
}
}
// Helpers for detecting splats since we preprocess splat_vector to vmv.v.x
// This should match the logic in RISCVDAGToDAGISel::selectVSplat
def riscv_splat_vector : PatFrag<(ops node:$rs1),
(riscv_vmv_v_x_vl undef, node:$rs1, srcvalue)>;
def riscv_vnot : PatFrag<(ops node:$rs1), (xor node:$rs1,
(riscv_splat_vector -1))>;
foreach vti = AllIntegerVectors in {
let Predicates = !listconcat([HasStdExtZvbb],
GetVTypePredicates<vti>.Predicates) in {
def : Pat<(vti.Vector (and (riscv_vnot vti.RegClass:$rs1),
vti.RegClass:$rs2)),
(!cast<Instruction>("PseudoVANDN_VV_"#vti.LMul.MX)
(vti.Vector (IMPLICIT_DEF)),
vti.RegClass:$rs2,
vti.RegClass:$rs1,
vti.AVL, vti.Log2SEW, TA_MA)>;
def : Pat<(vti.Vector (and (riscv_splat_vector
(not vti.ScalarRegClass:$rs1)),
vti.RegClass:$rs2)),
(!cast<Instruction>("PseudoVANDN_VX_"#vti.LMul.MX)
(vti.Vector (IMPLICIT_DEF)),
vti.RegClass:$rs2,
vti.ScalarRegClass:$rs1,
vti.AVL, vti.Log2SEW, TA_MA)>;
}
}
defm : VPatUnarySDNode_V<bitreverse, "PseudoVBREV">;
defm : VPatUnarySDNode_V<bswap, "PseudoVREV8">;
defm : VPatUnarySDNode_V<ctlz, "PseudoVCLZ">;
defm : VPatUnarySDNode_V<cttz, "PseudoVCTZ">;
defm : VPatUnarySDNode_V<ctpop, "PseudoVCPOP">;
defm : VPatBinarySDNode_VV_VX<rotl, "PseudoVROL">;
def NegImm64 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(0x3f & (64 - N->getZExtValue()), SDLoc(N),
N->getValueType(0));
}]>;
// Although there is no vrol.vi, an immediate rotate left can be achieved by
// negating the immediate in vror.vi
foreach vti = AllIntegerVectors in {
let Predicates = !listconcat([HasStdExtZvbb],
GetVTypePredicates<vti>.Predicates) in {
def : Pat<(vti.Vector (rotl vti.RegClass:$rs2,
(vti.Vector (SplatPat_uimm6 uimm6:$rs1)))),
(!cast<Instruction>("PseudoVROR_VI_"#vti.LMul.MX)
(vti.Vector (IMPLICIT_DEF)),
vti.RegClass:$rs2,
(NegImm64 uimm6:$rs1),
vti.AVL, vti.Log2SEW, TA_MA)>;
}
}
defm : VPatBinarySDNode_VV_VX_VI<rotr, "PseudoVROR", uimm6>;
//===----------------------------------------------------------------------===//
// VL patterns
//===----------------------------------------------------------------------===//
multiclass VPatUnaryVL_V<SDPatternOperator op, string instruction_name> {
foreach vti = AllIntegerVectors in {
let Predicates = !listconcat([HasStdExtZvbb],
GetVTypePredicates<vti>.Predicates) in {
def : Pat<(vti.Vector (op (vti.Vector vti.RegClass:$rs1),
(vti.Vector vti.RegClass:$merge),
(vti.Mask V0),
VLOpFrag)),
(!cast<Instruction>(instruction_name#"_V_"#vti.LMul.MX#"_MASK")
vti.RegClass:$merge,
vti.RegClass:$rs1,
(vti.Mask V0),
GPR:$vl,
vti.Log2SEW,
TAIL_AGNOSTIC)>;
}
}
}
foreach vti = AllIntegerVectors in {
let Predicates = !listconcat([HasStdExtZvbb],
GetVTypePredicates<vti>.Predicates) in {
def : Pat<(vti.Vector (riscv_and_vl (riscv_xor_vl
(vti.Vector vti.RegClass:$rs1),
(riscv_splat_vector -1),
(vti.Vector vti.RegClass:$merge),
(vti.Mask V0),
VLOpFrag),
(vti.Vector vti.RegClass:$rs2),
(vti.Vector vti.RegClass:$merge),
(vti.Mask V0),
VLOpFrag)),
(!cast<Instruction>("PseudoVANDN_VV_"#vti.LMul.MX#"_MASK")
vti.RegClass:$merge,
vti.RegClass:$rs2,
vti.RegClass:$rs1,
(vti.Mask V0),
GPR:$vl,
vti.Log2SEW,
TAIL_AGNOSTIC)>;
def : Pat<(vti.Vector (riscv_and_vl (riscv_splat_vector
(not vti.ScalarRegClass:$rs1)),
(vti.Vector vti.RegClass:$rs2),
(vti.Vector vti.RegClass:$merge),
(vti.Mask V0),
VLOpFrag)),
(!cast<Instruction>("PseudoVANDN_VX_"#vti.LMul.MX#"_MASK")
vti.RegClass:$merge,
vti.RegClass:$rs2,
vti.ScalarRegClass:$rs1,
(vti.Mask V0),
GPR:$vl,
vti.Log2SEW,
TAIL_AGNOSTIC)>;
}
}
defm : VPatUnaryVL_V<riscv_bitreverse_vl, "PseudoVBREV">;
defm : VPatUnaryVL_V<riscv_bswap_vl, "PseudoVREV8">;
defm : VPatUnaryVL_V<riscv_ctlz_vl, "PseudoVCLZ">;
defm : VPatUnaryVL_V<riscv_cttz_vl, "PseudoVCTZ">;
defm : VPatUnaryVL_V<riscv_ctpop_vl, "PseudoVCPOP">;