[llvm] 0cb7636 - [RISCV] Add MIPS extensions (#121394)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 27 23:04:15 PST 2025
Author: Djordje Todorovic
Date: 2025-01-28T08:04:09+01:00
New Revision: 0cb7636a462a8d4209e2b6344304eb43f02853eb
URL: https://github.com/llvm/llvm-project/commit/0cb7636a462a8d4209e2b6344304eb43f02853eb
DIFF: https://github.com/llvm/llvm-project/commit/0cb7636a462a8d4209e2b6344304eb43f02853eb.diff
LOG: [RISCV] Add MIPS extensions (#121394)
Adding two extensions for MIPS p8700 CPU:
1. cmove (conditional move)
2. lsp (load/store pair)
The official product page here:
https://mips.com/products/hardware/p8700
Added:
llvm/lib/Target/RISCV/RISCVInstrInfoXMips.td
llvm/test/MC/RISCV/xmips-invalid.s
llvm/test/MC/RISCV/xmips-valid.s
Modified:
clang/test/Driver/print-supported-extensions-riscv.c
llvm/docs/RISCVUsage.rst
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
llvm/lib/Target/RISCV/RISCV.h
llvm/lib/Target/RISCV/RISCVFeatures.td
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
llvm/lib/Target/RISCV/RISCVInstrInfo.td
llvm/lib/Target/RISCV/RISCVProcessors.td
llvm/lib/Target/RISCV/RISCVSubtarget.cpp
llvm/lib/Target/RISCV/RISCVSubtarget.h
llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
llvm/test/CodeGen/RISCV/select-and.ll
llvm/test/CodeGen/RISCV/select-bare.ll
llvm/test/CodeGen/RISCV/select-cc.ll
llvm/test/CodeGen/RISCV/select-or.ll
llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
Removed:
################################################################################
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index c72b65316ae8a9..3443ff0b69de9a 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 71927d57a8f0f9..09fb59f94e84dc 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 <https://github.com/quic/riscv-unified-db/releases/latest>`__ 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 <https://mips.com/products/hardware/p8700/>` by MIPS.
+
+``Xmipslsp``
+ LLVM implements load/store pair instructions for the `p8700 processor <https://mips.com/products/hardware/p8700/>` 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 a8f433ea91387d..f050977c55e196 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<XLenVT> {
// Standalone (codegen-only) immleaf patterns.
+// A 12-bit signed immediate plus one where the imm range will be -2047~2048.
+def simm12_plus1 : ImmLeaf<XLenVT,
+ [{return (isInt<12>(Imm) && Imm != -2048) || Imm == 2048;}]>;
+
// A 6-bit constant greater than 32.
def uimm6gt32 : ImmLeaf<XLenVT, [{
return isUInt<6>(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<XLenVT, [{return isShiftedUInt<4, 3>(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<dag outs, dag ins, string opcodestr, string argstr>
+ : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {
+ 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<dag outs, dag ins, string opcodestr, string argstr>
+ : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {
+ 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<dag outs, dag ins, string opcodestr, string argstr>
+ : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {
+ 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<dag outs, dag ins, string opcodestr, string argstr>
+ : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {
+ 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 28b13f74c29913..b5eea138732a55 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<unsigned> 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<bool>
+ UseMIPSLoadStorePairsOpt("mips-riscv-load-store-pairs",
+ cl::desc("RISCV: Optimize for load-store bonding"),
+ cl::init(false), cl::Hidden);
+
+static cl::opt<bool>
+ 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
diff erent 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
diff erent 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 aa8851e4897e26..7ebfcf915a7c5e 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
More information about the llvm-commits
mailing list