diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst index 5fd4fb350189c3..8242707348385f 100644 --- a/llvm/docs/RISCVUsage.rst +++ b/llvm/docs/RISCVUsage.rst @@ -185,6 +185,9 @@ The current vendor extensions supported are: ``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. +``XTheadMac`` + LLVM implements `the XTheadMac (multiply-accumulate instructions) 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 index de60ed98563e21..c0bc8e0a3299ca 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -111,6 +111,7 @@ Changes to the RISC-V Backend * Adds support for the vendor-defined XTHeadBa (address-generation) extension. * Adds support for the vendor-defined XTHeadBb (basic bit-manipulation) extension. * Adds support for the vendor-defined XTHeadBs (single-bit) extension. +* Adds support for the vendor-defined XTHeadMac (multiply-accumulate instructions) extension. Changes to the WebAssembly Backend ---------------------------------- diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp index 70095d0836719c..92ac0747fd46cf 100644 --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -112,6 +112,7 @@ static const RISCVSupportedExtension SupportedExtensions[] = { {"xtheadba", RISCVExtensionVersion{1, 0}}, {"xtheadbb", RISCVExtensionVersion{1, 0}}, {"xtheadbs", RISCVExtensionVersion{1, 0}}, + {"xtheadmac", 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 647607a6664da3..b37997634f21c5 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -492,6 +492,13 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, if (Result != MCDisassembler::Fail) return Result; } + if (STI.getFeatureBits()[RISCV::FeatureVendorXTHeadMac]) { + LLVM_DEBUG(dbgs() << "Trying XTHeadMac custom opcode table:\n"); + Result = decodeInstruction(DecoderTableTHeadMac32, 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 e6cd3341198bf9..3284d8ef4e1708 100644 --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -484,6 +484,13 @@ def HasVendorXTHeadBs : Predicate<"Subtarget->hasVendorXTHeadBs()">, AssemblerPredicate<(all_of FeatureVendorXTHeadBs), "'xtheadbs' (T-Head single-bit instructions)">; +def FeatureVendorXTHeadMac + : SubtargetFeature<"xtheadmac", "HasVendorXTHeadMac", "true", + "'xtheadmac' (T-Head Multiply-Accumulate Instructions)">; +def HasVendorXTHeadMac : Predicate<"Subtarget->hasVendorXTHeadMac()">, + AssemblerPredicate<(all_of FeatureVendorXTHeadMac), + "'xtheadmac' (T-Head Multiply-Accumulate 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 e9ef19a33296d6..cd9831ed6a2293 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -2165,15 +2165,29 @@ bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, return true; } -bool RISCVDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { +bool RISCVDAGToDAGISel::selectSExtBits(SDValue N, unsigned Bits, SDValue &Val) { if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && - cast(N.getOperand(1))->getVT() == MVT::i32) { + cast(N.getOperand(1))->getVT().getSizeInBits() == Bits) { Val = N.getOperand(0); return true; } + + auto UnwrapShlSra = [](SDValue N, unsigned ShiftAmt) { + if (N.getOpcode() != ISD::SRA || !isa(N.getOperand(1))) + return N; + + SDValue N0 = N.getOperand(0); + if (N0.getOpcode() == ISD::SHL && isa(N0.getOperand(1)) && + N.getConstantOperandVal(1) == ShiftAmt && + N0.getConstantOperandVal(1) == ShiftAmt) + return N0.getOperand(0); + + return N; + }; + MVT VT = N.getSimpleValueType(); - if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { - Val = N; + if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - Bits)) { + Val = UnwrapShlSra(N, VT.getSizeInBits() - Bits); return true; } @@ -2681,6 +2695,10 @@ bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { case RISCV::MULW: case RISCV::SLLIW: case RISCV::PACKW: + case RISCV::TH_MULAW: + case RISCV::TH_MULAH: + case RISCV::TH_MULSW: + case RISCV::TH_MULSH: // Result is already sign extended just remove the sext.w. // NOTE: We only handle the nodes that are selected with hasAllWUsers. ReplaceUses(N, N0.getNode()); diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h index c800ea9e528bb9..8195bceda95f18 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -60,7 +60,10 @@ class RISCVDAGToDAGISel : public SelectionDAGISel { return selectShiftMask(N, 32, ShAmt); } - bool selectSExti32(SDValue N, SDValue &Val); + bool selectSExtBits(SDValue N, unsigned Bits, SDValue &Val); + template bool selectSExtBits(SDValue N, SDValue &Val) { + return selectSExtBits(N, Bits, Val); + } bool selectZExtBits(SDValue N, unsigned Bits, SDValue &Val); template bool selectZExtBits(SDValue N, SDValue &Val) { return selectZExtBits(N, Bits, Val); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index 81c25373352f96..dd11ad70569688 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1195,7 +1195,8 @@ class PatGprUimmLog2XLen def assertsexti32 : PatFrag<(ops node:$src), (assertsext node:$src), [{ return cast(N->getOperand(1))->getVT().bitsLE(MVT::i32); }]>; -def sexti32 : ComplexPattern; +def sexti16 : ComplexPattern">; +def sexti32 : ComplexPattern">; def assertzexti32 : PatFrag<(ops node:$src), (assertzext node:$src), [{ return cast(N->getOperand(1))->getVT().bitsLE(MVT::i32); }]>; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td index f85af115f8770a..679eaedf706118 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td @@ -86,6 +86,17 @@ class THShiftW_ri funct7, bits<3> funct3, string opcodestr> (ins GPR:$rs1, uimm5:$shamt), opcodestr, "$rd, $rs1, $shamt">; + +let Predicates = [HasVendorXTHeadMac], DecoderNamespace = "THeadMac", + hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCommutable = 1 in +class THMulAccumulate_rr funct7, string opcodestr> + : RVInstR { + let Constraints = "$rd_wb = $rd"; +} + + //===----------------------------------------------------------------------===// // Combination of instruction classes. // Use these multiclasses to define instructions more easily. @@ -128,6 +139,21 @@ def TH_TST : RVBShift_ri<0b10001, 0b001, OPC_CUSTOM_0, "th.tst">, Sched<[WriteSingleBitImm, ReadSingleBitImm]>; } // Predicates = [HasVendorXTHeadBs] +let Predicates = [HasVendorXTHeadMac] in { +def TH_MULA : THMulAccumulate_rr<0b0010000, "th.mula">; +def TH_MULS : THMulAccumulate_rr<0b0010001, "th.muls">; +} // Predicates = [HasVendorXTHeadMac] + +let Predicates = [HasVendorXTHeadMac], IsSignExtendingOpW = 1 in { +def TH_MULAH : THMulAccumulate_rr<0b0010100, "th.mulah">; +def TH_MULSH : THMulAccumulate_rr<0b0010101, "th.mulsh">; +} // Predicates = [HasVendorXTHeadMac], IsSignExtendingOpW = 1 + +let Predicates = [HasVendorXTHeadMac, IsRV64], IsSignExtendingOpW = 1 in { +def TH_MULAW : THMulAccumulate_rr<0b0010010, "th.mulaw">; +def TH_MULSW : THMulAccumulate_rr<0b0010011, "th.mulsw">; +} // Predicates = [HasVendorXTHeadMac, IsRV64] + let Predicates = [HasVendorXTHeadVdot], Constraints = "@earlyclobber $vd", RVVConstraint = WidenV in { @@ -327,6 +353,34 @@ def : Pat<(seteq (and GPR:$rs1, SingleBitSetMask:$mask), 0), (TH_TST (XORI GPR:$rs1, -1), SingleBitSetMask:$mask)>; } // Predicates = [HasVendorXTHeadBs] +let Predicates = [HasVendorXTHeadMac] in { +def : Pat<(add GPR:$rd, (mul GPR:$rs1, GPR:$rs2)), (TH_MULA GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : Pat<(sub GPR:$rd, (mul GPR:$rs1, GPR:$rs2)), (TH_MULS GPR:$rd, GPR:$rs1, GPR:$rs2)>; +} // Predicates = [HasVendorXTHeadMac] + +let Predicates = [HasVendorXTHeadMac, IsRV64] in { +// mulaw, mulsw are available only in RV64. +def : Pat<(binop_allwusers GPR:$rd, (mul GPR:$rs1, GPR:$rs2)), + (TH_MULAW GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : Pat<(binop_allwusers GPR:$rd, (mul GPR:$rs1, GPR:$rs2)), + (TH_MULSW GPR:$rd, GPR:$rs1, GPR:$rs2)>; +// mulah, mulsh produce a sign-extended result. +def : Pat<(binop_allwusers GPR:$rd, (mul + (sexti16 GPR:$rs1), + (sexti16 GPR:$rs2))), + (TH_MULAH GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : Pat<(binop_allwusers GPR:$rd, (mul + (sexti16 GPR:$rs1), + (sexti16 GPR:$rs2))), + (TH_MULSH GPR:$rd, GPR:$rs1, GPR:$rs2)>; +} // Predicates = [HasVendorXTHeadMac, IsRV64] + +let Predicates = [HasVendorXTHeadMac, IsRV32] in { +def : Pat<(add GPR:$rd, (mul (sexti16 GPR:$rs1), (sexti16 GPR:$rs2))), + (TH_MULAH GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : Pat<(sub GPR:$rd, (mul (sexti16 GPR:$rs1), (sexti16 GPR:$rs2))), + (TH_MULSH GPR:$rd, GPR:$rs1, GPR:$rs2)>; +} // Predicates = [HasVendorXTHeadMac, IsRV32] defm PseudoTHVdotVMAQA : VPseudoVMAQA_VV_VX; defm PseudoTHVdotVMAQAU : VPseudoVMAQA_VV_VX; diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll index 68638ffa75d59f..dfdb2dd7063c72 100644 --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -41,6 +41,7 @@ ; RUN: llc -mtriple=riscv32 -mattr=+svnapot %s -o - | FileCheck --check-prefixes=CHECK,RV32SVNAPOT %s ; RUN: llc -mtriple=riscv32 -mattr=+svpbmt %s -o - | FileCheck --check-prefixes=CHECK,RV32SVPBMT %s ; RUN: llc -mtriple=riscv32 -mattr=+svinval %s -o - | FileCheck --check-prefixes=CHECK,RV32SVINVAL %s +; RUN: llc -mtriple=riscv32 -mattr=+xtheadmac %s -o - | FileCheck --check-prefixes=CHECK,RV32XTHEADMAC %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zca %s -o - | FileCheck --check-prefixes=CHECK,RV32ZCA %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zcb %s -o - | FileCheck --check-prefixes=CHECK,RV32ZCB %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zcd %s -o - | FileCheck --check-prefixes=CHECK,RV32ZCD %s @@ -91,6 +92,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+xtheadba %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADBA %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadbb %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADBB %s ; RUN: llc -mtriple=riscv64 -mattr=+xtheadbs %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADBS %s +; RUN: llc -mtriple=riscv64 -mattr=+xtheadmac %s -o - | FileCheck --check-prefixes=CHECK,RV64XTHEADMAC %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 @@ -140,6 +142,7 @@ ; RV32SVNAPOT: .attribute 5, "rv32i2p0_svnapot1p0" ; RV32SVPBMT: .attribute 5, "rv32i2p0_svpbmt1p0" ; RV32SVINVAL: .attribute 5, "rv32i2p0_svinval1p0" +; RV32XTHEADMAC: .attribute 5, "rv32i2p0_xtheadmac1p0" ; RV32ZCA: .attribute 5, "rv32i2p0_zca1p0" ; RV32ZCB: .attribute 5, "rv32i2p0_zca1p0_zcb1p0" ; RV32ZCD: .attribute 5, "rv32i2p0_zcd1p0" @@ -190,6 +193,7 @@ ; RV64XTHEADBA: .attribute 5, "rv64i2p0_xtheadba1p0" ; RV64XTHEADBB: .attribute 5, "rv64i2p0_xtheadbb1p0" ; RV64XTHEADBS: .attribute 5, "rv64i2p0_xtheadbs1p0" +; RV64XTHEADMAC: .attribute 5, "rv64i2p0_xtheadmac1p0" ; 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/xtheadmac.ll b/llvm/test/CodeGen/RISCV/xtheadmac.ll new file mode 100644 index 00000000000000..9e849f22a94ac8 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/xtheadmac.ll @@ -0,0 +1,152 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+xtheadmac -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32XTHEADMAC +; RUN: llc -mtriple=riscv64 -mattr=+xtheadmac -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64XTHEADMAC + +define i32 @mula_i32(i32 %a, i32 %b, i32 %c) { +; RV32XTHEADMAC-LABEL: mula_i32: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.mula a0, a1, a2 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mula_i32: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulaw a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i32 %b, %c + %e = add i32 %a, %d + ret i32 %e +} + +define i32 @muls_i32(i32 %a, i32 %b, i32 %c) { +; RV32XTHEADMAC-LABEL: muls_i32: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.muls a0, a1, a2 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: muls_i32: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulsw a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i32 %b, %c + %e = sub i32 %a, %d + ret i32 %e +} + +define i64 @mula_i64(i64 %a, i64 %b, i64 %c) { +; RV32XTHEADMAC-LABEL: mula_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: mulhu a6, a2, a4 +; RV32XTHEADMAC-NEXT: th.mula a6, a2, a5 +; RV32XTHEADMAC-NEXT: th.mula a6, a3, a4 +; RV32XTHEADMAC-NEXT: th.mula a2, a0, a4 +; RV32XTHEADMAC-NEXT: sltu a0, a2, a0 +; RV32XTHEADMAC-NEXT: add a0, a1, a0 +; RV32XTHEADMAC-NEXT: add a1, a0, a6 +; RV32XTHEADMAC-NEXT: mv a0, a2 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mula_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mula a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i64 %b, %c + %f = add i64 %a, %d + ret i64 %f +} + +define i64 @mulaw_i64(i32 %a, i32 %b, i32 %c) { +; RV32XTHEADMAC-LABEL: mulaw_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.mula a0, a1, a2 +; RV32XTHEADMAC-NEXT: srai a1, a0, 31 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mulaw_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulaw a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i32 %b, %c + %e = add i32 %a, %d + %f = sext i32 %e to i64 + ret i64 %f +} + +define i64 @mulah_i64(i32 %a, i16 %b, i16 %c) { +; RV32XTHEADMAC-LABEL: mulah_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.mulah a0, a1, a2 +; RV32XTHEADMAC-NEXT: srai a1, a0, 31 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mulah_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulah a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = sext i16 %b to i32 + %e = sext i16 %c to i32 + %f = mul i32 %d, %e + %g = add i32 %a, %f + %h = sext i32 %g to i64 + ret i64 %h +} + +define i64 @muls_i64(i64 %a, i64 %b, i64 %c) { +; RV32XTHEADMAC-LABEL: muls_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: mulhu a6, a2, a4 +; RV32XTHEADMAC-NEXT: th.mula a6, a2, a5 +; RV32XTHEADMAC-NEXT: th.mula a6, a3, a4 +; RV32XTHEADMAC-NEXT: mul a3, a2, a4 +; RV32XTHEADMAC-NEXT: th.muls a2, a0, a4 +; RV32XTHEADMAC-NEXT: sltu a0, a0, a3 +; RV32XTHEADMAC-NEXT: sub a1, a1, a0 +; RV32XTHEADMAC-NEXT: sub a1, a1, a6 +; RV32XTHEADMAC-NEXT: mv a0, a2 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: muls_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.muls a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i64 %b, %c + %f = sub i64 %a, %d + ret i64 %f +} + +define i64 @mulsw_i64(i32 %a, i32 %b, i32 %c) { +; RV32XTHEADMAC-LABEL: mulsw_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.muls a0, a1, a2 +; RV32XTHEADMAC-NEXT: srai a1, a0, 31 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mulsw_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulsw a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = mul i32 %b, %c + %e = sub i32 %a, %d + %f = sext i32 %e to i64 + ret i64 %f +} + +define i64 @mulsh_i64(i32 %a, i16 %b, i16 %c) { +; RV32XTHEADMAC-LABEL: mulsh_i64: +; RV32XTHEADMAC: # %bb.0: +; RV32XTHEADMAC-NEXT: th.mulsh a0, a1, a2 +; RV32XTHEADMAC-NEXT: srai a1, a0, 31 +; RV32XTHEADMAC-NEXT: ret +; +; RV64XTHEADMAC-LABEL: mulsh_i64: +; RV64XTHEADMAC: # %bb.0: +; RV64XTHEADMAC-NEXT: th.mulsh a0, a1, a2 +; RV64XTHEADMAC-NEXT: ret + %d = sext i16 %b to i32 + %e = sext i16 %c to i32 + %f = mul i32 %d, %e + %g = sub i32 %a, %f + %h = sext i32 %g to i64 + ret i64 %h +} diff --git a/llvm/test/MC/RISCV/rv32xtheadmac-invalid.s b/llvm/test/MC/RISCV/rv32xtheadmac-invalid.s new file mode 100644 index 00000000000000..1a811333576866 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32xtheadmac-invalid.s @@ -0,0 +1,4 @@ +# RUN: not llvm-mc -triple riscv32 -mattr=+xtheadmac < %s 2>&1 | FileCheck %s + +th.mulaw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}} +th.mulsw t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}} diff --git a/llvm/test/MC/RISCV/rv32xtheadmac-valid.s b/llvm/test/MC/RISCV/rv32xtheadmac-valid.s new file mode 100644 index 00000000000000..75bf8b0866f6a5 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32xtheadmac-valid.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+xtheadmac -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+xtheadmac < %s \ +# RUN: | llvm-objdump --mattr=+xtheadmac -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: th.mula a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x20] +th.mula a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulah a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x28] +th.mulah a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.muls a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x22] +th.muls a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulsh a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x2a] +th.mulsh a0, a1, a2 diff --git a/llvm/test/MC/RISCV/rv64xtheadmac-valid.s b/llvm/test/MC/RISCV/rv64xtheadmac-valid.s new file mode 100644 index 00000000000000..e7e541425308c5 --- /dev/null +++ b/llvm/test/MC/RISCV/rv64xtheadmac-valid.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+xtheadmac -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+xtheadmac < %s \ +# RUN: | llvm-objdump --mattr=+xtheadmac -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: th.mula a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x20] +th.mula a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulah a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x28] +th.mulah a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulaw a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x24] +th.mulaw a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.muls a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x22] +th.muls a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulsh a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x2a] +th.mulsh a0, a1, a2 + +# CHECK-ASM-AND-OBJ: th.mulsw a0, a1, a2 +# CHECK-ASM: encoding: [0x0b,0x95,0xc5,0x26] +th.mulsw a0, a1, a2 diff --git a/llvm/test/MC/RISCV/xtheadmac-invalid.s b/llvm/test/MC/RISCV/xtheadmac-invalid.s new file mode 100644 index 00000000000000..48bedbef013dd9 --- /dev/null +++ b/llvm/test/MC/RISCV/xtheadmac-invalid.s @@ -0,0 +1,7 @@ +# RUN: not llvm-mc -triple riscv32 -mattr=+xtheadmac < %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple riscv64 -mattr=+xtheadmac < %s 2>&1 | FileCheck %s + +th.mula t0, t1, 0(t2) # CHECK: :[[@LINE]]:18: error: invalid operand for instruction +th.muls t0, 12, t2 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction +th.mulsh t0, t1, 34 # CHECK: :[[@LINE]]:18: error: invalid operand for instruction +th.mulsw t0, -56, t2 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction