From 16877c5d2cd3f5c45642c9dc546c376ac87aa54d Mon Sep 17 00:00:00 2001 From: Lian Wang Date: Thu, 13 Jan 2022 02:53:00 +0000 Subject: [PATCH] [RISCV] Add bfp and bfpw intrinsic in zbf extension Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D116994 --- clang/include/clang/Basic/BuiltinsRISCV.def | 4 +++ clang/lib/CodeGen/CGBuiltin.cpp | 8 ++++++ .../CodeGen/RISCV/rvb-intrinsics/riscv32-zbf.c | 18 ++++++++++++ .../CodeGen/RISCV/rvb-intrinsics/riscv64-zbf.c | 33 ++++++++++++++++++++++ llvm/include/llvm/IR/IntrinsicsRISCV.td | 3 ++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 16 +++++++++++ llvm/lib/Target/RISCV/RISCVISelLowering.h | 7 +++++ llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 8 ++++++ llvm/test/CodeGen/RISCV/rv32zbf-intrinsic.ll | 14 +++++++++ llvm/test/CodeGen/RISCV/rv64zbf-intrinsic.ll | 25 ++++++++++++++++ 10 files changed, 136 insertions(+) create mode 100644 clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbf.c create mode 100644 clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbf.c create mode 100644 llvm/test/CodeGen/RISCV/rv32zbf-intrinsic.ll create mode 100644 llvm/test/CodeGen/RISCV/rv64zbf-intrinsic.ll diff --git a/clang/include/clang/Basic/BuiltinsRISCV.def b/clang/include/clang/Basic/BuiltinsRISCV.def index f33b2a8..81774d9 100644 --- a/clang/include/clang/Basic/BuiltinsRISCV.def +++ b/clang/include/clang/Basic/BuiltinsRISCV.def @@ -33,6 +33,10 @@ TARGET_BUILTIN(__builtin_riscv_bdecompress_32, "ZiZiZi", "nc", TARGET_BUILTIN(__builtin_riscv_bdecompress_64, "WiWiWi", "nc", "experimental-zbe,64bit") +// Zbf extension +TARGET_BUILTIN(__builtin_riscv_bfp_32, "ZiZiZi", "nc", "experimental-zbf") +TARGET_BUILTIN(__builtin_riscv_bfp_64, "WiWiWi", "nc", "experimental-zbf,64bit") + // Zbp extension TARGET_BUILTIN(__builtin_riscv_grev_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_grev_64, "WiWiWi", "nc", "experimental-zbp,64bit") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 91284ba..187a603 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18830,6 +18830,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, 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_bfp_32: + case RISCV::BI__builtin_riscv_bfp_64: case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: case RISCV::BI__builtin_riscv_gorc_32: @@ -18879,6 +18881,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, ID = Intrinsic::riscv_bdecompress; break; + // Zbf + case RISCV::BI__builtin_riscv_bfp_32: + case RISCV::BI__builtin_riscv_bfp_64: + ID = Intrinsic::riscv_bfp; + break; + // Zbp case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbf.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbf.c new file mode 100644 index 0000000..352a766 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbf.c @@ -0,0 +1,18 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +experimental-zbf -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV32ZBF + +// RV32ZBF-LABEL: @bfp32( +// RV32ZBF-NEXT: entry: +// RV32ZBF-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBF-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBF-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 +// RV32ZBF-NEXT: store i32 [[B:%.*]], i32* [[B_ADDR]], align 4 +// RV32ZBF-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4 +// RV32ZBF-NEXT: [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4 +// RV32ZBF-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.bfp.i32(i32 [[TMP0]], i32 [[TMP1]]) +// RV32ZBF-NEXT: ret i32 [[TMP2]] +// +int bfp32(int a, int b) { + return __builtin_riscv_bfp_32(a, b); +} diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbf.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbf.c new file mode 100644 index 0000000..d4d7402 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbf.c @@ -0,0 +1,33 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv64 -target-feature +experimental-zbf -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV64ZBF + +// RV64ZBF-LABEL: @bfp32( +// RV64ZBF-NEXT: entry: +// RV64ZBF-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// RV64ZBF-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// RV64ZBF-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 +// RV64ZBF-NEXT: store i32 [[B:%.*]], i32* [[B_ADDR]], align 4 +// RV64ZBF-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4 +// RV64ZBF-NEXT: [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4 +// RV64ZBF-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.bfp.i32(i32 [[TMP0]], i32 [[TMP1]]) +// RV64ZBF-NEXT: ret i32 [[TMP2]] +// +int bfp32(int a, int b) { + return __builtin_riscv_bfp_32(a, b); +} + +// RV64ZBF-LABEL: @bfp64( +// RV64ZBF-NEXT: entry: +// RV64ZBF-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBF-NEXT: [[B_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBF-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8 +// RV64ZBF-NEXT: store i64 [[B:%.*]], i64* [[B_ADDR]], align 8 +// RV64ZBF-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8 +// RV64ZBF-NEXT: [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8 +// RV64ZBF-NEXT: [[TMP2:%.*]] = call i64 @llvm.riscv.bfp.i64(i64 [[TMP0]], i64 [[TMP1]]) +// RV64ZBF-NEXT: ret i64 [[TMP2]] +// +long bfp64(long a, long b) { + return __builtin_riscv_bfp_64(a, b); +} diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td index 747049b..a3b4388 100644 --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -93,6 +93,9 @@ let TargetPrefix = "riscv" in { def int_riscv_bcompress : BitManipGPRGPRIntrinsics; def int_riscv_bdecompress : BitManipGPRGPRIntrinsics; + // Zbf + def int_riscv_bfp : BitManipGPRGPRIntrinsics; + // Zbp def int_riscv_grev : BitManipGPRGPRIntrinsics; def int_riscv_gorc : BitManipGPRGPRIntrinsics; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index a185e59..a9d52d1 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -4185,6 +4185,9 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, : RISCVISD::BDECOMPRESS; return DAG.getNode(Opc, DL, XLenVT, Op.getOperand(1), Op.getOperand(2)); } + case Intrinsic::riscv_bfp: + return DAG.getNode(RISCVISD::BFP, 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(), @@ -6275,6 +6278,17 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); break; } + case Intrinsic::riscv_bfp: { + 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)); + SDValue Res = DAG.getNode(RISCVISD::BFPW, 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(); @@ -9699,6 +9713,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { NODE_NAME_CASE(SHFLW) NODE_NAME_CASE(UNSHFL) NODE_NAME_CASE(UNSHFLW) + NODE_NAME_CASE(BFP) + NODE_NAME_CASE(BFPW) NODE_NAME_CASE(BCOMPRESS) NODE_NAME_CASE(BCOMPRESSW) NODE_NAME_CASE(BDECOMPRESS) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 4537dd7..199485e 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -120,6 +120,13 @@ enum NodeType : unsigned { BCOMPRESSW, BDECOMPRESS, BDECOMPRESSW, + // The bit field place (bfp) instruction places up to XLEN/2 LSB bits from rs2 + // into the value in rs1. The upper bits of rs2 control the length of the bit + // field and target position. The layout of rs2 is chosen in a way that makes + // it possible to construct rs2 easily using pack[h] instructions and/or + // andi/lui. + BFP, + BFPW, // 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. diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td index e21e3fb..12ce6ce 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -45,6 +45,8 @@ 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_bfp : SDNode<"RISCVISD::BFP", SDTIntBinOp>; +def riscv_bfpw : SDNode<"RISCVISD::BFPW", SDT_RISCVIntBinOpW>; def riscv_bcompress : SDNode<"RISCVISD::BCOMPRESS", SDTIntBinOp>; def riscv_bcompressw : SDNode<"RISCVISD::BCOMPRESSW", SDT_RISCVIntBinOpW>; def riscv_bdecompress : SDNode<"RISCVISD::BDECOMPRESS", SDTIntBinOp>; @@ -1129,3 +1131,9 @@ let Predicates = [HasStdExtZbr, IsRV64] in { def : PatGpr; def : PatGpr; } // Predicates = [HasStdExtZbr, IsRV64] + +let Predicates = [HasStdExtZbf] in +def : PatGprGpr; + +let Predicates = [HasStdExtZbf, IsRV64] in +def : PatGprGpr; diff --git a/llvm/test/CodeGen/RISCV/rv32zbf-intrinsic.ll b/llvm/test/CodeGen/RISCV/rv32zbf-intrinsic.ll new file mode 100644 index 0000000..f5ea414 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv32zbf-intrinsic.ll @@ -0,0 +1,14 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbf -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBF + +declare i32 @llvm.riscv.bfp.i32(i32 %a, i32 %b) + +define i32 @bfp32(i32 %a, i32 %b) nounwind { +; RV32ZBF-LABEL: bfp32: +; RV32ZBF: # %bb.0: +; RV32ZBF-NEXT: bfp a0, a0, a1 +; RV32ZBF-NEXT: ret + %tmp = call i32 @llvm.riscv.bfp.i32(i32 %a, i32 %b) + ret i32 %tmp +} diff --git a/llvm/test/CodeGen/RISCV/rv64zbf-intrinsic.ll b/llvm/test/CodeGen/RISCV/rv64zbf-intrinsic.ll new file mode 100644 index 0000000..ce1e613 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv64zbf-intrinsic.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbf -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBF + +declare i32 @llvm.riscv.bfp.i32(i32 %a, i32 %b) + +define i32 @bfp32(i32 %a, i32 %b) nounwind { +; RV64ZBF-LABEL: bfp32: +; RV64ZBF: # %bb.0: +; RV64ZBF-NEXT: bfpw a0, a0, a1 +; RV64ZBF-NEXT: ret + %tmp = call i32 @llvm.riscv.bfp.i32(i32 %a, i32 %b) + ret i32 %tmp +} + +declare i64 @llvm.riscv.bfp.i64(i64 %a, i64 %b) + +define i64 @bfp64(i64 %a, i64 %b) nounwind { +; RV64ZBF-LABEL: bfp64: +; RV64ZBF: # %bb.0: +; RV64ZBF-NEXT: bfp a0, a0, a1 +; RV64ZBF-NEXT: ret + %tmp = call i64 @llvm.riscv.bfp.i64(i64 %a, i64 %b) + ret i64 %tmp +} -- 2.7.4