diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index ae3a1c29df3976..d12fc42b2595b1 100644 --- a/clang/test/Driver/print-supported-extensions-riscv.c +++ b/clang/test/Driver/print-supported-extensions-riscv.c @@ -157,6 +157,8 @@ // CHECK-NEXT: xcvmac 1.0 'XCVmac' (CORE-V Multiply-Accumulate) // CHECK-NEXT: xcvmem 1.0 'XCVmem' (CORE-V Post-incrementing Load & Store) // CHECK-NEXT: xcvsimd 1.0 'XCVsimd' (CORE-V SIMD ALU) +// CHECK-NEXT: xmipscmove 1.0 'XMIPSCMove' (MIPS conditional move instruction(s) (ccmov)) +// CHECK-NEXT: xmipslsp 1.0 'XMIPSLSP' (MIPS optimization for hardware load-store bonding) // CHECK-NEXT: xsfcease 1.0 'XSfcease' (SiFive sf.cease Instruction) // CHECK-NEXT: xsfvcp 1.0 'XSfvcp' (SiFive Custom Vector Coprocessor Interface Instructions) // CHECK-NEXT: xsfvfnrclipxfqf 1.0 'XSfvfnrclipxfqf' (SiFive FP32-to-int8 Ranged Clip Instructions) diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst index c83fd1db0ba9b5..d8d7a30d8a285f 100644 --- a/llvm/docs/RISCVUsage.rst +++ b/llvm/docs/RISCVUsage.rst @@ -459,6 +459,12 @@ The current vendor extensions supported are: ``experimental-Xqcisls`` LLVM implements `version 0.2 of the Qualcomm uC Scaled Load Store extension specification `__ by Qualcomm. All instructions are prefixed with `qc.` as described in the specification. These instructions are only available for riscv32. +``Xmipscmove`` + LLVM implements conditional move for the `p8700 processor ` by MIPS. + +``Xmipslsp`` + LLVM implements load/store pair instructions for the `p8700 processor ` by MIPS. + Experimental C Intrinsics ========================= diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 2e86a891863fde..c51c4201ebd18c 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -877,6 +877,16 @@ struct RISCVOperand final : public MCParsedAsmOperand { VK == RISCVMCExpr::VK_RISCV_None; } + bool isUImm7Lsb000() const { + if (!isImm()) + return false; + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && isShiftedUInt<4, 3>(Imm) && + VK == RISCVMCExpr::VK_RISCV_None; + } + bool isUImm8Lsb00() const { if (!isImm()) return false; diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index 1c4f322e2104ef..3ec465810b1d11 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -681,6 +681,11 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size, "SiFive sf.cflush.d.l1 custom opcode table"); TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXSfcease, DecoderTableXSfcease32, "SiFive sf.cease custom opcode table"); + TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXMIPSLSP, DecoderTableXmipslsp32, + "MIPS mips.lsp custom opcode table"); + TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXMIPSCMove, + DecoderTableXmipscmove32, + "MIPS mips.ccmov custom opcode table"); TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXCVbitmanip, DecoderTableXCVbitmanip32, "CORE-V Bit Manipulation custom opcode table"); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h index e9abc90d69a131..2f4b569041a6f7 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -308,6 +308,7 @@ enum OperandType : unsigned { OPERAND_UIMM6_LSB0, OPERAND_UIMM7, OPERAND_UIMM7_LSB00, + OPERAND_UIMM7_LSB000, OPERAND_UIMM8_LSB00, OPERAND_UIMM8, OPERAND_UIMM8_LSB000, diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h index d7bab601d545cc..b1aee98739e852 100644 --- a/llvm/lib/Target/RISCV/RISCV.h +++ b/llvm/lib/Target/RISCV/RISCV.h @@ -84,6 +84,8 @@ void initializeRISCVMoveMergePass(PassRegistry &); FunctionPass *createRISCVPushPopOptimizationPass(); void initializeRISCVPushPopOptPass(PassRegistry &); +FunctionPass *createRISCVLoadStoreOptPass(); +void initializeRISCVLoadStoreOptPass(PassRegistry &); FunctionPass *createRISCVZacasABIFixPass(); void initializeRISCVZacasABIFixPass(PassRegistry &); diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td index 4119dd77804f1a..d1effaa81fc591 100644 --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -1228,6 +1228,21 @@ def HasVendorXCVbi : Predicate<"Subtarget->hasVendorXCVbi()">, AssemblerPredicate<(all_of FeatureVendorXCVbi), "'XCVbi' (CORE-V Immediate Branching)">; +// MIPS Extensions + +def FeatureVendorXMIPSCMove + : RISCVExtension<1, 0, "MIPS conditional move instruction(s) (ccmov)">; +def HasVendorXMIPSCMove + : Predicate<"Subtarget->hasVendorXMIPSCMove()">, + AssemblerPredicate<(all_of FeatureVendorXMIPSCMove), + "'Xmipscmove' ('mips.ccmov' instruction)">; +def UseCCMovInsn : Predicate<"Subtarget->useCCMovInsn()">; +def FeatureVendorXMIPSLSP + : RISCVExtension<1, 0, "MIPS optimization for hardware load-store bonding">; +def HasVendorXMIPSLSP + : Predicate<"Subtarget->hasVendorXMIPSLSP()">, + AssemblerPredicate<(all_of FeatureVendorXMIPSLSP), + "'Xmipslsp' (load and store pair instructions)">; // WCH / Nanjing Qinheng Microelectronics Extension(s) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 5e5bc0819a10cc..8d09e534b1858b 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -409,7 +409,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setOperationAction(ISD::ABS, MVT::i32, Custom); } - if (!Subtarget.hasVendorXTHeadCondMov()) + if (Subtarget.useCCMovInsn()) + setOperationAction(ISD::SELECT, XLenVT, Legal); + else if (!Subtarget.hasVendorXTHeadCondMov()) setOperationAction(ISD::SELECT, XLenVT, Custom); static const unsigned FPLegalNodeTypes[] = { diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index bd02880b0d7129..bb9ebedeea4f7b 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -2488,6 +2488,9 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI, case RISCVOp::OPERAND_UIMM7_LSB00: Ok = isShiftedUInt<5, 2>(Imm); break; + case RISCVOp::OPERAND_UIMM7_LSB000: + Ok = isShiftedUInt<4, 3>(Imm); + break; case RISCVOp::OPERAND_UIMM8_LSB00: Ok = isShiftedUInt<6, 2>(Imm); break; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index bb5bb6352c32a5..fec10864f95dc6 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -399,6 +399,10 @@ def ixlenimm_li_restricted : Operand { // Standalone (codegen-only) immleaf patterns. +// A 12-bit signed immediate plus one where the imm range will be -2047~2048. +def simm12_plus1 : ImmLeaf(Imm) && Imm != -2048) || Imm == 2048;}]>; + // A 6-bit constant greater than 32. def uimm6gt32 : ImmLeaf(Imm) && Imm > 32; @@ -2133,6 +2137,7 @@ include "RISCVInstrInfoSFB.td" include "RISCVInstrInfoXCV.td" include "RISCVInstrInfoXwch.td" include "RISCVInstrInfoXqci.td" +include "RISCVInstrInfoXMips.td" //===----------------------------------------------------------------------===// // Global ISel diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXMips.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXMips.td new file mode 100644 index 00000000000000..281829e99cc56c --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXMips.td @@ -0,0 +1,169 @@ +//===-- RISCVInstrInfoXMips.td -----------------------------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the vendor extensions defined by MIPS. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Operand definitions. +//===----------------------------------------------------------------------===// + +// A 7-bit unsigned immediate where the least significant three bits are zero. +def uimm7_lsb000 : RISCVOp, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<7, "Lsb000">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<7>"; + let OperandType = "OPERAND_UIMM7_LSB000"; + let MCOperandPredicate = [{ + int64_t Imm; + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isShiftedUInt<4, 3>(Imm); + }]; +} + +//===----------------------------------------------------------------------===// +// MIPS custom instruction formats +//===----------------------------------------------------------------------===// + +// Load double pair format. +class LDPFormat + : RVInst { + bits<7> imm7; + bits<5> rs1; + bits<5> rd1; + bits<5> rd2; + + let Inst{31-27} = rd2; + let Inst{26-23} = imm7{6-3}; + let Inst{22-20} = 0b000; + let Inst{19-15} = rs1; + let Inst{14-12} = 0b100; + let Inst{11-7} = rd1; + let Inst{6-0} = OPC_CUSTOM_0.Value; +} + +// Load word pair format. +class LWPFormat + : RVInst { + bits<7> imm7; + bits<5> rs1; + bits<5> rd1; + bits<5> rd2; + + let Inst{31-27} = rd2; + let Inst{26-22} = imm7{6-2}; + let Inst{21-20} = 0b01; + let Inst{19-15} = rs1; + let Inst{14-12} = 0b100; + let Inst{11-7} = rd1; + let Inst{6-0} = OPC_CUSTOM_0.Value; +} + +// Store double pair format. +class SDPFormat + : RVInst { + bits<7> imm7; + bits<5> rs3; + bits<5> rs2; + bits<5> rs1; + + let Inst{31-27} = rs3; + let Inst{26-25} = imm7{6-5}; + let Inst{24-20} = rs2; + let Inst{19-15} = rs1; + let Inst{14-12} = 0b101; + let Inst{11-10} = imm7{4-3}; + let Inst{9-7} = 0b000; + let Inst{6-0} = OPC_CUSTOM_0.Value; +} + +// Store word pair format. +class SWPFormat + : RVInst { + bits<7> imm7; + bits<5> rs3; + bits<5> rs2; + bits<5> rs1; + + let Inst{31-27} = rs3; + let Inst{26-25} = imm7{6-5}; + let Inst{24-20} = rs2; + let Inst{19-15} = rs1; + let Inst{14-12} = 0b101; + let Inst{11-9} = imm7{4-2}; + let Inst{8-7} = 0b01; + let Inst{6-0} = OPC_CUSTOM_0.Value; +} + +//===----------------------------------------------------------------------===// +// MIPS extensions +//===----------------------------------------------------------------------===// + +let Predicates = [HasVendorXMIPSCMove], hasSideEffects = 0, mayLoad = 0, mayStore = 0, + DecoderNamespace = "Xmipscmove" in { +def CCMOV : RVInstR4<0b11, 0b011, OPC_CUSTOM_0, (outs GPR:$rd), + (ins GPR:$rs1, GPR:$rs2, GPR:$rs3), + "mips.ccmov", "$rd, $rs2, $rs1, $rs3">, + Sched<[]>; +} + +let Predicates = [UseCCMovInsn] in { +def : Pat<(select (XLenVT (setne (XLenVT GPR:$rs2), (XLenVT 0))), + (XLenVT GPR:$rs1), (XLenVT GPR:$rs3)), + (CCMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; +def : Pat<(select (XLenVT (setne (XLenVT GPR:$x), (XLenVT simm12_plus1:$y))), + (XLenVT GPR:$rs1), (XLenVT GPR:$rs3)), + (CCMOV GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)), GPR:$rs3)>; +def : Pat<(select (XLenVT (setne (XLenVT GPR:$x), (XLenVT GPR:$y))), + (XLenVT GPR:$rs1), (XLenVT GPR:$rs3)), + (CCMOV GPR:$rs1, (XOR GPR:$x, GPR:$y), GPR:$rs3)>; +def : Pat<(select (XLenVT (seteq (XLenVT GPR:$rs2), (XLenVT 0))), + (XLenVT GPR:$rs3), (XLenVT GPR:$rs1)), + (CCMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; +def : Pat<(select (XLenVT (seteq (XLenVT GPR:$x), (XLenVT simm12_plus1:$y))), + (XLenVT GPR:$rs3), (XLenVT GPR:$rs1)), + (CCMOV GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)), GPR:$rs3)>; +def : Pat<(select (XLenVT (seteq (XLenVT GPR:$x), (XLenVT GPR:$y))), + (XLenVT GPR:$rs3), (XLenVT GPR:$rs1)), + (CCMOV GPR:$rs1, (XOR GPR:$x, GPR:$y), GPR:$rs3)>; +def : Pat<(select (XLenVT GPR:$rs2), (XLenVT GPR:$rs1), (XLenVT GPR:$rs3)), + (CCMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; +} + +let Predicates = [HasVendorXMIPSLSP], hasSideEffects = 0, + DecoderNamespace = "Xmipslsp" in { + +def LWP : LWPFormat<(outs GPR:$rd1, GPR:$rd2), (ins GPR:$rs1, uimm7_lsb00:$imm7), + "mips.lwp", "$rd1, $rd2, ${imm7}(${rs1})">, + Sched<[WriteLDW, WriteLDW, ReadMemBase]> { + let mayLoad = 1; + let mayStore = 0; +} +def LDP : LDPFormat<(outs GPR:$rd1, GPR:$rd2), (ins GPR:$rs1, uimm7_lsb000:$imm7), + "mips.ldp", "$rd1, $rd2, ${imm7}(${rs1})">, + Sched<[WriteLDD, WriteLDD, ReadMemBase]> { + let mayLoad = 1; + let mayStore = 0; +} +def SWP : SWPFormat<(outs), (ins GPR:$rs2, GPR:$rs3, GPR:$rs1, uimm7_lsb00:$imm7), + "mips.swp", "$rs2, $rs3, ${imm7}(${rs1})">, + Sched<[WriteSTW, ReadStoreData, ReadStoreData, ReadMemBase]> { + let mayLoad = 0; + let mayStore = 1; +} +def SDP : SDPFormat<(outs), (ins GPR:$rs2, GPR:$rs3, GPR:$rs1, uimm7_lsb000:$imm7), + "mips.sdp", "$rs2, $rs3, ${imm7}(${rs1})">, + Sched<[WriteSTD, ReadStoreData, ReadStoreData, ReadMemBase]> { + let mayLoad = 0; + let mayStore = 1; +} + +} diff --git a/llvm/lib/Target/RISCV/RISCVProcessors.td b/llvm/lib/Target/RISCV/RISCVProcessors.td index 6dfed7ddeb9f63..875b7a1e9486f8 100644 --- a/llvm/lib/Target/RISCV/RISCVProcessors.td +++ b/llvm/lib/Target/RISCV/RISCVProcessors.td @@ -116,7 +116,9 @@ def MIPS_P8700 : RISCVProcessorModel<"mips-p8700", FeatureStdExtZba, FeatureStdExtZbb, FeatureStdExtZifencei, - FeatureStdExtZicsr], + FeatureStdExtZicsr, + FeatureVendorXMIPSCMove, + FeatureVendorXMIPSLSP], [TuneMIPSP8700]>; def ROCKET_RV32 : RISCVProcessorModel<"rocket-rv32", diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp index 6e212dc58e6ddd..1b54c278820fc2 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -62,6 +62,15 @@ static cl::opt RISCVMinimumJumpTableEntries( "riscv-min-jump-table-entries", cl::Hidden, cl::desc("Set minimum number of entries to use a jump table on RISCV")); +static cl::opt + UseMIPSLoadStorePairsOpt("mips-riscv-load-store-pairs", + cl::desc("RISCV: Optimize for load-store bonding"), + cl::init(false), cl::Hidden); + +static cl::opt + UseCCMovInsn("riscv-ccmov", cl::desc("RISCV: Use 'mips.ccmov' instruction"), + cl::init(true), cl::Hidden); + void RISCVSubtarget::anchor() {} RISCVSubtarget & @@ -238,3 +247,7 @@ void RISCVSubtarget::overridePostRASchedPolicy(MachineSchedPolicy &Policy, Policy.OnlyBottomUp = false; } } + +bool RISCVSubtarget::useCCMovInsn() const { + return UseCCMovInsn && HasVendorXMIPSCMove; +} diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h index 87d508c3941737..8bec6edb324b14 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -188,6 +188,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { unsigned getXLen() const { return is64Bit() ? 64 : 32; } + bool useLoadStorePairs() const; + bool useCCMovInsn() const; unsigned getFLen() const { if (HasStdExtD) return 64; diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index f6ccbfbe217df6..dde808ad90413d 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -389,6 +389,7 @@ class RISCVPassConfig : public TargetPassConfig { DAG->addMutation(createStoreClusterDAGMutation( DAG->TII, DAG->TRI, /*ReorderWhileClustering=*/true)); } + return DAG; } diff --git a/llvm/test/CodeGen/RISCV/select-and.ll b/llvm/test/CodeGen/RISCV/select-and.ll index d305993f0e966b..f827e840f4a363 100644 --- a/llvm/test/CodeGen/RISCV/select-and.ll +++ b/llvm/test/CodeGen/RISCV/select-and.ll @@ -3,6 +3,8 @@ ; RUN: | FileCheck -check-prefix=RV32I %s ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV64I %s +; RUN: llc -mtriple=riscv64 -mattr=+xmipscmove -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I-CCMOV %s ;; There are a few different ways to lower (select (and A, B), X, Y). This test ;; ensures that we do so with as few branches as possible. @@ -27,6 +29,12 @@ define signext i32 @select_of_and(i1 zeroext %a, i1 zeroext %b, i32 signext %c, ; RV64I-NEXT: mv a0, a3 ; RV64I-NEXT: .LBB0_2: ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: select_of_and: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: and a0, a0, a1 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a2, a3 +; RV64I-CCMOV-NEXT: ret %1 = and i1 %a, %b %2 = select i1 %1, i32 %c, i32 %d ret i32 %2 @@ -69,6 +77,23 @@ define signext i32 @if_of_and(i1 zeroext %a, i1 zeroext %b) nounwind { ; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-NEXT: addi sp, sp, 16 ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: if_of_and: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: addi sp, sp, -16 +; RV64I-CCMOV-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-CCMOV-NEXT: beqz a0, .LBB1_3 +; RV64I-CCMOV-NEXT: # %bb.1: +; RV64I-CCMOV-NEXT: beqz a1, .LBB1_3 +; RV64I-CCMOV-NEXT: # %bb.2: # %if.then +; RV64I-CCMOV-NEXT: call both +; RV64I-CCMOV-NEXT: j .LBB1_4 +; RV64I-CCMOV-NEXT: .LBB1_3: # %if.else +; RV64I-CCMOV-NEXT: call neither +; RV64I-CCMOV-NEXT: .LBB1_4: # %if.end +; RV64I-CCMOV-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-CCMOV-NEXT: addi sp, sp, 16 +; RV64I-CCMOV-NEXT: ret %1 = and i1 %a, %b br i1 %1, label %if.then, label %if.else diff --git a/llvm/test/CodeGen/RISCV/select-bare.ll b/llvm/test/CodeGen/RISCV/select-bare.ll index cf8fe96742bfbd..c9e108a1ca9d05 100644 --- a/llvm/test/CodeGen/RISCV/select-bare.ll +++ b/llvm/test/CodeGen/RISCV/select-bare.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 -mattr=+xmipscmove -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I-CCMOV %s define i32 @bare_select(i1 %a, i32 %b, i32 %c) nounwind { ; RV32I-LABEL: bare_select: @@ -12,6 +14,12 @@ define i32 @bare_select(i1 %a, i32 %b, i32 %c) nounwind { ; RV32I-NEXT: mv a0, a2 ; RV32I-NEXT: .LBB0_2: ; RV32I-NEXT: ret +; +; RV64I-CCMOV-LABEL: bare_select: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: andi a0, a0, 1 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a1, a2 +; RV64I-CCMOV-NEXT: ret %1 = select i1 %a, i32 %b, i32 %c ret i32 %1 } @@ -26,6 +34,12 @@ define float @bare_select_float(i1 %a, float %b, float %c) nounwind { ; RV32I-NEXT: mv a0, a2 ; RV32I-NEXT: .LBB1_2: ; RV32I-NEXT: ret +; +; RV64I-CCMOV-LABEL: bare_select_float: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: andi a0, a0, 1 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a1, a2 +; RV64I-CCMOV-NEXT: ret %1 = select i1 %a, float %b, float %c ret float %1 } diff --git a/llvm/test/CodeGen/RISCV/select-cc.ll b/llvm/test/CodeGen/RISCV/select-cc.ll index 31e25702da8ba2..1c2a0cf007d117 100644 --- a/llvm/test/CodeGen/RISCV/select-cc.ll +++ b/llvm/test/CodeGen/RISCV/select-cc.ll @@ -3,6 +3,8 @@ ; RUN: | FileCheck -check-prefixes=RV32I %s ; RUN: llc -mtriple=riscv64 -disable-block-placement -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefixes=RV64I %s +; RUN: llc -mtriple=riscv64 -mattr=+xmipscmove -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I-CCMOV %s define signext i32 @foo(i32 signext %a, ptr %b) nounwind { ; RV32I-LABEL: foo: @@ -156,6 +158,57 @@ define signext i32 @foo(i32 signext %a, ptr %b) nounwind { ; RV64I-NEXT: mv a0, a1 ; RV64I-NEXT: .LBB0_28: ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: foo: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: lw a2, 0(a1) +; RV64I-CCMOV-NEXT: lw a3, 0(a1) +; RV64I-CCMOV-NEXT: lw a4, 0(a1) +; RV64I-CCMOV-NEXT: lw a5, 0(a1) +; RV64I-CCMOV-NEXT: xor a6, a0, a2 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a6, a2, a0 +; RV64I-CCMOV-NEXT: xor a2, a0, a3 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a2, a0, a3 +; RV64I-CCMOV-NEXT: lw a2, 0(a1) +; RV64I-CCMOV-NEXT: sltu a3, a4, a0 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a3, a0, a4 +; RV64I-CCMOV-NEXT: lw a3, 0(a1) +; RV64I-CCMOV-NEXT: sltu a4, a0, a5 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a4, a5, a0 +; RV64I-CCMOV-NEXT: lw a4, 0(a1) +; RV64I-CCMOV-NEXT: sltu a5, a0, a2 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a0, a2 +; RV64I-CCMOV-NEXT: lw a2, 0(a1) +; RV64I-CCMOV-NEXT: sltu a5, a3, a0 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a3, a0 +; RV64I-CCMOV-NEXT: lw a3, 0(a1) +; RV64I-CCMOV-NEXT: sext.w a5, a0 +; RV64I-CCMOV-NEXT: slt a5, a4, a5 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a0, a4 +; RV64I-CCMOV-NEXT: lw a4, 0(a1) +; RV64I-CCMOV-NEXT: sext.w a5, a0 +; RV64I-CCMOV-NEXT: slt a5, a5, a2 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a2, a0 +; RV64I-CCMOV-NEXT: lw a2, 0(a1) +; RV64I-CCMOV-NEXT: sext.w a5, a0 +; RV64I-CCMOV-NEXT: slt a5, a5, a3 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a0, a3 +; RV64I-CCMOV-NEXT: lw a3, 0(a1) +; RV64I-CCMOV-NEXT: sext.w a5, a0 +; RV64I-CCMOV-NEXT: slt a5, a4, a5 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a4, a0 +; RV64I-CCMOV-NEXT: lw a4, 0(a1) +; RV64I-CCMOV-NEXT: slti a5, a2, 1 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a0, a2 +; RV64I-CCMOV-NEXT: slti a5, a2, 0 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a5, a3, a0 +; RV64I-CCMOV-NEXT: lw a1, 0(a1) +; RV64I-CCMOV-NEXT: slti a3, a4, 1025 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a3, a4, a0 +; RV64I-CCMOV-NEXT: sltiu a2, a2, 2047 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a2, a1, a0 +; RV64I-CCMOV-NEXT: sext.w a0, a0 +; RV64I-CCMOV-NEXT: ret %val1 = load volatile i32, ptr %b %tst1 = icmp eq i32 %a, %val1 %val2 = select i1 %tst1, i32 %a, i32 %val1 @@ -258,6 +311,23 @@ define signext i16 @numsignbits(i16 signext %0, i16 signext %1, i16 signext %2, ; RV64I-NEXT: ld s0, 0(sp) # 8-byte Folded Reload ; RV64I-NEXT: addi sp, sp, 16 ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: numsignbits: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: addi sp, sp, -16 +; RV64I-CCMOV-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-CCMOV-NEXT: sd s0, 0(sp) # 8-byte Folded Spill +; RV64I-CCMOV-NEXT: mips.ccmov s0, a0, a2, a3 +; RV64I-CCMOV-NEXT: beqz a1, .LBB1_2 +; RV64I-CCMOV-NEXT: # %bb.1: +; RV64I-CCMOV-NEXT: mv a0, s0 +; RV64I-CCMOV-NEXT: call bar +; RV64I-CCMOV-NEXT: .LBB1_2: +; RV64I-CCMOV-NEXT: mv a0, s0 +; RV64I-CCMOV-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-CCMOV-NEXT: ld s0, 0(sp) # 8-byte Folded Reload +; RV64I-CCMOV-NEXT: addi sp, sp, 16 +; RV64I-CCMOV-NEXT: ret %5 = icmp eq i16 %0, 0 %6 = select i1 %5, i16 %3, i16 %2 %7 = icmp eq i16 %1, 0 @@ -295,6 +365,14 @@ define i32 @select_sge_int16min(i32 signext %x, i32 signext %y, i32 signext %z) ; RV64I-NEXT: .LBB2_2: ; RV64I-NEXT: mv a0, a1 ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: select_sge_int16min: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: lui a3, 1048560 +; RV64I-CCMOV-NEXT: addiw a3, a3, -1 +; RV64I-CCMOV-NEXT: slt a0, a3, a0 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a1, a2 +; RV64I-CCMOV-NEXT: ret %a = icmp sge i32 %x, -65536 %b = select i1 %a, i32 %y, i32 %z ret i32 %b @@ -331,6 +409,14 @@ define i64 @select_sge_int32min(i64 %x, i64 %y, i64 %z) { ; RV64I-NEXT: .LBB3_2: ; RV64I-NEXT: mv a0, a1 ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: select_sge_int32min: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: lui a3, 524288 +; RV64I-CCMOV-NEXT: addi a3, a3, -1 +; RV64I-CCMOV-NEXT: slt a0, a3, a0 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a1, a2 +; RV64I-CCMOV-NEXT: ret %a = icmp sge i64 %x, -2147483648 %b = select i1 %a, i64 %y, i64 %z ret i64 %b diff --git a/llvm/test/CodeGen/RISCV/select-or.ll b/llvm/test/CodeGen/RISCV/select-or.ll index 20a5ec15290cdb..338c7c06c3ab86 100644 --- a/llvm/test/CodeGen/RISCV/select-or.ll +++ b/llvm/test/CodeGen/RISCV/select-or.ll @@ -3,6 +3,8 @@ ; RUN: | FileCheck -check-prefix=RV32I %s ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV64I %s +; RUN: llc -mtriple=riscv64 -mattr=+xmipscmove -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I-CCMOV %s ;; There are a few different ways to lower (select (or A, B), X, Y). This test ;; ensures that we do so with as few branches as possible. @@ -27,6 +29,12 @@ define signext i32 @select_of_or(i1 zeroext %a, i1 zeroext %b, i32 signext %c, i ; RV64I-NEXT: mv a0, a3 ; RV64I-NEXT: .LBB0_2: ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: select_of_or: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: or a0, a0, a1 +; RV64I-CCMOV-NEXT: mips.ccmov a0, a0, a2, a3 +; RV64I-CCMOV-NEXT: ret %1 = or i1 %a, %b %2 = select i1 %1, i32 %c, i32 %d ret i32 %2 @@ -69,6 +77,23 @@ define signext i32 @if_of_or(i1 zeroext %a, i1 zeroext %b) nounwind { ; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-NEXT: addi sp, sp, 16 ; RV64I-NEXT: ret +; +; RV64I-CCMOV-LABEL: if_of_or: +; RV64I-CCMOV: # %bb.0: +; RV64I-CCMOV-NEXT: addi sp, sp, -16 +; RV64I-CCMOV-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-CCMOV-NEXT: bnez a0, .LBB1_3 +; RV64I-CCMOV-NEXT: # %bb.1: +; RV64I-CCMOV-NEXT: bnez a1, .LBB1_3 +; RV64I-CCMOV-NEXT: # %bb.2: # %if.else +; RV64I-CCMOV-NEXT: call neither +; RV64I-CCMOV-NEXT: j .LBB1_4 +; RV64I-CCMOV-NEXT: .LBB1_3: # %if.then +; RV64I-CCMOV-NEXT: call either +; RV64I-CCMOV-NEXT: .LBB1_4: # %if.end +; RV64I-CCMOV-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-CCMOV-NEXT: addi sp, sp, 16 +; RV64I-CCMOV-NEXT: ret %1 = or i1 %a, %b br i1 %1, label %if.then, label %if.else diff --git a/llvm/test/MC/RISCV/xmips-invalid.s b/llvm/test/MC/RISCV/xmips-invalid.s new file mode 100644 index 00000000000000..a1c1fd0666e0a5 --- /dev/null +++ b/llvm/test/MC/RISCV/xmips-invalid.s @@ -0,0 +1,26 @@ +# RUN: not llvm-mc -triple=riscv64 < %s 2>&1 | FileCheck %s -check-prefixes=CHECK-FEATURE +# RUN: not llvm-mc -triple=riscv64 -mattr=+xmipslsp,+xmipscmove < %s 2>&1 | FileCheck %s + +mips.ccmov x0, x1, 0x10 +# CHECK: error: invalid operand for instruction + +mips.ccmov x10 +# CHECK: error: too few operands for instruction + +mips.ccmov s0, s1, s2, s3 +# CHECK-FEATURE: error: instruction requires the following: 'Xmipscmove' ('mips.ccmov' instruction) + +mips.lwp x10, x11 +# CHECK: error: too few operands for instruction + +mips.ldp x9, 0x20 +# CHECK: error: invalid operand for instruction + +mips.lwp x11, x12, 0(x13) +# CHECK-FEATURE: error: instruction requires the following: 'Xmipslsp' (load and store pair instructions) + +mips.swp x18, x19, 8(x2) +# CHECK-FEATURE: error: instruction requires the following: 'Xmipslsp' (load and store pair instructions) + +mips.sdp 0x10, x3, 12(x4) +# CHECK: error: invalid operand for instruction diff --git a/llvm/test/MC/RISCV/xmips-valid.s b/llvm/test/MC/RISCV/xmips-valid.s new file mode 100644 index 00000000000000..ba256a823f511f --- /dev/null +++ b/llvm/test/MC/RISCV/xmips-valid.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+xmipslsp,+xmipscmove -M no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-INST,CHECK-ENC %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+xmipslsp,+xmipscmove < %s \ +# RUN: | llvm-objdump --mattr=+xmipslsp,+xmipscmove -M no-aliases -d - \ +# RUN: | FileCheck -check-prefix=CHECK-DIS %s + +# CHECK-INST: mips.ccmov s0, s1, s2, s3 +# CHECK-ENC: encoding: [0x0b,0x34,0x99,0x9e] +mips.ccmov s0, s1, s2, s3 + +# CHECK-DIS: mips.ccmov s0, s1, s2, s3 + +# CHECK-INST: mips.swp s3, s2, 0(sp) +# CHECK-ENC: encoding: [0x8b,0x50,0x31,0x91] +mips.swp s3, s2, 0(sp) + +# CHECK-DIS: mips.swp s3, s2, 0x0(sp) + +# CHECK-INST: mips.sdp s5, s6, 16(s7) +# CHECK-ENC: encoding: [0x0b,0xd8,0x5b,0xb1] +mips.sdp s5, s6, 16(s7) + +# CHECK-DIS: mips.sdp s5, s6, 0x10(s7) + +# CHECK-INST: mips.ldp s1, s2, 8(sp) +# CHECK-ENC: encoding: [0x8b,0x44,0x81,0x90] +mips.ldp s1, s2, 8(sp) + +# CHECK-DIS: mips.ldp s1, s2, 0x8(sp) + +# CHECK-INST: mips.lwp a0, a1, 20(a2) +# CHECK-ENC: encoding: [0x0b,0x45,0x56,0x59] +mips.lwp x10, x11, 20(x12) + +# CHECK-DIS: mips.lwp a0, a1, 0x14(a2) diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp index 14a60c1857f24f..0639b15656f54d 100644 --- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp +++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp @@ -1083,6 +1083,8 @@ R"(All available -march extensions for RISC-V xcvmac 1.0 xcvmem 1.0 xcvsimd 1.0 + xmipscmove 1.0 + xmipslsp 1.0 xsfcease 1.0 xsfvcp 1.0 xsfvfnrclipxfqf 1.0