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 @@ -109,6 +109,7 @@ * 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 --- 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/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -478,6 +478,13 @@ 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 --- 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 @@ -676,6 +676,8 @@ SDLoc DL(Node); MVT VT = Node->getSimpleValueType(0); + bool HasBitTest = Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs(); + switch (Opcode) { case ISD::Constant: { assert(VT == Subtarget->getXLenVT() && "Unexpected VT"); @@ -824,14 +826,15 @@ 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. + 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), @@ -953,8 +956,8 @@ bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && X.getOpcode() == ISD::SIGN_EXTEND_INREG && cast(X.getOperand(1))->getVT() == MVT::i32; - // Also Skip if we can use bexti. - Skip |= Subtarget->hasStdExtZbs() && Leading == XLen - 1; + // Also Skip if we can use bexti or th.tst. + Skip |= HasBitTest && 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 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1223,7 +1223,7 @@ // 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(AndI.getOperand(1)); if (!Mask) @@ -1246,8 +1246,11 @@ // 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(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 --- 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], 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 { @@ -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 @@ -89,6 +89,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+svinval %s -o - | FileCheck --check-prefixes=CHECK,RV64SVINVAL %s ; RUN: llc -mtriple=riscv64 -mattr=+xventanacondops %s -o - | FileCheck --check-prefixes=CHECK,RV64XVENTANACONDOPS %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadba %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADBA %s +; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADBS %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadvdot %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADVDOT %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zawrs %s -o - | FileCheck --check-prefixes=CHECK,RV64ZAWRS %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-ztso %s -o - | FileCheck --check-prefixes=CHECK,RV64ZTSO %s @@ -186,6 +187,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 --- 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; RV64ZBS-NEXT: tail bar@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@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@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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; RV32ZBS-NEXT: ret ; RV32ZBS-NEXT: .LBB115_2: ; RV32ZBS-NEXT: tail bar@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@plt %2 = and i64 %0, 9223372036854775807 %3 = icmp eq i64 %2, 0 br i1 %3, label %4, label %5 @@ -3240,6 +3441,17 @@ ; RV32ZBS-NEXT: tail bar@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@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 --- /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 --- /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 --- /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]