diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst --- a/llvm/docs/RISCVUsage.rst +++ b/llvm/docs/RISCVUsage.rst @@ -172,6 +172,9 @@ ``XTHeadBa`` LLVM implements `the THeadBa (address-generation) vendor-defined instructions specified in `_ by T-HEAD of Alibaba. Instructions are prefixed with `th.` as described in the specification. +``XTHeadBs`` + LLVM implements `the THeadBs (single-bit operations) vendor-defined instructions specified in `_ by T-HEAD of Alibaba. Instructions are prefixed with `th.` as described in the specification. + ``XTHeadVdot`` LLVM implements `version 1.0.0 of the THeadV-family custom instructions specification `_ by T-HEAD of Alibaba. All instructions are prefixed with `th.` as described in the specification, and the riscv-toolchain-convention document linked above. diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -103,6 +103,7 @@ * Assembler support for version 1.0.1 of the Zcb extension was added. * Zca, Zcf, and Zcd extensions were upgraded to version 1.0.1. * Adds support for the vendor-defined XTHeadBa (address-generation) extension. +* Adds support for the vendor-defined XTHeadBs (single-bit) extension. Changes to the WebAssembly Backend ---------------------------------- diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -110,6 +110,7 @@ // vendor-defined ('X') extensions {"xtheadba", RISCVExtensionVersion{1, 0}}, + {"xtheadbs", RISCVExtensionVersion{1, 0}}, {"xtheadvdot", RISCVExtensionVersion{1, 0}}, {"xventanacondops", RISCVExtensionVersion{1, 0}}, }; diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -470,6 +470,13 @@ AssemblerPredicate<(all_of FeatureVendorXTHeadBa), "'xtheadba' (T-Head address calculation instructions)">; +def FeatureVendorXTHeadBs + : SubtargetFeature<"xtheadbs", "HasVendorXTHeadBs", "true", + "'xtheadbs' (T-Head single-bit instructions)">; +def HasVendorXTHeadBs : Predicate<"Subtarget->hasVendorXTHeadBs()">, + AssemblerPredicate<(all_of FeatureVendorXTHeadBs), + "'xtheadbs' (T-Head single-bit instructions)">; + def FeatureVendorXTHeadVdot : SubtargetFeature<"xtheadvdot", "HasVendorXTHeadVdot", "true", "'xtheadvdot' (T-Head Vector Extensions for Dot)", diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -797,13 +797,15 @@ break; // If C2 is (1 << ShAmt) use bexti if possible. - if (Subtarget->hasStdExtZbs() && ShAmt + 1 == TrailingOnes) { - SDNode *BEXTI = - CurDAG->getMachineNode(RISCV::BEXTI, DL, VT, N0->getOperand(0), - CurDAG->getTargetConstant(ShAmt, DL, VT)); + if ((Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs()) && + ShAmt + 1 == TrailingOnes) { + SDNode *BEXTI = CurDAG->getMachineNode( + Subtarget->hasStdExtZbs() ? RISCV::BEXTI : RISCV::TH_TST, DL, VT, + N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); ReplaceNode(Node, BEXTI); return; } + unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; SDNode *SLLI = CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), @@ -927,6 +929,7 @@ cast(X.getOperand(1))->getVT() == MVT::i32; // Also Skip if we can use bexti. Skip |= Subtarget->hasStdExtZbs() && Leading == XLen - 1; + Skip |= Subtarget->hasVendorXTHeadBs() && Leading == XLen - 1; if (OneUseOrZExtW && !Skip) { SDNode *SLLI = CurDAG->getMachineNode( RISCV::SLLI, DL, VT, X, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td @@ -75,6 +75,12 @@ Sched<[WriteSHXADD, ReadSHXADD, ReadSHXADD]>; } // Predicates = [HasVendorXTHeadBa] +let Predicates = [HasVendorXTHeadBs] in { +let IsSignExtendingOpW = 1 in +def TH_TST : RVBShift_ri<0b10001, 0b001, OPC_CUSTOM_0, "th.tst">, + Sched<[WriteSingleBitImm, ReadSingleBitImm]>; +} // Predicates = [HasVendorXTHeadBs] + let Predicates = [HasVendorXTHeadVdot], Constraints = "@earlyclobber $vd", RVVConstraint = WidenV in { @@ -224,6 +230,14 @@ (TH_ADDSL GPR:$r, GPR:$r, 2), 2), 3)>; } // Predicates = [HasVendorXTHeadBa] +let Predicates = [HasVendorXTHeadBs] in { +def : Pat<(and (srl GPR:$rs1, uimmlog2xlen:$shamt), 1), + (TH_TST GPR:$rs1, uimmlog2xlen:$shamt)>; +def : Pat<(seteq (and GPR:$rs1, SingleBitSetMask:$mask), 0), + (TH_TST (XORI GPR:$rs1, -1), SingleBitSetMask:$mask)>; +} // Predicates = [HasVendorXTHeadBs] + + defm PseudoTHVdotVMAQA : VPseudoVMAQA_VV_VX; defm PseudoTHVdotVMAQAU : VPseudoVMAQA_VV_VX; defm PseudoTHVdotVMAQASU : VPseudoVMAQA_VV_VX; diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -87,6 +87,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+svinval %s -o - | FileCheck --check-prefix=RV64SVINVAL %s ; RUN: llc -mtriple=riscv64 -mattr=+xventanacondops %s -o - | FileCheck --check-prefix=RV64XVENTANACONDOPS %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadba %s -o - | FileCheck --check-prefix=RV64XTHEADBA %s +; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs %s -o - | FileCheck --check-prefix=RV64XTHEADBS %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadvdot %s -o - | FileCheck --check-prefix=RV64XTHEADVDOT %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zawrs %s -o - | FileCheck --check-prefix=RV64ZAWRS %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-ztso %s -o - | FileCheck --check-prefix=RV64ZTSO %s @@ -182,6 +183,7 @@ ; RV64SVINVAL: .attribute 5, "rv64i2p0_svinval1p0" ; RV64XVENTANACONDOPS: .attribute 5, "rv64i2p0_xventanacondops1p0" ; RV64XTHEADBA: .attribute 5, "rv64i2p0_xtheadba1p0" +; RV64XTHEADBS: .attribute 5, "rv64i2p0_xtheadbs1p0" ; RV64XTHEADVDOT: .attribute 5, "rv64i2p0_f2p0_d2p0_v1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0_xtheadvdot1p0" ; RV64ZTSO: .attribute 5, "rv64i2p0_ztso0p1" ; RV64ZCA: .attribute 5, "rv64i2p0_zca1p0" diff --git a/llvm/test/CodeGen/RISCV/rv32xtheadbs.ll b/llvm/test/CodeGen/RISCV/rv32xtheadbs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv32xtheadbs.ll @@ -0,0 +1,76 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=CHECK,RV32I +; RUN: llc -mtriple=riscv32 -mattr=+xtheadbs -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=CHECK,RV32XTHEADBS + +define i32 @bexti_i32(i32 %a) nounwind { +; RV32I-LABEL: bexti_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 26 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: ret +; +; RV32XTHEADBS-LABEL: bexti_i32: +; RV32XTHEADBS: # %bb.0: +; RV32XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV32XTHEADBS-NEXT: ret + %shr = lshr i32 %a, 5 + %and = and i32 %shr, 1 + ret i32 %and +} + +define i64 @bexti_i64(i64 %a) nounwind { +; RV32I-LABEL: bexti_i64: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 26 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: li a1, 0 +; RV32I-NEXT: ret +; +; RV32XTHEADBS-LABEL: bexti_i64: +; RV32XTHEADBS: # %bb.0: +; RV32XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV32XTHEADBS-NEXT: li a1, 0 +; RV32XTHEADBS-NEXT: ret + %shr = lshr i64 %a, 5 + %and = and i64 %shr, 1 + ret i64 %and +} + +define signext i32 @bexti_i32_cmp(i32 signext %a) nounwind { +; RV32I-LABEL: bexti_i32_cmp: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 26 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: ret +; +; RV32XTHEADBS-LABEL: bexti_i32_cmp: +; RV32XTHEADBS: # %bb.0: +; RV32XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV32XTHEADBS-NEXT: ret + %and = and i32 %a, 32 + %cmp = icmp ne i32 %and, 0 + %zext = zext i1 %cmp to i32 + ret i32 %zext +} + +define i64 @bexti_i64_cmp(i64 %a) nounwind { +; RV32I-LABEL: bexti_i64_cmp: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 26 +; RV32I-NEXT: srli a0, a0, 31 +; RV32I-NEXT: li a1, 0 +; RV32I-NEXT: ret +; +; RV32XTHEADBS-LABEL: bexti_i64_cmp: +; RV32XTHEADBS: # %bb.0: +; RV32XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV32XTHEADBS-NEXT: li a1, 0 +; RV32XTHEADBS-NEXT: ret + %and = and i64 %a, 32 + %cmp = icmp ne i64 %and, 0 + %zext = zext i1 %cmp to i64 + ret i64 %zext +} + diff --git a/llvm/test/CodeGen/RISCV/rv64xtheadbs.ll b/llvm/test/CodeGen/RISCV/rv64xtheadbs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv64xtheadbs.ll @@ -0,0 +1,72 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=CHECK,RV64I +; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=CHECK,RV64XTHEADBS + +define signext i32 @bexti_i32(i32 signext %a) nounwind { +; RV64I-LABEL: bexti_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 58 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: ret +; +; RV64XTHEADBS-LABEL: bexti_i32: +; RV64XTHEADBS: # %bb.0: +; RV64XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV64XTHEADBS-NEXT: ret + %shr = lshr i32 %a, 5 + %and = and i32 %shr, 1 + ret i32 %and +} + +define i64 @bexti_i64(i64 %a) nounwind { +; RV64I-LABEL: bexti_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 58 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: ret +; +; RV64XTHEADBS-LABEL: bexti_i64: +; RV64XTHEADBS: # %bb.0: +; RV64XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV64XTHEADBS-NEXT: ret + %shr = lshr i64 %a, 5 + %and = and i64 %shr, 1 + ret i64 %and +} + +define signext i32 @bexti_i32_cmp(i32 signext %a) nounwind { +; RV64I-LABEL: bexti_i32_cmp: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 58 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: ret +; +; RV64XTHEADBS-LABEL: bexti_i32_cmp: +; RV64XTHEADBS: # %bb.0: +; RV64XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV64XTHEADBS-NEXT: ret + %and = and i32 %a, 32 + %cmp = icmp ne i32 %and, 0 + %zext = zext i1 %cmp to i32 + ret i32 %zext +} + +define i64 @bexti_i64_cmp(i64 %a) nounwind { +; RV64I-LABEL: bexti_i64_cmp: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 58 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: ret +; +; RV64XTHEADBS-LABEL: bexti_i64_cmp: +; RV64XTHEADBS: # %bb.0: +; RV64XTHEADBS-NEXT: th.tst a0, a0, 5 +; RV64XTHEADBS-NEXT: ret + %and = and i64 %a, 32 + %cmp = icmp ne i64 %and, 0 + %zext = zext i1 %cmp to i64 + ret i64 %zext +} + diff --git a/llvm/test/MC/RISCV/rv32xtheadbs-invalid.s b/llvm/test/MC/RISCV/rv32xtheadbs-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32xtheadbs-invalid.s @@ -0,0 +1,7 @@ +# RUN: not llvm-mc -triple riscv32 -mattr=+xtheadbs < %s 2>&1 | FileCheck %s + +# Too few operands +th.tst t0, t1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction +# Immediate operand out of range +th.tst t0, t1, 32 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31] +th.tst t0, t1, -1 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31] diff --git a/llvm/test/MC/RISCV/rv32xtheadbs-valid.s b/llvm/test/MC/RISCV/rv32xtheadbs-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32xtheadbs-valid.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+xtheadbs -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+xtheadbs -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+xtheadbs < %s \ +# RUN: | llvm-objdump --mattr=+xtheadbs -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+xtheadbs < %s \ +# RUN: | llvm-objdump --mattr=+xtheadbs -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: th.tst t0, t1, 1 +# CHECK-ASM: encoding: [0x8b,0x12,0x13,0x88] +th.tst t0, t1, 1 +# CHECK-ASM-AND-OBJ: th.tst t0, t1, 31 +# CHECK-ASM: encoding: [0x8b,0x12,0xf3,0x89] +th.tst t0, t1, 31 diff --git a/llvm/test/MC/RISCV/rv64xtheadbs-invalid.s b/llvm/test/MC/RISCV/rv64xtheadbs-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv64xtheadbs-invalid.s @@ -0,0 +1,5 @@ +# RUN: not llvm-mc -triple riscv64 -mattr=+xtheadbs < %s 2>&1 | FileCheck %s + +# Immediate operand out of range +th.tst t0, t1, 64 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 63] +th.tst t0, t1, -1 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 63]