[llvm] 656188d - [RISCV] Add vendor-defined XTHeadBs (single-bit) extension

Philipp Tomsich via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 7 22:57:39 PST 2023


Author: Philipp Tomsich
Date: 2023-02-08T07:57:27+01:00
New Revision: 656188ddc4075eb50260607b3497589873f373d2

URL: https://github.com/llvm/llvm-project/commit/656188ddc4075eb50260607b3497589873f373d2
DIFF: https://github.com/llvm/llvm-project/commit/656188ddc4075eb50260607b3497589873f373d2.diff

LOG: [RISCV] Add vendor-defined XTHeadBs (single-bit) extension

The vendor-defined XTHeadBs (predating the standard Zbs extension)
extension adds a bit-test instruction (th.tst) with similar semantics
as bexti from Zbs.  It is supported by the C9xx cores (e.g., found in
the wild in the Allwinner D1) by Alibaba T-Head.

The current (as of this commit) public documentation for XTHeadBs is
available from:
  https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.2.2/xthead-2023-01-30-2.2.2.pdf

Support for these instructions has already landed in GNU Binutils:
  https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=8254c3d2c94ae5458095ea6c25446ba89134b9da

Depends on D143394

Differential Revision: https://reviews.llvm.org/D143036

Added: 
    llvm/test/CodeGen/RISCV/rv32xtheadbs.ll
    llvm/test/CodeGen/RISCV/rv64xtheadbs.ll
    llvm/test/MC/RISCV/rv32xtheadbs-invalid.s
    llvm/test/MC/RISCV/rv32xtheadbs-valid.s
    llvm/test/MC/RISCV/rv64xtheadbs-invalid.s

Modified: 
    llvm/docs/RISCVUsage.rst
    llvm/docs/ReleaseNotes.rst
    llvm/lib/Support/RISCVISAInfo.cpp
    llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
    llvm/lib/Target/RISCV/RISCVFeatures.td
    llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
    llvm/test/CodeGen/RISCV/attributes.ll
    llvm/test/CodeGen/RISCV/bittest.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 251091788846d..a81896d89f0d2 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -172,6 +172,9 @@ The current vendor extensions supported are:
 ``XTHeadBa``
   LLVM implements `the THeadBa (address-generation) vendor-defined instructions specified in <https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.2.2/xthead-2023-01-30-2.2.2.pdf>`_  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 <https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.2.2/xthead-2023-01-30-2.2.2.pdf>`_  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 <https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.2.0/xthead-2022-12-04-2.2.0.pdf>`_ 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
index 75aeee6631276..7ade6be2fb6ef 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -109,6 +109,7 @@ Changes to the RISC-V Backend
 * vsetvli intrinsics no longer have side effects. They may now be combined,
   moved, deleted, etc. by optimizations.
 * 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
index fe1ee08189e0a..92c15885b225a 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -110,6 +110,7 @@ static const RISCVSupportedExtension SupportedExtensions[] = {
 
     // 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/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index bf60cd1c868ac..7276d8240520b 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -478,6 +478,13 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
       if (Result != MCDisassembler::Fail)
         return Result;
     }
