Zbb extension:
RV32 / 64:
orc.b
https://reviews.llvm.org/D99320
https://reviews.llvm.org/D99319
Zbc extension:
RV32 / 64:
clmul
clmulh
clmulr
https://reviews.llvm.org/D99711
https://reviews.llvm.org/D99712
Zbe extension:
RV32/64:
bcomress
bdecompress
RV64 ONLY:
bcomressw
bdecompressw
https://reviews.llvm.org/D101143
https://reviews.llvm.org/D101144
Zbf extension:
TBD
Zbm extension:
RV64 ONLY:
bmator
bmatxor
bmatflip
https://reviews.llvm.org/D101248
https://reviews.llvm.org/D101249
Zbp extension:
RV32/64:
grev
grevi
gorc
gorci
shfl
shfli
unshfl
unshfli
xperm.n
xperm.b
xperm.h
RV64 ONLY:
grevw
greviw
gorcw
gorciw
shflw
shfli (For non-existing shfliw)
unshfli (For non-existing unshfliw)
xperm.w
https://reviews.llvm.org/D100830
https://reviews.llvm.org/D100831
Zbr extension:
RV32 / 64:
crc32b
crc32h
crc32w
crc32cb
crc32ch
crc32cw
RV64 Only:
crc32d
crc32cd
https://reviews.llvm.org/D99009
https://reviews.llvm.org/D99008
Zbt extension:
TBD
Let’s take a look for those patches and what needs to done for those intrinsic on llvm, In:
llvm/include/llvm/IR/IntrinsicsRISCV.td
//===----------------------------------------------------------------------===// // Bitmanip (Bit Manipulation) Extension let TargetPrefix = "riscv" in { class BitManipGPRIntrinsics : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable, IntrWillReturn]>; class BitManipGPRGPRIntrinsics : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable, IntrWillReturn]>; // Zbb def int_riscv_orc_b : BitManipGPRIntrinsics; // Zbc def int_riscv_clmul : BitManipGPRGPRIntrinsics; def int_riscv_clmulh : BitManipGPRGPRIntrinsics; def int_riscv_clmulr : BitManipGPRGPRIntrinsics; // Zbe def int_riscv_bcompress : BitManipGPRGPRIntrinsics; def int_riscv_bdecompress : BitManipGPRGPRIntrinsics; // Zbm def int_riscv_bmator : BitManipGPRGPRIntrinsics; def int_riscv_bmatxor : BitManipGPRGPRIntrinsics; def int_riscv_bmatflip : BitManipGPRIntrinsics; // Zbp def int_riscv_grev : BitManipGPRGPRIntrinsics; def int_riscv_gorc : BitManipGPRGPRIntrinsics; def int_riscv_shfl : BitManipGPRGPRIntrinsics; def int_riscv_unshfl : BitManipGPRGPRIntrinsics; def int_riscv_xperm_n : BitManipGPRGPRIntrinsics; def int_riscv_xperm_b : BitManipGPRGPRIntrinsics; def int_riscv_xperm_h : BitManipGPRGPRIntrinsics; def int_riscv_xperm_w : BitManipGPRGPRIntrinsics; // Zbr def int_riscv_crc32_b : BitManipGPRIntrinsics; def int_riscv_crc32_h : BitManipGPRIntrinsics; def int_riscv_crc32_w : BitManipGPRIntrinsics; def int_riscv_crc32_d : BitManipGPRIntrinsics; def int_riscv_crc32c_b : BitManipGPRIntrinsics; def int_riscv_crc32c_h : BitManipGPRIntrinsics; def int_riscv_crc32c_w : BitManipGPRIntrinsics; def int_riscv_crc32c_d : BitManipGPRIntrinsics; } // TargetPrefix = "riscv"
We defined two new classes that’s derived form base type Intrinsic
class BitManipGPRIntrinsics
: Intrinsic<[llvm_any_ty],
[LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
will be used for instruction with only one input, like orc.b rd, rs1
class BitManipGPRGPRIntrinsics
: Intrinsic<[llvm_any_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
will be used for instruction with two input operands, like clmul rd, rs1, rs2
Then we categorize all specific instruction to these two class.
PatGpr was missing, so let’s add it back
llvm/lib/Target/RISCV/RISCVInstrInfo.td
// // Naming convention: For 'generic' pattern classes, we use the naming // convention PatTy1Ty2. For pattern classes which offer a more complex // expansion, prefix the class name, e.g. BccPat. //===----------------------------------------------------------------------===// /// Generic pattern classes +class PatGpr<SDPatternOperator OpNode, RVInst Inst> + : Pat<(OpNode GPR:$rs1), (Inst GPR:$rs1)>; class PatGprGpr<SDPatternOperator OpNode, RVInst Inst> : Pat<(OpNode GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>; class PatGprSimm12<SDPatternOperator OpNode, RVInstI Inst> : Pat<(OpNode GPR:$rs1, simm12:$imm12), (Inst GPR:$rs1, simm12:$imm12)>; class PatGprUimmLog2XLen<SDPatternOperator OpNode, RVInstIShift Inst> : Pat<(OpNode GPR:$rs1, uimmlog2xlen:$shamt), (Inst GPR:$rs1, uimmlog2xlen:$shamt)>;
In order to make clang emit the correct info when Zb* is missing, we need some change in
clang/lib/Sema/SemaChecking.cpp
bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { // CodeGenFunction can also detect this, but this gives a better error // message. + bool FeatureMissing = false; + SmallVector<StringRef> ReqFeatures; StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); - if (Features.find("experimental-v") != StringRef::npos && - !TI.hasFeature("experimental-v")) - return Diag(TheCall->getBeginLoc(), diag::err_riscvv_builtin_requires_v) - << TheCall->getSourceRange(); + Features.split(ReqFeatures, ','); - return false; + // Check if each required feature is included + for (auto &I : ReqFeatures) { + if (TI.hasFeature(I)) + continue; + // Make message like "experimental-zbr" to "Zbr" + I.consume_front("experimental-"); + std::string FeatureStr = I.str(); + FeatureStr[0] = std::toupper(FeatureStr[0]); + + // Error message + FeatureMissing = true; + Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) + << TheCall->getSourceRange() << StringRef(FeatureStr); + } + + return FeatureMissing; }
clang/include/clang/Basic/DiagnosticSemaKinds.td
-// RISC-V V-extension +// RISC-V builtin required extension warning -def err_riscvv_builtin_requires_v : Error< +def err_riscv_builtin_requires_extension : Error< - "builtin requires 'V' extension support to be enabled">; + "builtin requires %0 extension support to be enabled">;
So that Clang will print “builtin requires Zb* extension support to be enabled” when “-Xclang +experimental-zbr” is missing when compiling.
Now we need predicates and InstAlias
llvm/lib/Target/RISCV/RISCVInstrInfoB.td
def riscv_gorc : SDNode<"RISCVISD::GORC", SDTIntBinOp>; def riscv_gorcw : SDNode<"RISCVISD::GORCW", SDT_RISCVIntBinOpW>; def riscv_shfl : SDNode<"RISCVISD::SHFL", SDTIntBinOp>; +def riscv_shflw : SDNode<"RISCVISD::SHFLW", SDT_RISCVIntBinOpW>; +def riscv_unshfl : SDNode<"RISCVISD::UNSHFL", SDTIntBinOp>; +def riscv_unshflw: SDNode<"RISCVISD::UNSHFLW",SDT_RISCVIntBinOpW>; +def riscv_bcompress : SDNode<"RISCVISD::BCOMPRESS", SDTIntBinOp>; +def riscv_bcompressw : SDNode<"RISCVISD::BCOMPRESSW", SDT_RISCVIntBinOpW>; +def riscv_bdecompress : SDNode<"RISCVISD::BDECOMPRESS", SDTIntBinOp>; +def riscv_bdecompressw : SDNode<"RISCVISD::BDECOMPRESSW",SDT_RISCVIntBinOpW>; ... let Predicates = [HasStdExtZbbOrZbp, IsRV64] in { def : InstAlias<"rorw $rd, $rs1, $shamt", (RORIW GPR:$rd, GPR:$rs1, uimm5:$shamt), 0>; } // Predicates = [HasStdExtZbbOrZbp, IsRV64] +let Predicates = [HasStdExtZbp] in { +def : InstAlias<"grev $rd, $rs1, $shamt", + (GREVI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; +def : InstAlias<"gorc $rd, $rs1, $shamt", + (GORCI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; +def : InstAlias<"shfl $rd, $rs1, $shamt", + (SHFLI GPR:$rd, GPR:$rs1, shfl_uimm:$shamt), 0>; +def : InstAlias<"unshfl $rd, $rs1, $shamt", + (UNSHFLI GPR:$rd, GPR:$rs1, shfl_uimm:$shamt), 0>; +} // Predicates = [HasStdExtZbp] + +let Predicates = [HasStdExtZbp, IsRV64] in { +def : InstAlias<"grevw $rd, $rs1, $shamt", + (GREVIW GPR:$rd, GPR:$rs1, uimm5:$shamt), 0>; +def : InstAlias<"gorcw $rd, $rs1, $shamt", + (GORCIW GPR:$rd, GPR:$rs1, uimm5:$shamt), 0>; +} // Predicates = [HasStdExtZbp, IsRV64] + let Predicates = [HasStdExtZbs] in { ... let Predicates = [HasStdExtZbp] in { +def : PatGprGpr<riscv_grev, GREV>; +def : PatGprGpr<riscv_gorc, GORC>; +def : PatGprGpr<riscv_shfl, SHFL>; +def : PatGprGpr<riscv_unshfl, UNSHFL>; +def : PatGprGpr<int_riscv_xperm_n, XPERMN>; +def : PatGprGpr<int_riscv_xperm_b, XPERMB>; +def : PatGprGpr<int_riscv_xperm_h, XPERMH>; +def : PatGprGpr<int_riscv_xperm_w, XPERMW>; def : PatGprImm<riscv_shfl, SHFLI, shfl_uimm>; +def : PatGprImm<riscv_unshfl, UNSHFLI, shfl_uimm>; def : PatGprImm<riscv_grev, GREVI, uimmlog2xlen>; ... let Predicates = [HasStdExtZbp, IsRV64] in { def : Pat<(riscv_rorw (riscv_grevw GPR:$rs1, 24), 16), (GREVIW GPR:$rs1, 8)>; def : Pat<(riscv_rolw (riscv_grevw GPR:$rs1, 24), 16), (GREVIW GPR:$rs1, 8)>; +def : PatGprGpr<riscv_grevw, GREVW>; +def : PatGprGpr<riscv_gorcw, GORCW>; +def : PatGprGpr<riscv_shflw, SHFLW>; +def : PatGprGpr<riscv_unshflw, UNSHFLW>; def : PatGprImm<riscv_grevw, GREVIW, uimm5>; def : PatGprImm<riscv_gorcw, GORCIW, uimm5>; } // Predicates = [HasStdExtZbp, IsRV64]
let Predicates = [HasStdExtZbbOrZbp] in { def : InstAlias<"ror $rd, $rs1, $shamt", (RORI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; } // Predicates = [HasStdExtZbbOrZbp] let Predicates = [HasStdExtZbbOrZbp, IsRV64] in { def : InstAlias<"rorw $rd, $rs1, $shamt", (RORIW GPR:$rd, GPR:$rs1, uimm5:$shamt), 0>; } // Predicates = [HasStdExtZbbOrZbp, IsRV64] let Predicates = [HasStdExtZbs] in { def : InstAlias<"bset $rd, $rs1, $shamt", (BSETI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; def : InstAlias<"bclr $rd, $rs1, $shamt", (BCLRI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; def : InstAlias<"binv $rd, $rs1, $shamt", (BINVI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; def : InstAlias<"bext $rd, $rs1, $shamt", (BEXTI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; } // Predicates = [HasStdExtZbs] ... let Predicates = [HasStdExtZbc] in { def : PatGprGpr<int_riscv_clmul, CLMUL>; def : PatGprGpr<int_riscv_clmulh, CLMULH>; def : PatGprGpr<int_riscv_clmulr, CLMULR>; } // Predicates = [HasStdExtZbc] let Predicates = [HasStdExtZbe] in { def : PatGprGpr<riscv_bcompress, BCOMPRESS>; def : PatGprGpr<riscv_bdecompress, BDECOMPRESS>; } // Predicates = [HasStdExtZbe] let Predicates = [HasStdExtZbe, IsRV64] in { def : PatGprGpr<riscv_bcompressw, BCOMPRESSW>; def : PatGprGpr<riscv_bdecompressw, BDECOMPRESSW>; } // Predicates = [HasStdExtZbe, IsRV64] let Predicates = [HasStdExtZbm, IsRV64] in { def : PatGprGpr<int_riscv_bmator, BMATOR>; def : PatGprGpr<int_riscv_bmatxor, BMATXOR>; def : PatGpr<int_riscv_bmatflip, BMATFLIP>; } // Predicates = [HasStdExtZbm, IsRV64] let Predicates = [HasStdExtZbr] in { def : PatGpr<int_riscv_crc32_b, CRC32B>; def : PatGpr<int_riscv_crc32_h, CRC32H>; def : PatGpr<int_riscv_crc32_w, CRC32W>; def : PatGpr<int_riscv_crc32c_b, CRC32CB>; def : PatGpr<int_riscv_crc32c_h, CRC32CH>; def : PatGpr<int_riscv_crc32c_w, CRC32CW>; } // Predicates = [HasStdExtZbr] let Predicates = [HasStdExtZbr, IsRV64] in { def : PatGpr<int_riscv_crc32_d, CRC32D>; def : PatGpr<int_riscv_crc32c_d, CRC32CD>; } // Predicates = [HasStdExtZbr, IsRV64]
Then some of *.w instruction requires sign-extendtion and truncation in SelLowering:
llvm/lib/Target/RISCV/RISCVISelLowering.h
GREV, GREVW, GORC, GORCW, SHFL, SHFLW, UNSHFL, UNSHFLW, + // Bit Compress/Decompress implement the generic bit extract and bit deposit + // functions. This operation is also referred to as bit gather/scatter, bit + // pack/unpack, parallel extract/deposit, compress/expand, or right + // compress/right expand. + BCOMPRESS, + BCOMPRESSW, + BDECOMPRESS, + BDECOMPRESSW, // Vector Extension // VMV_V_X_VL matches the semantics of vmv.v.x but includes an extra operand // for the VL value to be used for the operation. VMV_V_X_VL, // VFMV_V_F_VL matches the semantics of vfmv.v.f but includes an extra operand // for the VL value to be used for the operation.
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
if (Subtarget.hasStdExtZbb() && Subtarget.is64Bit()) setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i32, Custom); + if (Subtarget.hasStdExtZbe() && Subtarget.is64Bit()) + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i32, Custom); if (Subtarget.is64Bit()) { setOperationAction(ISD::ADD, MVT::i32, Custom); setOperationAction(ISD::SUB, MVT::i32, Custom); ... if (Subtarget.is64Bit()) { setOperationAction(ISD::BITREVERSE, MVT::i32, Custom); setOperationAction(ISD::BSWAP, MVT::i32, Custom); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i32, Custom); } ... case Intrinsic::riscv_orc_b: // Lower to the GORCI encoding for orc.b. return DAG.getNode(RISCVISD::GORC, DL, XLenVT, Op.getOperand(1), DAG.getConstant(7, DL, XLenVT)); + case Intrinsic::riscv_grev: + case Intrinsic::riscv_gorc: { + unsigned Opc = + IntNo == Intrinsic::riscv_grev ? RISCVISD::GREV : RISCVISD::GORC; + return DAG.getNode(Opc, DL, XLenVT, Op.getOperand(1), Op.getOperand(2)); + } + case Intrinsic::riscv_shfl: + case Intrinsic::riscv_unshfl: { + unsigned Opc = + IntNo == Intrinsic::riscv_shfl ? RISCVISD::SHFL : RISCVISD::UNSHFL; + return DAG.getNode(Opc, DL, XLenVT, Op.getOperand(1), Op.getOperand(2)); + } + case Intrinsic::riscv_bcompress: + case Intrinsic::riscv_bdecompress: { + unsigned Opc = IntNo == Intrinsic::riscv_bcompress ? RISCVISD::BCOMPRESS + : RISCVISD::BDECOMPRESS; + return DAG.getNode(Opc, DL, XLenVT, Op.getOperand(1), Op.getOperand(2)); + } case Intrinsic::riscv_vmv_x_s: assert(Op.getValueType() == XLenVT && "Unexpected VT!"); return DAG.getNode(RISCVISD::VMV_X_S, DL, Op.getValueType(), Op.getOperand(1)); ... SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp, DAG.getConstant(7, DL, MVT::i64)); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); return; } + case Intrinsic::riscv_grev: + case Intrinsic::riscv_gorc: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue NewOp1 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); + SDValue NewOp2 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2)); + unsigned Opc = + IntNo == Intrinsic::riscv_grev ? RISCVISD::GREVW : RISCVISD::GORCW; + SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); + break; + } + case Intrinsic::riscv_shfl: + case Intrinsic::riscv_unshfl: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue NewOp1 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); + SDValue NewOp2 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2)); + unsigned Opc = + IntNo == Intrinsic::riscv_shfl ? RISCVISD::SHFLW : RISCVISD::UNSHFLW; + if (isa<ConstantSDNode>(N->getOperand(2))) { + NewOp2 = DAG.getNode(ISD::AND, DL, MVT::i64, NewOp2, + DAG.getConstant(0xf, DL, MVT::i64)); + Opc = + IntNo == Intrinsic::riscv_shfl ? RISCVISD::SHFL : RISCVISD::UNSHFL; + } + SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); + break; + } + case Intrinsic::riscv_bcompress: + case Intrinsic::riscv_bdecompress: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue NewOp1 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); + SDValue NewOp2 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2)); + unsigned Opc = IntNo == Intrinsic::riscv_bcompress + ? RISCVISD::BCOMPRESSW + : RISCVISD::BDECOMPRESSW; + SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); + break; + } case Intrinsic::riscv_vmv_x_s: { ... IntNo == Intrinsic::riscv_shfl ? RISCVISD::SHFL : RISCVISD::UNSHFL; } SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); break; } + case Intrinsic::riscv_bcompress: + case Intrinsic::riscv_bdecompress: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue NewOp1 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); + SDValue NewOp2 = + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2)); + unsigned Opc = IntNo == Intrinsic::riscv_bcompress + ? RISCVISD::BCOMPRESSW + : RISCVISD::BDECOMPRESSW; + SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp1, NewOp2); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); + break; + } case Intrinsic::riscv_vmv_x_s: { EVT VT = N->getValueType(0); MVT XLenVT = Subtarget.getXLenVT(); if (VT.bitsLT(XLenVT)) { ... case RISCVISD::FSLW: case RISCVISD::FSRW: + case RISCVISD::SHFLW: + case RISCVISD::UNSHFLW: + case RISCVISD::BCOMPRESSW: + case RISCVISD::BDECOMPRESSW: // TODO: As the result is sign-extended, this is conservatively correct. A // more precise answer could be calculated for SRAW depending on known // bits in the shift amount. return 33; + case RISCVISD::SHFL: + case RISCVISD::UNSHFL: { // There is no SHFLIW, but a i64 SHFLI with bit 4 of the control word // cleared doesn't affect bit 31. The upper 32 bits will be shuffled, but // will stay within the upper 32 bits. If there were more than 32 sign bits // before there will be at least 33 sign bits after. if (Op.getValueType() == MVT::i64 && isa<ConstantSDNode>(Op.getOperand(1)) && (Op.getConstantOperandVal(1) & 0x10) == 0) { unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1); ... NODE_NAME_CASE(GREVW) NODE_NAME_CASE(GORC) NODE_NAME_CASE(GORCW) NODE_NAME_CASE(SHFL) + NODE_NAME_CASE(SHFLW) + NODE_NAME_CASE(UNSHFL) + NODE_NAME_CASE(UNSHFLW) + NODE_NAME_CASE(BCOMPRESS) + NODE_NAME_CASE(BCOMPRESSW) + NODE_NAME_CASE(BDECOMPRESS) + NODE_NAME_CASE(BDECOMPRESSW) NODE_NAME_CASE(VMV_V_X_VL) NODE_NAME_CASE(VFMV_V_F_VL)
Although there is still some test cases lf if you want submit a formal patch, we’ve done most of work on backend, let’s shift to front end and check what needs to be done.
First let’s define those intrinsic in
clang/include/clang/Basic/BuiltinsRISCV.def
// Zbb extension TARGET_BUILTIN(__builtin_riscv_orc_b_32, "ZiZi", "nc", "experimental-zbb") TARGET_BUILTIN(__builtin_riscv_orc_b_64, "WiWi", "nc", "experimental-zbb,64bit") // Zbc extension TARGET_BUILTIN(__builtin_riscv_clmul, "LiLiLi", "nc", "experimental-zbc") TARGET_BUILTIN(__builtin_riscv_clmulh, "LiLiLi", "nc", "experimental-zbc") TARGET_BUILTIN(__builtin_riscv_clmulr, "LiLiLi", "nc", "experimental-zbc") // Zbe extension TARGET_BUILTIN(__builtin_riscv_bcompress_32, "ZiZiZi", "nc", "experimental-zbe") TARGET_BUILTIN(__builtin_riscv_bcompress_64, "WiWiWi", "nc", "experimental-zbe,64bit") TARGET_BUILTIN(__builtin_riscv_bdecompress_32, "ZiZiZi", "nc", "experimental-zbe") TARGET_BUILTIN(__builtin_riscv_bdecompress_64, "WiWiWi", "nc", "experimental-zbe,64bit") // Zbm extension TARGET_BUILTIN(__builtin_riscv_bmator, "WiWiWi", "nc","experimental-zbm,64bit") TARGET_BUILTIN(__builtin_riscv_bmatxor, "WiWiWi", "nc", "experimental-zbm,64bit") TARGET_BUILTIN(__builtin_riscv_bmatflip, "WiWi", "nc", "experimental-zbm,64bit") // Zbp extension TARGET_BUILTIN(__builtin_riscv_grev_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_grev_64, "WiWiWi", "nc", "experimental-zbp,64bit") TARGET_BUILTIN(__builtin_riscv_gorc_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_gorc_64, "WiWiWi", "nc", "experimental-zbp,64bit") TARGET_BUILTIN(__builtin_riscv_shfl_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_shfl_64, "WiWiWi", "nc", "experimental-zbp,64bit") TARGET_BUILTIN(__builtin_riscv_unshfl_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_unshfl_64, "WiWiWi", "nc", "experimental-zbp,64bit") TARGET_BUILTIN(__builtin_riscv_xperm_n, "LiLiLi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_xperm_b, "LiLiLi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_xperm_h, "LiLiLi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_xperm_w, "WiWiWi", "nc", "experimental-zbp,64bit") // Zbr extension TARGET_BUILTIN(__builtin_riscv_crc32_b, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32_h, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32_w, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32c_b, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32c_h, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32c_w, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32_d, "LiLi", "nc", "experimental-zbr") TARGET_BUILTIN(__builtin_riscv_crc32c_d, "LiLi", "nc", "experimental-zbr")
clang/lib/CodeGen/CGBuiltin.cpp
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { SmallVector<Value *, 4> Ops; llvm::Type *ResultType = ConvertType(E->getType()); for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); Intrinsic::ID ID = Intrinsic::not_intrinsic; // Required for overloaded intrinsics. llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; switch (BuiltinID) { default: llvm_unreachable("unexpected builtin ID"); case RISCV::BI__builtin_riscv_orc_b_32: case RISCV::BI__builtin_riscv_orc_b_64: case RISCV::BI__builtin_riscv_clmul: case RISCV::BI__builtin_riscv_clmulh: case RISCV::BI__builtin_riscv_clmulr: case RISCV::BI__builtin_riscv_bmator: case RISCV::BI__builtin_riscv_bmatxor: case RISCV::BI__builtin_riscv_bmatflip: case RISCV::BI__builtin_riscv_bcompress_32: case RISCV::BI__builtin_riscv_bcompress_64: case RISCV::BI__builtin_riscv_bdecompress_32: case RISCV::BI__builtin_riscv_bdecompress_64: case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: case RISCV::BI__builtin_riscv_gorc_32: case RISCV::BI__builtin_riscv_gorc_64: case RISCV::BI__builtin_riscv_shfl_32: case RISCV::BI__builtin_riscv_shfl_64: case RISCV::BI__builtin_riscv_unshfl_32: case RISCV::BI__builtin_riscv_unshfl_64: case RISCV::BI__builtin_riscv_xperm_n: case RISCV::BI__builtin_riscv_xperm_b: case RISCV::BI__builtin_riscv_xperm_h: case RISCV::BI__builtin_riscv_xperm_w: case RISCV::BI__builtin_riscv_crc32_b: case RISCV::BI__builtin_riscv_crc32_h: case RISCV::BI__builtin_riscv_crc32_w: case RISCV::BI__builtin_riscv_crc32_d: case RISCV::BI__builtin_riscv_crc32c_b: case RISCV::BI__builtin_riscv_crc32c_h: case RISCV::BI__builtin_riscv_crc32c_w: case RISCV::BI__builtin_riscv_crc32c_d: { switch (BuiltinID) { default: llvm_unreachable("unexpected builtin ID"); // Zbb case RISCV::BI__builtin_riscv_orc_b_32: case RISCV::BI__builtin_riscv_orc_b_64: ID = Intrinsic::riscv_orc_b; break; // Zbc case RISCV::BI__builtin_riscv_clmul: ID = Intrinsic::riscv_clmul; break; case RISCV::BI__builtin_riscv_clmulh: ID = Intrinsic::riscv_clmulh; break; case RISCV::BI__builtin_riscv_clmulr: ID = Intrinsic::riscv_clmulr; break; // Zbe case RISCV::BI__builtin_riscv_bcompress_32: case RISCV::BI__builtin_riscv_bcompress_64: ID = Intrinsic::riscv_bcompress; break; case RISCV::BI__builtin_riscv_bdecompress_32: case RISCV::BI__builtin_riscv_bdecompress_64: ID = Intrinsic::riscv_bdecompress; break; // Zbm case RISCV::BI__builtin_riscv_bmator: ID = Intrinsic::riscv_bmator; break; case RISCV::BI__builtin_riscv_bmatxor: ID = Intrinsic::riscv_bmatxor; break; case RISCV::BI__builtin_riscv_bmatflip: ID = Intrinsic::riscv_bmatflip; break; // Zbp case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: ID = Intrinsic::riscv_grev; break; case RISCV::BI__builtin_riscv_gorc_32: case RISCV::BI__builtin_riscv_gorc_64: ID = Intrinsic::riscv_gorc; break; case RISCV::BI__builtin_riscv_shfl_32: case RISCV::BI__builtin_riscv_shfl_64: ID = Intrinsic::riscv_shfl; break; case RISCV::BI__builtin_riscv_unshfl_32: case RISCV::BI__builtin_riscv_unshfl_64: ID = Intrinsic::riscv_unshfl; break; case RISCV::BI__builtin_riscv_xperm_n: ID = Intrinsic::riscv_xperm_n; break; case RISCV::BI__builtin_riscv_xperm_b: ID = Intrinsic::riscv_xperm_b; break; case RISCV::BI__builtin_riscv_xperm_h: ID = Intrinsic::riscv_xperm_h; break; case RISCV::BI__builtin_riscv_xperm_w: ID = Intrinsic::riscv_xperm_w; break; // Zbr case RISCV::BI__builtin_riscv_crc32_b: ID = Intrinsic::riscv_crc32_b; break; case RISCV::BI__builtin_riscv_crc32_h: ID = Intrinsic::riscv_crc32_h; break; case RISCV::BI__builtin_riscv_crc32_w: ID = Intrinsic::riscv_crc32_w; break; case RISCV::BI__builtin_riscv_crc32_d: ID = Intrinsic::riscv_crc32_d; break; case RISCV::BI__builtin_riscv_crc32c_b: ID = Intrinsic::riscv_crc32c_b; break; case RISCV::BI__builtin_riscv_crc32c_h: ID = Intrinsic::riscv_crc32c_h; break; case RISCV::BI__builtin_riscv_crc32c_w: ID = Intrinsic::riscv_crc32c_w; break; case RISCV::BI__builtin_riscv_crc32c_d: ID = Intrinsic::riscv_crc32c_d; break; } IntrinsicTypes = {ResultType}; break; } // Vector builtins are handled from here. #include "clang/Basic/riscv_vector_builtin_cg.inc" } assert(ID != Intrinsic::not_intrinsic); llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); return Builder.CreateCall(F, Ops, ""); }
Now you should have _builtin_riscv_* to use. If additional header is needed, please refer to [2/2] of each patch.