+    if (STI.getFeatureBits()[RISCV::FeatureVendorXTHeadBs]) {
+      LLVM_DEBUG(dbgs() << "Trying XTHeadBs custom opcode table:\n");
+      Result = decodeInstruction(DecoderTableTHeadBs32, MI, Insn, Address, this,
+                                 STI);
+      if (Result != MCDisassembler::Fail)
+        return Result;
+    }
     if (STI.getFeatureBits()[RISCV::FeatureVendorXTHeadVdot]) {
       LLVM_DEBUG(dbgs() << "Trying XTHeadVdot custom opcode table:\n");
       Result =

diff  --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 6fd6f0cced718..838056f391c9a 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -470,6 +470,13 @@ def HasVendorXTHeadBa : Predicate<"Subtarget->hasVendorXTHeadBa()">,
                                   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
index 82a3458ec487a..ec7c4608f16cc 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -834,14 +834,17 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     if (!N0.hasOneUse())
       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 C2 is (1 << ShAmt) use bexti or th.tst if possible.
+    bool HasBitTest =
+        Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs();
+    if (HasBitTest && 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),
@@ -963,8 +966,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
           bool Skip = Subtarget->hasStdExtZba() && Leading == 32 &&
                       X.getOpcode() == ISD::SIGN_EXTEND_INREG &&
                       cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32;
-          // Also Skip if we can use bexti.
+          // Also Skip if we can use bexti or th.tst.
           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/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index eb37679b4d990..c2abb5cd4cb54 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1223,7 +1223,7 @@ bool RISCVTargetLowering::isMaskAndCmp0FoldingBeneficial(
   // on the basis that it's possible the sinking+duplication of the AND in
   // CodeGenPrepare triggered by this hook wouldn't decrease the instruction
   // count and would increase code size (e.g. ANDI+BNEZ => BEXTI+BNEZ).
-  if (!Subtarget.hasStdExtZbs())
+  if (!Subtarget.hasStdExtZbs() && !Subtarget.hasVendorXTHeadBs())
     return false;
   ConstantInt *Mask = dyn_cast<ConstantInt>(AndI.getOperand(1));
   if (!Mask)
@@ -1246,8 +1246,11 @@ bool RISCVTargetLowering::hasBitTest(SDValue X, SDValue Y) const {
   // Zbs provides BEXT[_I], which can be used with SEQZ/SNEZ as a bit test.
   if (Subtarget.hasStdExtZbs())
     return X.getValueType().isScalarInteger();
-  // We can use ANDI+SEQZ/SNEZ as a bit test. Y contains the bit position.
   auto *C = dyn_cast<ConstantSDNode>(Y);
+  // XTheadBs provides th.tst (similar to bexti), if Y is a constant
+  if (Subtarget.hasVendorXTHeadBs())
+    return C != nullptr;
+  // We can use ANDI+SEQZ/SNEZ as a bit test. Y contains the bit position.
   return C && C->getAPIntValue().ule(10);
 }
 

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
index 9cf61ffa00e8f..8f6690ac2c403 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td
@@ -75,6 +75,12 @@ def TH_ADDSL : THShiftALU_rri<0b001, "th.addsl">,
                Sched<[WriteSHXADD, ReadSHXADD, ReadSHXADD]>;
 } // Predicates = [HasVendorXTHeadBa]
 
+let Predicates = [HasVendorXTHeadBs], DecoderNamespace = "THeadBs" 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 {
@@ -163,6 +169,14 @@ def : Pat<(add sh3add_op:$rs1, non_imm12:$rs2),
           (TH_ADDSL GPR:$rs2, sh3add_op:$rs1, 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
index 3b965c1a9c6ed..bb84cc7978802 100644
--- 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/bittest.ll b/llvm/test/CodeGen/RISCV/bittest.ll
index 53943b11adfa4..5a11bbc64817f 100644
--- a/llvm/test/CodeGen/RISCV/bittest.ll
+++ b/llvm/test/CodeGen/RISCV/bittest.ll
@@ -7,6 +7,10 @@
 ; RUN:   | FileCheck %s -check-prefixes=CHECK,ZBS,RV32,RV32ZBS
 ; RUN: llc -mtriple=riscv64 -mattr=+zbs -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefixes=CHECK,ZBS,RV64,RV64ZBS
+; RUN: llc -mtriple=riscv32 -mattr=+xtheadbs -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=CHECK,XTHEADBS,RV32,RV32XTHEADBS
+; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=CHECK,XTHEADBS,RV64,RV64XTHEADBS
 
 define signext i32 @bittest_7_i32(i32 signext %a) nounwind {
 ; CHECK-LABEL: bittest_7_i32:
@@ -52,6 +56,12 @@ define signext i32 @bittest_11_i32(i32 signext %a) nounwind {
 ; ZBS-NEXT:    not a0, a0
 ; ZBS-NEXT:    bexti a0, a0, 11
 ; ZBS-NEXT:    ret
+;
+; XTHEADBS-LABEL: bittest_11_i32:
+; XTHEADBS:       # %bb.0:
+; XTHEADBS-NEXT:    not a0, a0
+; XTHEADBS-NEXT:    th.tst a0, a0, 11
+; XTHEADBS-NEXT:    ret
   %shr = lshr i32 %a, 11
   %not = xor i32 %shr, -1
   %and = and i32 %not, 1
@@ -142,6 +152,19 @@ define i64 @bittest_11_i64(i64 %a) nounwind {
 ; RV64ZBS-NEXT:    not a0, a0
 ; RV64ZBS-NEXT:    bexti a0, a0, 11
 ; RV64ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bittest_11_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    not a0, a0
+; RV32XTHEADBS-NEXT:    th.tst a0, a0, 11
+; RV32XTHEADBS-NEXT:    li a1, 0
+; RV32XTHEADBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_11_i64:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    not a0, a0
+; RV64XTHEADBS-NEXT:    th.tst a0, a0, 11
+; RV64XTHEADBS-NEXT:    ret
   %shr = lshr i64 %a, 11
   %not = xor i64 %shr, -1
   %and = and i64 %not, 1
@@ -167,6 +190,12 @@ define i64 @bittest_31_i64(i64 %a) nounwind {
 ; RV64ZBS-NEXT:    not a0, a0
 ; RV64ZBS-NEXT:    bexti a0, a0, 31
 ; RV64ZBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_31_i64:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    not a0, a0
+; RV64XTHEADBS-NEXT:    th.tst a0, a0, 31
+; RV64XTHEADBS-NEXT:    ret
   %shr = lshr i64 %a, 31
   %not = xor i64 %shr, -1
   %and = and i64 %not, 1
@@ -193,6 +222,12 @@ define i64 @bittest_32_i64(i64 %a) nounwind {
 ; RV64ZBS-NEXT:    not a0, a0
 ; RV64ZBS-NEXT:    bexti a0, a0, 32
 ; RV64ZBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_32_i64:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    not a0, a0
+; RV64XTHEADBS-NEXT:    th.tst a0, a0, 32
+; RV64XTHEADBS-NEXT:    ret
   %shr = lshr i64 %a, 32
   %not = xor i64 %shr, -1
   %and = and i64 %not, 1
@@ -249,6 +284,22 @@ define i1 @bittest_constant_by_var_shr_i32(i32 signext %b) nounwind {
 ; RV64ZBS-NEXT:    addiw a1, a1, 722
 ; RV64ZBS-NEXT:    bext a0, a1, a0
 ; RV64ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bittest_constant_by_var_shr_i32:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    lui a1, 301408
+; RV32XTHEADBS-NEXT:    addi a1, a1, 722
+; RV32XTHEADBS-NEXT:    srl a0, a1, a0
+; RV32XTHEADBS-NEXT:    andi a0, a0, 1
+; RV32XTHEADBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_constant_by_var_shr_i32:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    lui a1, 301408
+; RV64XTHEADBS-NEXT:    addiw a1, a1, 722
+; RV64XTHEADBS-NEXT:    srlw a0, a1, a0
+; RV64XTHEADBS-NEXT:    andi a0, a0, 1
+; RV64XTHEADBS-NEXT:    ret
   %shl = lshr i32 1234567890, %b
   %and = and i32 %shl, 1
   %cmp = icmp ne i32 %and, 0
@@ -286,6 +337,22 @@ define i1 @bittest_constant_by_var_shl_i32(i32 signext %b) nounwind {
 ; RV64ZBS-NEXT:    addiw a1, a1, 722
 ; RV64ZBS-NEXT:    bext a0, a1, a0
 ; RV64ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bittest_constant_by_var_shl_i32:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    lui a1, 301408
+; RV32XTHEADBS-NEXT:    addi a1, a1, 722
+; RV32XTHEADBS-NEXT:    srl a0, a1, a0
+; RV32XTHEADBS-NEXT:    andi a0, a0, 1
+; RV32XTHEADBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_constant_by_var_shl_i32:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    lui a1, 301408
+; RV64XTHEADBS-NEXT:    addiw a1, a1, 722
+; RV64XTHEADBS-NEXT:    srlw a0, a1, a0
+; RV64XTHEADBS-NEXT:    andi a0, a0, 1
+; RV64XTHEADBS-NEXT:    ret
   %shl = shl i32 1, %b
   %and = and i32 %shl, 1234567890
   %cmp = icmp ne i32 %and, 0
@@ -318,6 +385,14 @@ define i1 @bittest_constant_by_var_shr_i64(i64 %b) nounwind {
 ; RV64ZBS-NEXT:    addiw a1, a1, 722
 ; RV64ZBS-NEXT:    bext a0, a1, a0
 ; RV64ZBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_constant_by_var_shr_i64:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    lui a1, 301408
+; RV64XTHEADBS-NEXT:    addiw a1, a1, 722
+; RV64XTHEADBS-NEXT:    srl a0, a1, a0
+; RV64XTHEADBS-NEXT:    andi a0, a0, 1
+; RV64XTHEADBS-NEXT:    ret
   %shl = lshr i64 1234567890, %b
   %and = and i64 %shl, 1
   %cmp = icmp ne i64 %and, 0
@@ -350,6 +425,14 @@ define i1 @bittest_constant_by_var_shl_i64(i64 %b) nounwind {
 ; RV64ZBS-NEXT:    addiw a1, a1, 722
 ; RV64ZBS-NEXT:    bext a0, a1, a0
 ; RV64ZBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_constant_by_var_shl_i64:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    lui a1, 301408
+; RV64XTHEADBS-NEXT:    addiw a1, a1, 722
+; RV64XTHEADBS-NEXT:    srl a0, a1, a0
+; RV64XTHEADBS-NEXT:    andi a0, a0, 1
+; RV64XTHEADBS-NEXT:    ret
   %shl = shl i64 1, %b
   %and = and i64 %shl, 1234567890
   %cmp = icmp ne i64 %and, 0
@@ -417,6 +500,37 @@ define void @bittest_switch(i32 signext %0) {
 ; RV64ZBS-NEXT:    tail bar at plt
 ; RV64ZBS-NEXT:  .LBB14_3:
 ; RV64ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bittest_switch:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    li a1, 31
+; RV32XTHEADBS-NEXT:    bltu a1, a0, .LBB14_3
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    lui a1, 524291
+; RV32XTHEADBS-NEXT:    addi a1, a1, 768
+; RV32XTHEADBS-NEXT:    srl a0, a1, a0
+; RV32XTHEADBS-NEXT:    andi a0, a0, 1
+; RV32XTHEADBS-NEXT:    beqz a0, .LBB14_3
+; RV32XTHEADBS-NEXT:  # %bb.2:
+; RV32XTHEADBS-NEXT:    tail bar at plt
+; RV32XTHEADBS-NEXT:  .LBB14_3:
+; RV32XTHEADBS-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: bittest_switch:
+; RV64XTHEADBS:       # %bb.0:
+; RV64XTHEADBS-NEXT:    li a1, 31
+; RV64XTHEADBS-NEXT:    bltu a1, a0, .LBB14_3
+; RV64XTHEADBS-NEXT:  # %bb.1:
+; RV64XTHEADBS-NEXT:    lui a1, 2048
+; RV64XTHEADBS-NEXT:    addiw a1, a1, 51
+; RV64XTHEADBS-NEXT:    slli a1, a1, 8
+; RV64XTHEADBS-NEXT:    srl a0, a1, a0
+; RV64XTHEADBS-NEXT:    andi a0, a0, 1
+; RV64XTHEADBS-NEXT:    beqz a0, .LBB14_3
+; RV64XTHEADBS-NEXT:  # %bb.2:
+; RV64XTHEADBS-NEXT:    tail bar at plt
+; RV64XTHEADBS-NEXT:  .LBB14_3:
+; RV64XTHEADBS-NEXT:    ret
   switch i32 %0, label %3 [
     i32 8, label %2
     i32 9, label %2
@@ -697,6 +811,18 @@ define i64 @bit_10_nz_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB24_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_10_nz_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    th.tst a6, a0, 10
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    bnez a6, .LBB24_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB24_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 1024
   %2 = icmp ne i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -766,6 +892,18 @@ define i64 @bit_11_nz_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB26_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_11_nz_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    th.tst a6, a0, 11
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    bnez a6, .LBB26_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB26_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 2048
   %2 = icmp ne i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -835,6 +973,18 @@ define i64 @bit_20_nz_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB28_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_20_nz_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    th.tst a6, a0, 20
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    bnez a6, .LBB28_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB28_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 1048576
   %2 = icmp ne i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -1015,6 +1165,18 @@ define i64 @bit_55_nz_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB34_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_55_nz_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    th.tst a6, a1, 23
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    bnez a6, .LBB34_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB34_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 36028797018963968
   %2 = icmp ne i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -2374,6 +2536,20 @@ define i64 @bit_63_1_z_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB85_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_63_1_z_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    slli a1, a1, 1
+; RV32XTHEADBS-NEXT:    srli a1, a1, 1
+; RV32XTHEADBS-NEXT:    or a6, a0, a1
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    beqz a6, .LBB85_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB85_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 9223372036854775807
   %2 = icmp eq i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -2417,6 +2593,20 @@ define i64 @bit_63_1_nz_select_i64(i64 %a, i64 %b, i64 %c) {
 ; RV32ZBS-NEXT:    mv a1, a5
 ; RV32ZBS-NEXT:  .LBB86_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_63_1_nz_select_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    slli a1, a1, 1
+; RV32XTHEADBS-NEXT:    srli a1, a1, 1
+; RV32XTHEADBS-NEXT:    or a6, a0, a1
+; RV32XTHEADBS-NEXT:    mv a1, a3
+; RV32XTHEADBS-NEXT:    mv a0, a2
+; RV32XTHEADBS-NEXT:    bnez a6, .LBB86_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    mv a0, a4
+; RV32XTHEADBS-NEXT:    mv a1, a5
+; RV32XTHEADBS-NEXT:  .LBB86_2:
+; RV32XTHEADBS-NEXT:    ret
   %1 = and i64 %a, 9223372036854775807
   %2 = icmp ne i64 %1, 0
   %3 = select i1 %2, i64 %b, i64 %c
@@ -3198,6 +3388,17 @@ define void @bit_63_1_z_branch_i64(i64 %0) {
 ; RV32ZBS-NEXT:    ret
 ; RV32ZBS-NEXT:  .LBB115_2:
 ; RV32ZBS-NEXT:    tail bar at plt
+;
+; RV32XTHEADBS-LABEL: bit_63_1_z_branch_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    slli a1, a1, 1
+; RV32XTHEADBS-NEXT:    srli a1, a1, 1
+; RV32XTHEADBS-NEXT:    or a0, a0, a1
+; RV32XTHEADBS-NEXT:    beqz a0, .LBB115_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    ret
+; RV32XTHEADBS-NEXT:  .LBB115_2:
+; RV32XTHEADBS-NEXT:    tail bar at plt
   %2 = and i64 %0, 9223372036854775807
   %3 = icmp eq i64 %2, 0
   br i1 %3, label %4, label %5
@@ -3240,6 +3441,17 @@ define void @bit_63_1_nz_branch_i64(i64 %0) {
 ; RV32ZBS-NEXT:    tail bar at plt
 ; RV32ZBS-NEXT:  .LBB116_2:
 ; RV32ZBS-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: bit_63_1_nz_branch_i64:
+; RV32XTHEADBS:       # %bb.0:
+; RV32XTHEADBS-NEXT:    slli a1, a1, 1
+; RV32XTHEADBS-NEXT:    srli a1, a1, 1
+; RV32XTHEADBS-NEXT:    or a0, a0, a1
+; RV32XTHEADBS-NEXT:    beqz a0, .LBB116_2
+; RV32XTHEADBS-NEXT:  # %bb.1:
+; RV32XTHEADBS-NEXT:    tail bar at plt
+; RV32XTHEADBS-NEXT:  .LBB116_2:
+; RV32XTHEADBS-NEXT:    ret
   %2 = and i64 %0, 9223372036854775807
   %3 = icmp ne i64 %2, 0
   br i1 %3, label %4, label %5

diff  --git a/llvm/test/CodeGen/RISCV/rv32xtheadbs.ll b/llvm/test/CodeGen/RISCV/rv32xtheadbs.ll
new file mode 100644
index 0000000000000..1c8727668f685
--- /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=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+xtheadbs -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=RV32XTHEADBS
+
+define i32 @th_tst_i32(i32 %a) nounwind {
+; RV32I-LABEL: th_tst_i32:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a0, a0, 26
+; RV32I-NEXT:    srli a0, a0, 31
+; RV32I-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: th_tst_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 @th_tst_i64(i64 %a) nounwind {
+; RV32I-LABEL: th_tst_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: th_tst_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 @th_tst_i32_cmp(i32 signext %a) nounwind {
+; RV32I-LABEL: th_tst_i32_cmp:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a0, a0, 26
+; RV32I-NEXT:    srli a0, a0, 31
+; RV32I-NEXT:    ret
+;
+; RV32XTHEADBS-LABEL: th_tst_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 @th_tst_i64_cmp(i64 %a) nounwind {
+; RV32I-LABEL: th_tst_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: th_tst_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
index 0000000000000..f36c618af199b
--- /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=RV64I
+; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=RV64XTHEADBS
+
+define signext i32 @th_tst_i32(i32 signext %a) nounwind {
+; RV64I-LABEL: th_tst_i32:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a0, a0, 58
+; RV64I-NEXT:    srli a0, a0, 63
+; RV64I-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: th_tst_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 @the_tst_i64(i64 %a) nounwind {
+; RV64I-LABEL: the_tst_i64:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a0, a0, 58
+; RV64I-NEXT:    srli a0, a0, 63
+; RV64I-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: the_tst_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 @th_tst_i32_cmp(i32 signext %a) nounwind {
+; RV64I-LABEL: th_tst_i32_cmp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a0, a0, 58
+; RV64I-NEXT:    srli a0, a0, 63
+; RV64I-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: th_tst_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 @th_tst_i64_cmp(i64 %a) nounwind {
+; RV64I-LABEL: th_tst_i64_cmp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a0, a0, 58
+; RV64I-NEXT:    srli a0, a0, 63
+; RV64I-NEXT:    ret
+;
+; RV64XTHEADBS-LABEL: th_tst_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
index 0000000000000..4246681aee224
--- /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
index 0000000000000..7e68e2a62824a
--- /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
index 0000000000000..db9e7dc813d62
--- /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]


        


More information about the llvm-commits mailing list