[llvm] [Mips] Fix R6 floating-point condition register handling (PR #226838)
Jiaxun Yang via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 27 14:40:04 PDT 2026
https://github.com/FlyGoat created https://github.com/llvm/llvm-project/pull/226838
Sharing a predicate between R6 floating-point selects can produce copies between incompatible register classes and crash in copyPhysReg. The condition classes model both CMP.S and CMP.D results as i32, despite the instructions writing 32-bit and 64-bit FPRs respectively.
Use ordinary FPR classes for compare results and tied select operands. Represent the legalized i32 condition with a same-width copy for CMP.S and a low-word subregister for CMP.D. Insert the condition into the low word for SEL.D, leaving the unused upper word undefined. This lets register coalescing handle shared predicates and mixed-precision users, removing the special condition classes, copy heuristics and register-flags pass.
Select BC1EQZ/BC1NEZ directly for FP comparison conditions, including their microMIPS counterparts, and support them in branch analysis. These branches read bit zero, avoiding a GPR transfer and boolean normalization. Fold normalization of known 0/-1 masks into zero/nonzero branches as well, while preserving normalization for integer users that require 0/1.
Add coverage for shared predicates, mixed precision, PHIs, spills and all nonconstant FP branch predicates across MIPS32r6, MIPS64r6 and microMIPS, including both byte orders. Update branch analysis and long-branch tests.
Fixes: #223905
Fixes: #224541
Fixes: #224542
Assisted-by: OpenAI Codex
>From 93ba89f3df5c01f8f1fc78f2150bd90ed28fd639 Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Fri, 18 Sep 2026 07:54:37 +0100
Subject: [PATCH] [Mips] Fix R6 floating-point condition register handling
Sharing a predicate between R6 floating-point selects can produce copies
between incompatible register classes and crash in copyPhysReg. The
condition classes model both CMP.S and CMP.D results as i32, despite the
instructions writing 32-bit and 64-bit FPRs respectively.
Use ordinary FPR classes for compare results and tied select operands.
Represent the legalized i32 condition with a same-width copy for CMP.S
and a low-word subregister for CMP.D. Insert the condition into the low
word for SEL.D, leaving the unused upper word undefined. This lets register
coalescing handle shared predicates and mixed-precision users, removing
the special condition classes, copy heuristics and register-flags pass.
Select BC1EQZ/BC1NEZ directly for FP comparison conditions, including their
microMIPS counterparts, and support them in branch analysis. These branches
read bit zero, avoiding a GPR transfer and boolean normalization. Fold
normalization of known 0/-1 masks into zero/nonzero branches as well, while
preserving normalization for integer users that require 0/1.
Add coverage for shared predicates, mixed precision, PHIs, spills and all
nonconstant FP branch predicates across MIPS32r6, MIPS64r6 and microMIPS,
including both byte orders. Update branch analysis and long-branch tests.
Fixes: #223905
Fixes: #224541
Fixes: #224542
Assisted-by: OpenAI Codex
---
llvm/lib/Target/Mips/CMakeLists.txt | 1 -
.../Mips/Disassembler/MipsDisassembler.cpp | 22 -
.../Target/Mips/MCTargetDesc/MipsBaseInfo.h | 10 -
.../lib/Target/Mips/MicroMips32r6InstrInfo.td | 55 ++-
llvm/lib/Target/Mips/Mips.h | 2 -
llvm/lib/Target/Mips/Mips32r6InstrInfo.td | 161 ++++---
llvm/lib/Target/Mips/MipsMTInstrInfo.td | 4 +-
llvm/lib/Target/Mips/MipsRegisterInfo.td | 17 -
llvm/lib/Target/Mips/MipsSEISelLowering.cpp | 17 -
llvm/lib/Target/Mips/MipsSEISelLowering.h | 1 -
llvm/lib/Target/Mips/MipsSEInstrInfo.cpp | 140 +-----
.../Mips/MipsSetMachineRegisterFlags.cpp | 111 -----
llvm/lib/Target/Mips/MipsTargetMachine.cpp | 2 -
llvm/test/CodeGen/Mips/analyzebranch.ll | 29 +-
llvm/test/CodeGen/Mips/fcmp.ll | 28 +-
llvm/test/CodeGen/Mips/fpbr.ll | 87 ++--
llvm/test/CodeGen/Mips/llvm-ir/select-dbl.ll | 4 +-
.../branch-limits-fp-micromipsr6.mir | 16 +-
.../longbranch/branch-limits-fp-mipsr6.mir | 16 +-
llvm/test/CodeGen/Mips/micromips-mtc-mfc.ll | 24 +-
llvm/test/CodeGen/Mips/msa/f16-llvm-ir.ll | 4 +-
llvm/test/CodeGen/Mips/r6-fp-branch.ll | 434 ++++++++++++++++++
.../CodeGen/Mips/r6-fp-condition-spill.mir | 45 ++
.../CodeGen/Mips/r6-fp-condition-subregs.ll | 217 +++++++++
llvm/test/CodeGen/Mips/select.ll | 6 +-
25 files changed, 964 insertions(+), 489 deletions(-)
delete mode 100644 llvm/lib/Target/Mips/MipsSetMachineRegisterFlags.cpp
create mode 100644 llvm/test/CodeGen/Mips/r6-fp-branch.ll
create mode 100644 llvm/test/CodeGen/Mips/r6-fp-condition-spill.mir
create mode 100644 llvm/test/CodeGen/Mips/r6-fp-condition-subregs.ll
diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt
index 918a099b68df8a..119cd34c369aa2 100644
--- a/llvm/lib/Target/Mips/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/CMakeLists.txt
@@ -60,7 +60,6 @@ add_llvm_target(MipsCodeGen
MipsSEISelLowering.cpp
MipsSERegisterInfo.cpp
MipsSelectionDAGInfo.cpp
- MipsSetMachineRegisterFlags.cpp
MipsSubtarget.cpp
MipsTargetMachine.cpp
MipsTargetObjectFile.cpp
diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
index bbd614fc644236..54c8cec0358329 100644
--- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
+++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
@@ -995,28 +995,6 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
-static DecodeStatus DecodeFGR32CCRegisterClass(MCInst &Inst, unsigned RegNo,
- uint64_t Address,
- const MCDisassembler *Decoder) {
- if (RegNo > 31)
- return MCDisassembler::Fail;
-
- MCRegister Reg = getReg(Decoder, Mips::FGR32CCRegClassID, RegNo);
- Inst.addOperand(MCOperand::createReg(Reg));
- return MCDisassembler::Success;
-}
-
-static DecodeStatus DecodeFGR64CCRegisterClass(MCInst &Inst, unsigned RegNo,
- uint64_t Address,
- const MCDisassembler *Decoder) {
- if (RegNo > 31)
- return MCDisassembler::Fail;
-
- MCRegister Reg = getReg(Decoder, Mips::FGR64CCRegClassID, RegNo);
- Inst.addOperand(MCOperand::createReg(Reg));
- return MCDisassembler::Success;
-}
-
static DecodeStatus DecodeMem(MCInst &Inst, unsigned Insn, uint64_t Address,
const MCDisassembler *Decoder) {
int Offset = SignExtend32<16>(Insn & 0xffff);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index a265331c0610e2..0fd873002981a3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -154,16 +154,6 @@ inline static MCRegister getMSARegFromFReg(MCRegister Reg) {
return MCRegister();
}
-inline static MCRegister getFloatRegFromFReg(MCRegister Reg) {
- if (Reg >= Mips::F0 && Reg <= Mips::F31)
- return Reg;
- else if (Reg >= Mips::D0_64 && Reg <= Mips::D31_64)
- return Reg - Mips::D0_64 + Mips::F0;
- else if (Reg >= Mips::W0 && Reg <= Mips::W31)
- return Reg - Mips::W0 + Mips::F0;
- return Mips::NoRegister;
-}
-
} // namespace llvm
#endif
diff --git a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
index 5487254c14ab3f..9fdda60e247baa 100644
--- a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
@@ -878,73 +878,72 @@ class CVT_S_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.l", FGR64Opnd, FGR32Opnd>,
FGR_64;
multiclass CMP_CC_MMR6<bits<6> format, string Typestr,
- RegisterOperand FGROpnd,
- RegisterOperand FGRCCOpnd> {
+ RegisterOperand FGROpnd> {
def CMP_AF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.af.", Typestr), format, FIELD_CMP_COND_AF>,
- CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.un.", Typestr), format, FIELD_CMP_COND_UN>,
- CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, FGRCCOpnd, setuo>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_EQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.eq.", Typestr), format, FIELD_CMP_COND_EQ>,
- CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, FGRCCOpnd, setoeq>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ueq.", Typestr), format, FIELD_CMP_COND_UEQ>,
- CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, FGRCCOpnd, setueq>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.lt.", Typestr), format, FIELD_CMP_COND_LT>,
- CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, FGRCCOpnd, setolt>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ult.", Typestr), format, FIELD_CMP_COND_ULT>,
- CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, FGRCCOpnd, setult>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.le.", Typestr), format, FIELD_CMP_COND_LE>,
- CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, FGRCCOpnd, setole>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ule.", Typestr), format, FIELD_CMP_COND_ULE>,
- CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, FGRCCOpnd, setule>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
let mayRaiseFPException = 1 in {
def CMP_SAF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.saf.", Typestr), format, FIELD_CMP_COND_SAF>,
- CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sun.", Typestr), format, FIELD_CMP_COND_SUN>,
- CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.seq.", Typestr), format, FIELD_CMP_COND_SEQ>,
- CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sueq.", Typestr), format, FIELD_CMP_COND_SUEQ>,
- CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.slt.", Typestr), format, FIELD_CMP_COND_SLT>,
- CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sult.", Typestr), format, FIELD_CMP_COND_SULT>,
- CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sle.", Typestr), format, FIELD_CMP_COND_SLE>,
- CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sule.", Typestr), format, FIELD_CMP_COND_SULE>,
- CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd, FGRCCOpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, HARDFLOAT,
ISA_MICROMIPS32R6;
}
}
@@ -998,8 +997,8 @@ class ROUND_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.s", FGR32Opnd,
class ROUND_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.d", FGR64Opnd,
FGR64Opnd>;
-class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd, FGR32CCOpnd>;
-class SEL_D_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd, FGR64CCOpnd>;
+class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>;
+class SEL_D_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd>;
class SELEQZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>;
class SELEQZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>;
@@ -1185,7 +1184,7 @@ class BNEZC_MMR6_DESC
MMR6Arch<"bnezc">;
class BRANCH_COP1_MMR6_DESC_BASE<string opstr> :
- InstSE<(outs), (ins FGR64Opnd:$rt, brtarget_mm:$offset),
+ InstSE<(outs), (ins FGR32Opnd:$rt, brtarget_mm:$offset),
!strconcat(opstr, "\t$rt, $offset"), [], FrmI>,
HARDFLOAT, BRANCH_DESC_BASE {
list<Register> Defs = [AT];
@@ -1423,8 +1422,8 @@ let mayRaiseFPException = 1 in {
}
}
-defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd, FGR32CCOpnd>;
-defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd, FGR64CCOpnd>;
+defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd>;
+defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd>;
let mayRaiseFPException = 1 in {
def FLOOR_L_S_MMR6 : StdMMR6Rel, FLOOR_L_S_MMR6_ENC, FLOOR_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
@@ -1690,6 +1689,16 @@ defm : SelectInt_Pats<i32, OR_MM, XORI_MMR6, SLTi_MM, SLTiu_MM, SELEQZ_MMR6,
defm S_MMR6 : Cmp_Pats<f32>, ISA_MICROMIPS32R6;
defm D_MMR6 : Cmp_Pats<f64>, ISA_MICROMIPS32R6;
+defm : FPBrcondPats<BC1EQZC_MMR6, BC1NEZC_MMR6>, ISA_MICROMIPS32R6;
+
+def : MipsPat<(brcond (and i32_zero_or_negative_one:$cond, 1), bb:$dst),
+ (BNEZC_MMR6 GPR32:$cond, bb:$dst)>, ISA_MICROMIPS32R6;
+def : MipsPat<(brcond (and (not i32_zero_or_negative_one:$cond), 1), bb:$dst),
+ (BEQZC_MMR6 GPR32:$cond, bb:$dst)>, ISA_MICROMIPS32R6;
+
+def : SEL_FP_PAT<FGR32Opnd, SEL_S_MMR6>, ISA_MICROMIPS32R6;
+def : SEL_FP_PAT<FGR64Opnd, SEL_D_MMR6>, ISA_MICROMIPS32R6;
+
def : MipsPat<(f32 fpimm0), (MTC1_MMR6 ZERO)>, ISA_MICROMIPS32R6;
def : MipsPat<(f32 fpimm0neg), (FNEG_S_MMR6(MTC1_MMR6 ZERO))>,
ISA_MICROMIPS32R6;
diff --git a/llvm/lib/Target/Mips/Mips.h b/llvm/lib/Target/Mips/Mips.h
index da06d33f15223b..053bc3d0e4a410 100644
--- a/llvm/lib/Target/Mips/Mips.h
+++ b/llvm/lib/Target/Mips/Mips.h
@@ -50,7 +50,6 @@ FunctionPass *createMipsExpandPseudoPass();
FunctionPass *createMipsPreLegalizeCombiner();
FunctionPass *createMipsPostLegalizeCombiner(bool IsOptNone);
FunctionPass *createMipsMulMulBugPass();
-FunctionPass *createMipsSetMachineRegisterFlagsPass();
InstructionSelector *
createMipsInstructionSelector(const MipsTargetMachine &, const MipsSubtarget &,
@@ -64,7 +63,6 @@ void initializeMipsDelaySlotFillerPass(PassRegistry &);
void initializeMipsMulMulBugFixPass(PassRegistry &);
void initializeMipsPostLegalizerCombinerPass(PassRegistry &);
void initializeMipsPreLegalizerCombinerPass(PassRegistry &);
-void initializeMipsSetMachineRegisterFlagsPass(PassRegistry &);
} // namespace llvm
#endif
diff --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
index 5283a5da43eee8..2f7039985697a5 100644
--- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -12,19 +12,6 @@
include "Mips32r6InstrFormats.td"
-//===----------------------------------------------------------------------===//
-//
-// Mips profiles and nodes
-//
-//===----------------------------------------------------------------------===//
-
-def SDT_MipsFSelect : SDTypeProfile<1, 3, [SDTCisFP<1>,
- SDTCisSameAs<0,2>,
- SDTCisSameAs<2,3>]>;
-
-// Floating point select
-def MipsFSelect : SDNode<"MipsISD::FSELECT", SDT_MipsFSelect>;
-
//===----------------------------------------------------------------------===//
//
// Mips Operands
@@ -211,100 +198,90 @@ class SIGRIE_ENC : SIGRIE_FM;
//===----------------------------------------------------------------------===//
class CMP_CONDN_DESC_BASE<string CondStr, string Typestr,
- RegisterOperand FGROpnd,
- RegisterOperand FGRCCOpnd,
- SDPatternOperator Op = null_frag> {
- dag OutOperandList = (outs FGRCCOpnd:$fd);
+ RegisterOperand FGROpnd> : NeverHasSideEffects {
+ dag OutOperandList = (outs FGROpnd:$fd);
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft");
- list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))];
bit isCTI = 1;
}
multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr,
- RegisterOperand FGROpnd,
- RegisterOperand FGRCCOpnd>{
+ RegisterOperand FGROpnd>{
let AdditionalPredicates = [NotInMicroMips] in {
def CMP_F_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_AF>,
- CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.af.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_UN_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UN>,
- CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, FGRCCOpnd, setuo>,
+ CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.un.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_EQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_EQ>,
- CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, FGRCCOpnd,
- setoeq>,
+ CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.eq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_UEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_UEQ>,
- CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, FGRCCOpnd,
- setueq>,
+ CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.ueq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_LT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>,
- CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, FGRCCOpnd,
- setolt>,
+ CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.lt.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_ULT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_ULT>,
- CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, FGRCCOpnd,
- setult>,
+ CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.ult.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_LE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>,
- CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, FGRCCOpnd,
- setole>,
+ CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.le.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_ULE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_ULE>,
- CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, FGRCCOpnd,
- setule>,
+ CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.ule.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
let mayRaiseFPException = 1 in {
def CMP_SAF_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SAF>,
- CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.saf.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SUN_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SUN>,
- CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.sun.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SEQ>,
- CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.seq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SUEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SUEQ>,
- CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.sueq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SLT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SLT>,
- CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.slt.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SULT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SULT>,
- CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.sult.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SLE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SLE>,
- CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.sle.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SULE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SULE>,
- CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd, FGRCCOpnd>,
+ CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>,
MipsR6Arch<!strconcat("cmp.sule.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
}
@@ -454,8 +431,7 @@ class BEQZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21, GPR32Opnd>;
class BNEZC_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21, GPR32Opnd>;
class COP1_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE {
- dag InOperandList = (ins FGR64Opnd:$ft, brtarget:$offset);
- dag OutOperandList = (outs);
+ dag InOperandList = (ins FGR32Opnd:$ft, brtarget:$offset);
string AsmString = instr_asm;
bit hasDelaySlot = 1;
}
@@ -588,20 +564,16 @@ class MUL_R6_DESC : MUL_R6_DESC_BASE<"mul", GPR32Opnd, mul>;
class MULU_DESC : MUL_R6_DESC_BASE<"mulu", GPR32Opnd>;
class COP1_SEL_DESC_BASE<string instr_asm,
- RegisterOperand FGROpnd,
- RegisterOperand FGRCCOpnd> {
+ RegisterOperand FGROpnd> : NeverHasSideEffects {
dag OutOperandList = (outs FGROpnd:$fd);
- dag InOperandList = (ins FGRCCOpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft);
+ dag InOperandList = (ins FGROpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft");
- list<dag> Pattern = [(set FGROpnd:$fd, (select FGRCCOpnd:$fd_in,
- FGROpnd:$ft,
- FGROpnd:$fs))];
string Constraints = "$fd_in = $fd";
}
-class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd, FGR64CCOpnd>,
+class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd>,
MipsR6Arch<"sel.d">;
-class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd, FGR32CCOpnd>,
+class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>,
MipsR6Arch<"sel.s">;
class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
@@ -859,8 +831,8 @@ let AdditionalPredicates = [NotInMicroMips] in {
}
def CLO_R6 : R6MMR6Rel, CLO_R6_ENC, CLO_R6_DESC, ISA_MIPS32R6;
def CLZ_R6 : R6MMR6Rel, CLZ_R6_ENC, CLZ_R6_DESC, ISA_MIPS32R6;
-defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd, FGR32CCOpnd>;
-defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd, FGR64CCOpnd>;
+defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd>;
+defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd>;
let AdditionalPredicates = [NotInMicroMips] in {
def DIV : R6MMR6Rel, DIV_ENC, DIV_DESC, ISA_MIPS32R6;
def DIVU : R6MMR6Rel, DIVU_ENC, DIVU_DESC, ISA_MIPS32R6;
@@ -984,17 +956,39 @@ def : MipsInstAlias<"lapc $rd, $imm",
//
//===----------------------------------------------------------------------===//
-// comparisons supported via another comparison
+// CMP.S and CMP.D write 32-bit and 64-bit masks to FPRs, respectively, while
+// SETCC has an i32 result. Keep the full-width result in the ordinary FPR class
+// and expose its low word as i32. These copies can coalesce with FPR users.
+class CmpPat<ValueType VT, dag Pattern, dag Result>
+ : MipsPat<(i32 Pattern), !if(!eq(VT, f64),
+ (EXTRACT_SUBREG Result, sub_lo),
+ (COPY_TO_REGCLASS Result, FGR32))>, HARDFLOAT;
+
multiclass Cmp_Pats<ValueType VT> {
-def : MipsPat<(seteq VT:$lhs, VT:$rhs),
+def : CmpPat<VT, (setuo VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_UN_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setoeq VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_EQ_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setueq VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_UEQ_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setolt VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_LT_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setult VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_ULT_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setole VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_LE_"#NAME) VT:$lhs, VT:$rhs)>;
+def : CmpPat<VT, (setule VT:$lhs, VT:$rhs),
+ (!cast<Instruction>("CMP_ULE_"#NAME) VT:$lhs, VT:$rhs)>;
+
+def : CmpPat<VT, (seteq VT:$lhs, VT:$rhs),
(!cast<Instruction>("CMP_EQ_"#NAME) VT:$lhs, VT:$rhs)>;
-def : MipsPat<(setgt VT:$lhs, VT:$rhs),
+def : CmpPat<VT, (setgt VT:$lhs, VT:$rhs),
(!cast<Instruction>("CMP_LE_"#NAME) VT:$rhs, VT:$lhs)>;
-def : MipsPat<(setge VT:$lhs, VT:$rhs),
+def : CmpPat<VT, (setge VT:$lhs, VT:$rhs),
(!cast<Instruction>("CMP_LT_"#NAME) VT:$rhs, VT:$lhs)>;
-def : MipsPat<(setlt VT:$lhs, VT:$rhs),
+def : CmpPat<VT, (setlt VT:$lhs, VT:$rhs),
(!cast<Instruction>("CMP_LT_"#NAME) VT:$lhs, VT:$rhs)>;
-def : MipsPat<(setle VT:$lhs, VT:$rhs),
+def : CmpPat<VT, (setle VT:$lhs, VT:$rhs),
(!cast<Instruction>("CMP_LE_"#NAME) VT:$lhs, VT:$rhs)>;
}
@@ -1003,6 +997,38 @@ let AdditionalPredicates = [NotInMicroMips] in {
defm D : Cmp_Pats<f64>, ISA_MIPS32R6;
}
+// BRCOND normalizes FP comparison masks to 0/1 during type legalization.
+// For a value known to be 0 or -1, a zero/nonzero test needs no normalization.
+def i32_zero_or_negative_one : PatLeaf<(i32 GPR32:$src), [{
+ return CurDAG->ComputeNumSignBits(SDValue(N, 0)) == 32;
+}]>;
+
+// Match the condition without folding SETCC into the branch, so other users
+// can share the compare. Its i32 result is the low word of CMP.S or CMP.D.
+def r6_fp_condition : PatLeaf<(i32 GPR32:$src), [{
+ return N->getOpcode() == ISD::SETCC &&
+ N->getOperand(0).getValueType().isFloatingPoint();
+}]>;
+
+// BC1EQZ/BC1NEZ read only bit zero, so FGR32 covers both compare widths.
+// Prefer these patterns to GPR branches to avoid transferring the condition.
+multiclass FPBrcondPats<Instruction EQZ, Instruction NEZ> {
+ let AddedComplexity = 1 in {
+ def : MipsPat<(brcond (and r6_fp_condition:$cond, 1), bb:$dst),
+ (NEZ (COPY_TO_REGCLASS i32:$cond, FGR32), bb:$dst)>, HARDFLOAT;
+ def : MipsPat<(brcond (and (not r6_fp_condition:$cond), 1), bb:$dst),
+ (EQZ (COPY_TO_REGCLASS i32:$cond, FGR32), bb:$dst)>, HARDFLOAT;
+ }
+}
+
+let AdditionalPredicates = [NotInMicroMips] in {
+ defm : FPBrcondPats<BC1EQZ, BC1NEZ>, ISA_MIPS32R6;
+ def : MipsPat<(brcond (and i32_zero_or_negative_one:$cond, 1), bb:$dst),
+ (BNE GPR32:$cond, ZERO, bb:$dst)>, ISA_MIPS32R6;
+ def : MipsPat<(brcond (and (not i32_zero_or_negative_one:$cond), 1), bb:$dst),
+ (BEQ GPR32:$cond, ZERO, bb:$dst)>, ISA_MIPS32R6;
+}
+
// i32 selects
multiclass SelectInt_Pats<ValueType RC, Instruction OROp, Instruction XORiOp,
Instruction SLTiOp, Instruction SLTiuOp,
@@ -1056,6 +1082,21 @@ def : MipsPat<(select i32:$cond, immz, i32:$f),
ISA_MIPS32R6;
}
+// SEL reads bit zero of its tied input, which must have the result's register
+// class. Copy the i32 condition to FGR32 for SEL.S, or insert it into the low
+// word of FGR64 for SEL.D; the unused upper word can remain undefined.
+class SEL_FP_PAT<RegisterOperand RC, Instruction Inst>
+ : MipsPat<(select i32:$cond, RC:$t, RC:$f),
+ (Inst !if(!eq(RC, FGR64Opnd),
+ (INSERT_SUBREG (f64 (IMPLICIT_DEF)), i32:$cond, sub_lo),
+ (COPY_TO_REGCLASS i32:$cond, FGR32)),
+ RC:$f, RC:$t)>, HARDFLOAT;
+
+let AdditionalPredicates = [NotInMicroMips] in {
+ def : SEL_FP_PAT<FGR32Opnd, SEL_S>, ISA_MIPS32R6;
+ def : SEL_FP_PAT<FGR64Opnd, SEL_D>, ISA_MIPS32R6;
+}
+
// llvm.fmin/fmax operations.
let AdditionalPredicates = [NotInMicroMips] in {
def : MipsPat<(fmaxnum_ieee f32:$lhs, f32:$rhs),
diff --git a/llvm/lib/Target/Mips/MipsMTInstrInfo.td b/llvm/lib/Target/Mips/MipsMTInstrInfo.td
index 4cb609df0639be..77a008d7b5035e 100644
--- a/llvm/lib/Target/Mips/MipsMTInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsMTInstrInfo.td
@@ -135,7 +135,7 @@ def MFTC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32Opnd:$ft),
def MFTHC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32Opnd:$ft),
"mfthc1 $rt, $ft">, ASE_MT;
-def CFTC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32CCOpnd:$ft),
+def CFTC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32Opnd:$ft),
"cftc1 $rt, $ft">, ASE_MT;
@@ -164,7 +164,7 @@ def MTTC1 : MipsAsmPseudoInst<(outs FGR32Opnd:$ft), (ins GPR32Opnd:$rt),
def MTTHC1 : MipsAsmPseudoInst<(outs FGR32Opnd:$ft), (ins GPR32Opnd:$rt),
"mtthc1 $rt, $ft">, ASE_MT;
-def CTTC1 : MipsAsmPseudoInst<(outs FGR32CCOpnd:$ft), (ins GPR32Opnd:$rt),
+def CTTC1 : MipsAsmPseudoInst<(outs FGR32Opnd:$ft), (ins GPR32Opnd:$rt),
"cttc1 $rt, $ft">, ASE_MT;
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.td b/llvm/lib/Target/Mips/MipsRegisterInfo.td
index a1c775060786db..9eb748183aa196 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -450,11 +450,6 @@ def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>,
def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>,
Unallocatable;
-// MIPS32r6/MIPS64r6 store FPU condition codes in normal FGR registers.
-// This class allows us to represent this in codegen patterns.
-def FGR32CC : RegisterClass<"Mips", [i32], 32, (sequence "F%u", 0, 31)>;
-def FGR64CC : RegisterClass<"Mips", [i32, f32, f64], 64, (sequence "D%u_64", 0, 31)>;
-
def MSA128B: RegisterClass<"Mips", [v16i8], 128,
(sequence "W%u", 0, 31)>;
def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128,
@@ -723,18 +718,6 @@ def StrictlyFGR32Opnd : RegisterOperand<FGR32> {
let ParserMatchClass = StrictlyFGR32AsmOperand;
}
-def FGR64CCOpnd : RegisterOperand<FGR64CC> {
- // The assembler doesn't use register classes so we can re-use
- // FGR64AsmOperand.
- let ParserMatchClass = FGR64AsmOperand;
-}
-
-def FGR32CCOpnd : RegisterOperand<FGR32CC> {
- // The assembler doesn't use register classes so we can re-use
- // FGR32AsmOperand.
- let ParserMatchClass = FGR32AsmOperand;
-}
-
def FCCRegsOpnd : RegisterOperand<FCC> {
let ParserMatchClass = FCCRegsAsmOperand;
}
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 474e956e9ca02e..4b616328f7d46a 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -471,21 +471,6 @@ addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) {
}
}
-SDValue MipsSETargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
- if(!Subtarget.hasMips32r6())
- return MipsTargetLowering::LowerOperation(Op, DAG);
-
- EVT ResTy = Op->getValueType(0);
- SDLoc DL(Op);
-
- // Although MTC1_D64 takes an i32 and writes an f64, the upper 32 bits of the
- // floating point register are undefined. Not really an issue as sel.d, which
- // is produced from an FSELECT node, only looks at bit 0.
- SDValue Tmp = DAG.getNode(MipsISD::MTC1_D64, DL, MVT::f64, Op->getOperand(0));
- return DAG.getNode(MipsISD::FSELECT, DL, ResTy, Tmp, Op->getOperand(1),
- Op->getOperand(2));
-}
-
// Lower FP16_TO_FP (the soft-promote-half representation of an f16 -> f32/f64
// conversion).
SDValue MipsSETargetLowering::lowerFP16_TO_FP(SDValue Op,
@@ -607,8 +592,6 @@ SDValue MipsSETargetLowering::LowerOperation(SDValue Op,
case ISD::EXTRACT_VECTOR_ELT: return lowerEXTRACT_VECTOR_ELT(Op, DAG);
case ISD::BUILD_VECTOR: return lowerBUILD_VECTOR(Op, DAG);
case ISD::VECTOR_SHUFFLE: return lowerVECTOR_SHUFFLE(Op, DAG);
- case ISD::SELECT:
- return lowerSELECT(Op, DAG);
case ISD::FP16_TO_FP:
case ISD::STRICT_FP16_TO_FP:
return lowerFP16_TO_FP(Op, DAG);
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.h b/llvm/lib/Target/Mips/MipsSEISelLowering.h
index b4620aa7549171..5949cbd672b80b 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.h
@@ -92,7 +92,6 @@ using TargetRegisterClass = MCRegisterClass;
/// Lower VECTOR_SHUFFLE into one of a number of instructions
/// depending on the indices in the shuffle.
SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const;
- SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFP16_TO_FP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
index 60febefb085482..394bb6871a72b0 100644
--- a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
@@ -73,70 +73,6 @@ Register MipsSEInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
return 0;
}
-static std::pair<bool, bool> readsWritesFloatRegister(MachineInstr &MI,
- Register Reg) {
- bool Reads = false;
- bool Writes = false;
- int Idx = -1;
- Register RegF32 = getFloatRegFromFReg(Reg);
- assert(RegF32 != Mips::NoRegister && "Reg is not a Float Register");
- for (llvm::MachineOperand &MO : MI.operands()) {
- Idx++;
- if (!MO.isReg())
- continue;
- Register MORegF32 = getFloatRegFromFReg(MO.getReg());
- if (MORegF32 == Mips::NoRegister)
- continue;
- if (MORegF32 == RegF32) {
- if (Idx == 0)
- Writes = true;
- else
- Reads = true;
- }
- }
- return std::make_pair(Reads, Writes);
-}
-
-static bool isWritedByFCMP(MachineBasicBlock::iterator I, Register Reg) {
- MachineBasicBlock *MBB = I->getParent();
- if (I == MBB->begin())
- return false;
- MachineBasicBlock::reverse_iterator RevI = std::prev(I)->getReverseIterator();
- for (; RevI != MBB->rend(); RevI++) {
- bool Reads, Writes;
- std::tie(Reads, Writes) = readsWritesFloatRegister(*RevI, Reg);
- unsigned Opcode = RevI->getOpcode();
- if (Writes) {
- if (Opcode >= Mips::CMP_AF_D_MMR6 && Opcode <= Mips::CMP_UN_S_MMR6)
- return true;
- return false;
- }
- }
- return false;
-}
-
-static bool isOnlyReadsBySEL(MachineBasicBlock::iterator I, Register Reg) {
- MachineBasicBlock *MBB = I->getParent();
- MachineBasicBlock::iterator NextI = std::next(I);
- bool MaybeOK = false;
- for (; NextI != MBB->end(); NextI++) {
- bool Reads, Writes;
- std::tie(Reads, Writes) = readsWritesFloatRegister(*NextI, Reg);
- unsigned Opcode = NextI->getOpcode();
- if (Reads) {
- if (Opcode < Mips::SEL_D || Opcode > Mips::SEL_S_MMR6)
- return false;
- else if (I->getOperand(1).isKill())
- return true;
- else
- MaybeOK = true;
- }
- if (Writes)
- return MaybeOK;
- }
- return false;
-}
-
void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, Register DestReg,
@@ -171,10 +107,6 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
return;
} else if (Mips::MSACtrlRegClass.contains(SrcReg)) {
Opc = Mips::CFCMSA;
- } else if (Mips::FGR64RegClass.contains(SrcReg) &&
- (I->getFlag(MachineInstr::MIFlag::NoSWrap) ||
- isWritedByFCMP(I, SrcReg))) {
- Opc = Mips::MFC1_D64;
}
}
else if (Mips::GPR32RegClass.contains(SrcReg)) { // Copy from CPU Reg.
@@ -200,9 +132,6 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
.addReg(DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
return;
- } else if (Mips::FGR64RegClass.contains(DestReg) &&
- isOnlyReadsBySEL(I, DestReg)) {
- Opc = Mips::MTC1_D64;
}
}
else if (Mips::FGR32RegClass.contains(DestReg, SrcReg))
@@ -233,31 +162,6 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
Opc = Mips::MOVE_V;
}
- // FCMP + FSEL for MIPSr6 may emit
- // $d0_64 = COPY killed renamable $f0
- if (Opc == 0 && Mips::FGR32RegClass.contains(SrcReg) &&
- Mips::FGR64RegClass.contains(DestReg) && I != MBB.begin()) {
- // Who produces SrcReg? If SrcReg is produced by CMP_*, then it's OK.
- // Who uses DestReg? If DestReg is only used by SEL_*, then it's OK.
- if (isWritedByFCMP(I, SrcReg) || isOnlyReadsBySEL(I, DestReg)) {
- Opc = Mips::FMOV_D64;
- unsigned DestRegOff = DestReg.id() - Mips::D0_64;
- unsigned SrcRegOff = SrcReg.id() - Mips::F0;
- if (SrcRegOff == DestRegOff && SrcRegOff <= 31)
- return;
- }
- } else if (Opc == 0 && Mips::FGR32RegClass.contains(DestReg) &&
- Mips::FGR64RegClass.contains(SrcReg) && I != MBB.begin()) {
- // Who produces SrcReg? If SrcReg is produced by CMP_*, then it's OK.
- // Who uses DestReg? If DestReg is only used by SEL_*, then it's OK.
- if (isWritedByFCMP(I, SrcReg) || isOnlyReadsBySEL(I, DestReg)) {
- Opc = Mips::FMOV_D32;
- unsigned DestRegOff = DestReg.id() - Mips::F0;
- unsigned SrcRegOff = SrcReg.id() - Mips::D0_64;
- if (SrcRegOff == DestRegOff && SrcRegOff <= 31)
- return;
- }
- }
assert(Opc && "Cannot copy registers");
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc));
@@ -722,30 +626,34 @@ unsigned MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
}
unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
- return (Opc == Mips::BEQ || Opc == Mips::BEQ_MM || Opc == Mips::BNE ||
- Opc == Mips::BNE_MM || Opc == Mips::BGTZ || Opc == Mips::BGEZ ||
- Opc == Mips::BLTZ || Opc == Mips::BLEZ || Opc == Mips::BEQ64 ||
- Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || Opc == Mips::BGEZ64 ||
- Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || Opc == Mips::BC1T ||
- Opc == Mips::BC1F || Opc == Mips::B || Opc == Mips::J ||
- Opc == Mips::J_MM || Opc == Mips::B_MM || Opc == Mips::BEQZC_MM ||
- Opc == Mips::BNEZC_MM || Opc == Mips::BEQC || Opc == Mips::BNEC ||
- Opc == Mips::BLTC || Opc == Mips::BGEC || Opc == Mips::BLTUC ||
- Opc == Mips::BGEUC || Opc == Mips::BGTZC || Opc == Mips::BLEZC ||
- Opc == Mips::BGEZC || Opc == Mips::BLTZC || Opc == Mips::BEQZC ||
- Opc == Mips::BNEZC || Opc == Mips::BEQZC64 || Opc == Mips::BNEZC64 ||
+ return (Opc == Mips::BEQ || Opc == Mips::BEQ_MM || Opc == Mips::BNE ||
+ Opc == Mips::BNE_MM || Opc == Mips::BGTZ || Opc == Mips::BGEZ ||
+ Opc == Mips::BLTZ || Opc == Mips::BLEZ || Opc == Mips::BEQ64 ||
+ Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || Opc == Mips::BGEZ64 ||
+ Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || Opc == Mips::BC1T ||
+ Opc == Mips::BC1F || Opc == Mips::B || Opc == Mips::J ||
+ Opc == Mips::J_MM || Opc == Mips::B_MM || Opc == Mips::BEQZC_MM ||
+ Opc == Mips::BNEZC_MM || Opc == Mips::BEQC || Opc == Mips::BNEC ||
+ Opc == Mips::BLTC || Opc == Mips::BGEC || Opc == Mips::BLTUC ||
+ Opc == Mips::BGEUC || Opc == Mips::BGTZC || Opc == Mips::BLEZC ||
+ Opc == Mips::BGEZC || Opc == Mips::BLTZC || Opc == Mips::BEQZC ||
+ Opc == Mips::BNEZC || Opc == Mips::BEQZC64 || Opc == Mips::BNEZC64 ||
Opc == Mips::BEQC64 || Opc == Mips::BNEC64 || Opc == Mips::BGEC64 ||
Opc == Mips::BGEUC64 || Opc == Mips::BLTC64 || Opc == Mips::BLTUC64 ||
Opc == Mips::BGTZC64 || Opc == Mips::BGEZC64 ||
Opc == Mips::BLTZC64 || Opc == Mips::BLEZC64 || Opc == Mips::BC ||
- Opc == Mips::BBIT0 || Opc == Mips::BBIT1 || Opc == Mips::BBIT032 ||
- Opc == Mips::BBIT132 || Opc == Mips::BC_MMR6 ||
- Opc == Mips::BEQC_MMR6 || Opc == Mips::BNEC_MMR6 ||
- Opc == Mips::BLTC_MMR6 || Opc == Mips::BGEC_MMR6 ||
- Opc == Mips::BLTUC_MMR6 || Opc == Mips::BGEUC_MMR6 ||
- Opc == Mips::BGTZC_MMR6 || Opc == Mips::BLEZC_MMR6 ||
- Opc == Mips::BGEZC_MMR6 || Opc == Mips::BLTZC_MMR6 ||
- Opc == Mips::BEQZC_MMR6 || Opc == Mips::BNEZC_MMR6) ? Opc : 0;
+ Opc == Mips::BC1EQZ || Opc == Mips::BC1NEZ || Opc == Mips::BBIT0 ||
+ Opc == Mips::BBIT1 || Opc == Mips::BBIT032 || Opc == Mips::BBIT132 ||
+ Opc == Mips::BC_MMR6 || Opc == Mips::BEQC_MMR6 ||
+ Opc == Mips::BNEC_MMR6 || Opc == Mips::BLTC_MMR6 ||
+ Opc == Mips::BGEC_MMR6 || Opc == Mips::BLTUC_MMR6 ||
+ Opc == Mips::BGEUC_MMR6 || Opc == Mips::BGTZC_MMR6 ||
+ Opc == Mips::BLEZC_MMR6 || Opc == Mips::BGEZC_MMR6 ||
+ Opc == Mips::BLTZC_MMR6 || Opc == Mips::BEQZC_MMR6 ||
+ Opc == Mips::BNEZC_MMR6 || Opc == Mips::BC1EQZC_MMR6 ||
+ Opc == Mips::BC1NEZC_MMR6)
+ ? Opc
+ : 0;
}
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Mips/MipsSetMachineRegisterFlags.cpp b/llvm/lib/Target/Mips/MipsSetMachineRegisterFlags.cpp
deleted file mode 100644
index 38e54d4ca1d808..00000000000000
--- a/llvm/lib/Target/Mips/MipsSetMachineRegisterFlags.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-//===- MipsSetMachineRegisterFlags.cpp - Set Machine Register Flags -------===//
-//
-// 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 pass sets machine register flags for MIPS backend.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Mips.h"
-#include "MipsInstrInfo.h"
-#include "MipsSubtarget.h"
-#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/Support/Debug.h"
-
-#define DEBUG_TYPE "mips-set-machine-register-flags"
-
-using namespace llvm;
-
-namespace {
-
-class MipsSetMachineRegisterFlags : public MachineFunctionPass {
-public:
- MipsSetMachineRegisterFlags() : MachineFunctionPass(ID) {}
-
- StringRef getPassName() const override {
- return "Mips Set Machine Register Flags";
- }
-
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- static char ID;
-
-private:
- bool processBasicBlock(MachineBasicBlock &MBB, const MipsInstrInfo &MipsII,
- const MachineRegisterInfo &RegInfo);
-};
-
-} // namespace
-
-INITIALIZE_PASS(MipsSetMachineRegisterFlags, DEBUG_TYPE,
- "Mips Set Machine Register Flags", false, false)
-
-char MipsSetMachineRegisterFlags::ID = 0;
-
-bool MipsSetMachineRegisterFlags::runOnMachineFunction(MachineFunction &MF) {
- const MipsInstrInfo &MipsII =
- *static_cast<const MipsInstrInfo *>(MF.getSubtarget().getInstrInfo());
- const MachineRegisterInfo &RegInfo = MF.getRegInfo();
-
- bool Modified = false;
-
- for (auto &MBB : MF)
- Modified |= processBasicBlock(MBB, MipsII, RegInfo);
-
- return Modified;
-}
-
-bool MipsSetMachineRegisterFlags::processBasicBlock(
- MachineBasicBlock &MBB, const MipsInstrInfo &MipsII,
- const MachineRegisterInfo &RegInfo) {
- bool Modified = false;
-
- // Iterate through the instructions in the basic block
- for (MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end(); MII != E;
- ++MII) {
- MachineInstr &MI = *MII;
-
- LLVM_DEBUG(dbgs() << "Processing instruction: " << MI << "\n");
-
- unsigned Opcode = MI.getOpcode();
- if (Opcode >= Mips::CMP_AF_D_MMR6 && Opcode <= Mips::CMP_UN_S_MMR6) {
- MachineOperand &DestOperand = MI.getOperand(0);
- assert(DestOperand.isReg());
- Register Dest = DestOperand.getReg();
- if (Dest.isVirtual() &&
- RegInfo.getRegClassOrNull(Dest) == &Mips::FGR64CCRegClass) {
- MI.setFlag(MachineInstr::MIFlag::NoSWrap);
- }
- } else if (Opcode == Mips::COPY) {
- MachineOperand &SrcOperand = MI.getOperand(1);
- assert(SrcOperand.isReg());
- Register Src = SrcOperand.getReg();
- if (Src.isVirtual() &&
- RegInfo.getRegClassOrNull(Src) == &Mips::FGR64CCRegClass) {
- MI.setFlag(MachineInstr::MIFlag::NoSWrap);
- }
- } else if (Opcode == Mips::INSERT_SUBREG) {
- MachineOperand &SrcOperand = MI.getOperand(2);
- assert(SrcOperand.isReg());
- Register Src = SrcOperand.getReg();
- if (Src.isVirtual() &&
- RegInfo.getRegClassOrNull(Src) == &Mips::FGR64CCRegClass) {
- MI.setFlag(MachineInstr::MIFlag::NoSWrap);
- }
- }
- }
-
- return Modified;
-}
-
-FunctionPass *llvm::createMipsSetMachineRegisterFlagsPass() {
- return new MipsSetMachineRegisterFlags();
-}
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 0aa14d6171d5e7..bbd46e84097f5e 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -74,7 +74,6 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTarget() {
initializeMipsPostLegalizerCombinerPass(*PR);
initializeMipsMulMulBugFixPass(*PR);
initializeMipsDAGToDAGISelLegacyPass(*PR);
- initializeMipsSetMachineRegisterFlagsPass(*PR);
}
static std::unique_ptr<TargetLoweringObjectFile>
@@ -237,7 +236,6 @@ bool MipsPassConfig::addInstSelector() {
void MipsPassConfig::addPreRegAlloc() {
addPass(createMipsOptimizePICCallPass());
- addPass(createMipsSetMachineRegisterFlagsPass());
}
TargetTransformInfo
diff --git a/llvm/test/CodeGen/Mips/analyzebranch.ll b/llvm/test/CodeGen/Mips/analyzebranch.ll
index 099d49522d89f1..054a59fa18c865 100644
--- a/llvm/test/CodeGen/Mips/analyzebranch.ll
+++ b/llvm/test/CodeGen/Mips/analyzebranch.ll
@@ -55,16 +55,14 @@ define double @foo(double %a, double %b) nounwind readnone {
; MIPS32r6-NEXT: mtc1 $zero, $f1
; MIPS32r6-NEXT: mthc1 $zero, $f1
; MIPS32r6-NEXT: cmp.lt.d $f1, $f1, $f12
-; MIPS32r6-NEXT: mfc1 $1, $f1
-; MIPS32r6-NEXT: andi $1, $1, 1
-; MIPS32r6-NEXT: bnezc $1, $BB0_2
+; MIPS32r6-NEXT: bc1nez $f1, $BB0_2
+; MIPS32r6-NEXT: nop
; MIPS32r6-NEXT: # %bb.1: # %if.else
; MIPS32r6-NEXT: mtc1 $zero, $f0
; MIPS32r6-NEXT: mthc1 $zero, $f0
; MIPS32r6-NEXT: cmp.ule.d $f1, $f14, $f0
-; MIPS32r6-NEXT: mfc1 $1, $f1
-; MIPS32r6-NEXT: andi $1, $1, 1
-; MIPS32r6-NEXT: bnezc $1, $BB0_3
+; MIPS32r6-NEXT: bc1nez $f1, $BB0_3
+; MIPS32r6-NEXT: nop
; MIPS32r6-NEXT: $BB0_2: # %if.end6
; MIPS32r6-NEXT: sub.d $f0, $f14, $f0
; MIPS32r6-NEXT: add.d $f0, $f0, $f0
@@ -127,18 +125,15 @@ define double @foo(double %a, double %b) nounwind readnone {
;
; MIPS64R6-LABEL: foo:
; MIPS64R6: # %bb.0: # %entry
-; MIPS64R6-NEXT: mov.d $f0, $f12
; MIPS64R6-NEXT: dmtc1 $zero, $f1
; MIPS64R6-NEXT: cmp.lt.d $f1, $f1, $f12
-; MIPS64R6-NEXT: mfc1 $1, $f1
-; MIPS64R6-NEXT: andi $1, $1, 1
-; MIPS64R6-NEXT: bnezc $1, .LBB0_2
+; MIPS64R6-NEXT: bc1nez $f1, .LBB0_2
+; MIPS64R6-NEXT: mov.d $f0, $f12
; MIPS64R6-NEXT: # %bb.1: # %if.else
; MIPS64R6-NEXT: dmtc1 $zero, $f0
; MIPS64R6-NEXT: cmp.ule.d $f1, $f13, $f0
-; MIPS64R6-NEXT: mfc1 $1, $f1
-; MIPS64R6-NEXT: andi $1, $1, 1
-; MIPS64R6-NEXT: bnezc $1, .LBB0_3
+; MIPS64R6-NEXT: bc1nez $f1, .LBB0_3
+; MIPS64R6-NEXT: nop
; MIPS64R6-NEXT: .LBB0_2: # %if.end6
; MIPS64R6-NEXT: sub.d $f0, $f13, $f0
; MIPS64R6-NEXT: add.d $f0, $f0, $f0
@@ -206,9 +201,7 @@ define void @f1(float %f) nounwind {
; MIPS32r6-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill
; MIPS32r6-NEXT: mtc1 $zero, $f0
; MIPS32r6-NEXT: cmp.eq.s $f0, $f12, $f0
-; MIPS32r6-NEXT: mfc1 $1, $f0
-; MIPS32r6-NEXT: andi $1, $1, 1
-; MIPS32r6-NEXT: beqzc $1, $BB1_2
+; MIPS32r6-NEXT: bc1eqz $f0, $BB1_2
; MIPS32r6-NEXT: nop
; MIPS32r6-NEXT: # %bb.1: # %if.end
; MIPS32r6-NEXT: jal f2
@@ -280,9 +273,7 @@ define void @f1(float %f) nounwind {
; MIPS64R6-NEXT: sd $ra, 8($sp) # 8-byte Folded Spill
; MIPS64R6-NEXT: mtc1 $zero, $f0
; MIPS64R6-NEXT: cmp.eq.s $f0, $f12, $f0
-; MIPS64R6-NEXT: mfc1 $1, $f0
-; MIPS64R6-NEXT: andi $1, $1, 1
-; MIPS64R6-NEXT: beqzc $1, .LBB1_2
+; MIPS64R6-NEXT: bc1eqz $f0, .LBB1_2
; MIPS64R6-NEXT: nop
; MIPS64R6-NEXT: # %bb.1: # %if.end
; MIPS64R6-NEXT: jal f2
diff --git a/llvm/test/CodeGen/Mips/fcmp.ll b/llvm/test/CodeGen/Mips/fcmp.ll
index dc90083833c699..722b2e5b9e248b 100644
--- a/llvm/test/CodeGen/Mips/fcmp.ll
+++ b/llvm/test/CodeGen/Mips/fcmp.ll
@@ -1091,10 +1091,7 @@ entry:
; 32-CMP-DAG: add.s $[[T0:f[0-9]+]], $f14, $f12
; 32-CMP-DAG: lwc1 $[[T1:f[0-9]+]], %lo($CPI32_0)(
; 32-CMP-DAG: cmp.le.s $[[T2:f[0-9]+]], $[[T0]], $[[T1]]
-; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
-; FIXME: This instruction is redundant.
-; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 32-CMP-DAG: bnezc $[[T4]],
+; 32-CMP-DAG: bc1nez $[[T2]],
; 64-C-DAG: add.s $[[T0:f[0-9]+]], $f13, $f12
; 64-C-DAG: lwc1 $[[T1:f[0-9]+]], %lo(.LCPI32_0)(
@@ -1104,10 +1101,7 @@ entry:
; 64-CMP-DAG: add.s $[[T0:f[0-9]+]], $f13, $f12
; 64-CMP-DAG: lwc1 $[[T1:f[0-9]+]], %lo(.LCPI32_0)(
; 64-CMP-DAG: cmp.le.s $[[T2:f[0-9]+]], $[[T0]], $[[T1]]
-; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
-; FIXME: This instruction is redundant.
-; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 64-CMP-DAG: bnezc $[[T4]],
+; 64-CMP-DAG: bc1nez $[[T2]],
; MM32R3-DAG: add.s $[[T0:f[0-9]+]], $f14, $f12
; MM32R3-DAG: lui $[[T1:[0-9]+]], %hi($CPI32_0)
@@ -1119,9 +1113,7 @@ entry:
; MM32R6-DAG: lui $[[T1:[0-9]+]], %hi($CPI32_0)
; MM32R6-DAG: lwc1 $[[T2:f[0-9]+]], %lo($CPI32_0)($[[T1]])
; MM32R6-DAG: cmp.le.s $[[T3:f[0-9]+]], $[[T0]], $[[T2]]
-; MM32R6-DAG: mfc1 $[[T4:[0-9]+]], $[[T3:f[0-9]+]]
-; MM32R6-DAG: andi16 $[[T5:[0-9]+]], $[[T4]], 1
-; MM32R6-DAG: bnezc $[[T5]],
+; MM32R6-DAG: bc1nezc $[[T3]],
%add = fadd fast float %at, %angle
%cmp = fcmp ogt float %add, 1.000000e+00
@@ -1149,10 +1141,7 @@ entry:
; 32-CMP-DAG: add.d $[[T0:f[0-9]+]], $f14, $f12
; 32-CMP-DAG: ldc1 $[[T1:f[0-9]+]], %lo($CPI33_0)(
; 32-CMP-DAG: cmp.le.d $[[T2:f[0-9]+]], $[[T0]], $[[T1]]
-; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
-; FIXME: This instruction is redundant.
-; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 32-CMP-DAG: bnezc $[[T4]],
+; 32-CMP-DAG: bc1nez $[[T2]],
; 64-C-DAG: add.d $[[T0:f[0-9]+]], $f13, $f12
; 64-C-DAG: ldc1 $[[T1:f[0-9]+]], %lo(.LCPI33_0)(
@@ -1162,10 +1151,7 @@ entry:
; 64-CMP-DAG: add.d $[[T0:f[0-9]+]], $f13, $f12
; 64-CMP-DAG: ldc1 $[[T1:f[0-9]+]], %lo(.LCPI33_0)(
; 64-CMP-DAG: cmp.le.d $[[T2:f[0-9]+]], $[[T0]], $[[T1]]
-; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
-; FIXME: This instruction is redundant.
-; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 64-CMP-DAG: bnezc $[[T4]],
+; 64-CMP-DAG: bc1nez $[[T2]],
; MM32R3-DAG: add.d $[[T0:f[0-9]+]], $f14, $f12
; MM32R3-DAG: lui $[[T1:[0-9]+]], %hi($CPI33_0)
@@ -1177,9 +1163,7 @@ entry:
; MM32R6-DAG: lui $[[T1:[0-9]+]], %hi($CPI33_0)
; MM32R6-DAG: ldc1 $[[T2:f[0-9]+]], %lo($CPI33_0)($[[T1]])
; MM32R6-DAG: cmp.le.d $[[T3:f[0-9]+]], $[[T0]], $[[T2]]
-; MM32R6-DAG: mfc1 $[[T4:[0-9]+]], $[[T3]]
-; MM32R6-DAG: andi16 $[[T5:[0-9]+]], $[[T4]], 1
-; MM32R6-DAG: bnezc $[[T5]],
+; MM32R6-DAG: bc1nezc $[[T3]],
%add = fadd fast double %at, %angle
%cmp = fcmp ogt double %add, 1.000000e+00
diff --git a/llvm/test/CodeGen/Mips/fpbr.ll b/llvm/test/CodeGen/Mips/fpbr.ll
index bb24d59ec3e3a0..8f74add43d59f6 100644
--- a/llvm/test/CodeGen/Mips/fpbr.ll
+++ b/llvm/test/CodeGen/Mips/fpbr.ll
@@ -1,9 +1,9 @@
; RUN: llc < %s -mtriple=mipsel-elf -mcpu=mips32 -relocation-model=pic | FileCheck %s -check-prefixes=ALL,32-FCC
; RUN: llc < %s -mtriple=mipsel-elf -mcpu=mips32r2 -relocation-model=pic | FileCheck %s -check-prefixes=ALL,32-FCC
-; RUN: llc < %s -mtriple=mipsel-elf -mcpu=mips32r6 -relocation-model=pic | FileCheck %s -check-prefixes=ALL,GPR,32-GPR
+; RUN: llc < %s -mtriple=mipsel-elf -mcpu=mips32r6 -relocation-model=pic | FileCheck %s -check-prefixes=ALL,R6,32-R6
; RUN: llc < %s -mtriple=mips64el-elf -mcpu=mips64 | FileCheck %s -check-prefixes=ALL,64-FCC
; RUN: llc < %s -mtriple=mips64el-elf -mcpu=mips64r2 | FileCheck %s -check-prefixes=ALL,64-FCC
-; RUN: llc < %s -mtriple=mips64el-elf -mcpu=mips64r6 | FileCheck %s -check-prefixes=ALL,GPR,64-GPR
+; RUN: llc < %s -mtriple=mips64el-elf -mcpu=mips64r6 | FileCheck %s -check-prefixes=ALL,R6,64-R6
define void @func0(float %f2, float %f3) nounwind {
entry:
@@ -14,13 +14,13 @@ entry:
; 64-FCC: c.eq.s $f12, $f13
; 64-FCC: bc1f .LBB0_2
-; 32-GPR: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $f14
-; 64-GPR: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $f13
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; FIXME: We ought to be able to transform not+bnez -> beqz
-; GPR: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: bnez $[[GPRCC]], $BB0_2
-; 64-GPR: bnezc $[[GPRCC]], .LBB0_2
+; 32-R6: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $f14
+; 64-R6: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $f13
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1eqz $[[FGRCC]], $BB0_2
+; 64-R6: bc1eqz $[[FGRCC]], .LBB0_2
%cmp = fcmp oeq float %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -50,12 +50,13 @@ entry:
; 64-FCC: c.olt.s $f12, $f13
; 64-FCC: bc1f .LBB1_2
-; 32-GPR: cmp.ule.s $[[FGRCC:f[0-9]+]], $f14, $f12
-; 64-GPR: cmp.ule.s $[[FGRCC:f[0-9]+]], $f13, $f12
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: bnez $[[GPRCC]], $BB1_2
-; 64-GPR: bnezc $[[GPRCC]], .LBB1_2
+; 32-R6: cmp.ule.s $[[FGRCC:f[0-9]+]], $f14, $f12
+; 64-R6: cmp.ule.s $[[FGRCC:f[0-9]+]], $f13, $f12
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1nez $[[FGRCC]], $BB1_2
+; 64-R6: bc1nez $[[FGRCC]], .LBB1_2
%cmp = fcmp olt float %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -81,12 +82,13 @@ entry:
; 64-FCC: c.ole.s $f12, $f13
; 64-FCC: bc1t .LBB2_2
-; 32-GPR: cmp.ult.s $[[FGRCC:f[0-9]+]], $f14, $f12
-; 64-GPR: cmp.ult.s $[[FGRCC:f[0-9]+]], $f13, $f12
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: beqz $[[GPRCC]], $BB2_2
-; 64-GPR: beqzc $[[GPRCC]], .LBB2_2
+; 32-R6: cmp.ult.s $[[FGRCC:f[0-9]+]], $f14, $f12
+; 64-R6: cmp.ult.s $[[FGRCC:f[0-9]+]], $f13, $f12
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1eqz $[[FGRCC]], $BB2_2
+; 64-R6: bc1eqz $[[FGRCC]], .LBB2_2
%cmp = fcmp ugt float %f2, %f3
br i1 %cmp, label %if.else, label %if.then
@@ -112,13 +114,14 @@ entry:
; 64-FCC: c.eq.d $f12, $f13
; 64-FCC: bc1f .LBB3_2
-; 32-GPR: cmp.eq.d $[[FGRCC:f[0-9]+]], $f12, $f14
-; 64-GPR: cmp.eq.d $[[FGRCC:f[0-9]+]], $f12, $f13
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; FIXME: We ought to be able to transform not+bnez -> beqz
-; GPR: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: bnezc $[[GPRCC]], $BB3_2
-; 64-GPR: bnezc $[[GPRCC]], .LBB3_2
+; 32-R6: cmp.eq.d $[[FGRCC:f[0-9]+]], $f12, $f14
+; 64-R6: cmp.eq.d $[[FGRCC:f[0-9]+]], $f12, $f13
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1eqz $[[FGRCC]], $BB3_2
+; 32-R6-NEXT: addu $gp, $2, $25
+; 64-R6: bc1eqz $[[FGRCC]], .LBB3_2
%cmp = fcmp oeq double %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -144,12 +147,14 @@ entry:
; 64-FCC: c.olt.d $f12, $f13
; 64-FCC: bc1f .LBB4_2
-; 32-GPR: cmp.ule.d $[[FGRCC:f[0-9]+]], $f14, $f12
-; 64-GPR: cmp.ule.d $[[FGRCC:f[0-9]+]], $f13, $f12
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: bnezc $[[GPRCC]], $BB4_2
-; 64-GPR: bnezc $[[GPRCC]], .LBB4_2
+; 32-R6: cmp.ule.d $[[FGRCC:f[0-9]+]], $f14, $f12
+; 64-R6: cmp.ule.d $[[FGRCC:f[0-9]+]], $f13, $f12
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1nez $[[FGRCC]], $BB4_2
+; 32-R6-NEXT: addu $gp, $2, $25
+; 64-R6: bc1nez $[[FGRCC]], .LBB4_2
%cmp = fcmp olt double %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -175,12 +180,14 @@ entry:
; 64-FCC: c.ole.d $f12, $f13
; 64-FCC: bc1t .LBB5_2
-; 32-GPR: cmp.ult.d $[[FGRCC:f[0-9]+]], $f14, $f12
-; 64-GPR: cmp.ult.d $[[FGRCC:f[0-9]+]], $f13, $f12
-; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
-; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; 32-GPR: beqzc $[[GPRCC]], $BB5_2
-; 64-GPR: beqzc $[[GPRCC]], .LBB5_2
+; 32-R6: cmp.ult.d $[[FGRCC:f[0-9]+]], $f14, $f12
+; 64-R6: cmp.ult.d $[[FGRCC:f[0-9]+]], $f13, $f12
+; R6-NOT: mfc1
+; R6-NOT: not
+; R6-NOT: andi
+; 32-R6: bc1eqz $[[FGRCC]], $BB5_2
+; 32-R6-NEXT: addu $gp, $2, $25
+; 64-R6: bc1eqz $[[FGRCC]], .LBB5_2
%cmp = fcmp ugt double %f2, %f3
br i1 %cmp, label %if.else, label %if.then
diff --git a/llvm/test/CodeGen/Mips/llvm-ir/select-dbl.ll b/llvm/test/CodeGen/Mips/llvm-ir/select-dbl.ll
index 4f56ed2932a0de..475f489840731b 100644
--- a/llvm/test/CodeGen/Mips/llvm-ir/select-dbl.ll
+++ b/llvm/test/CodeGen/Mips/llvm-ir/select-dbl.ll
@@ -72,8 +72,8 @@ define double @tst_select_i1_double(i1 signext %s, double %x, double %y) {
; 32R6: # %bb.0: # %entry
; 32R6-NEXT: mtc1 $7, $f1
; 32R6-NEXT: mthc1 $6, $f1
-; 32R6-NEXT: ldc1 $f2, 16($sp)
; 32R6-NEXT: mtc1 $4, $f0
+; 32R6-NEXT: ldc1 $f2, 16($sp)
; 32R6-NEXT: jr $ra
; 32R6-NEXT: sel.d $f0, $f2, $f1
;
@@ -130,8 +130,8 @@ define double @tst_select_i1_double(i1 signext %s, double %x, double %y) {
; MM32R6: # %bb.0: # %entry
; MM32R6-NEXT: mtc1 $7, $f1
; MM32R6-NEXT: mthc1 $6, $f1
-; MM32R6-NEXT: ldc1 $f2, 16($sp)
; MM32R6-NEXT: mtc1 $4, $f0
+; MM32R6-NEXT: ldc1 $f2, 16($sp)
; MM32R6-NEXT: sel.d $f0, $f2, $f1
; MM32R6-NEXT: jrc $ra
;
diff --git a/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-micromipsr6.mir b/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-micromipsr6.mir
index 21afed21d029e2..8de343f7f38594 100644
--- a/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-micromipsr6.mir
+++ b/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-micromipsr6.mir
@@ -1,6 +1,6 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MM
-# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
+# RUN: llc -verify-machineinstrs -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MM
+# RUN: llc -verify-machineinstrs -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
# Test the long branch expansion of various branches
@@ -72,7 +72,7 @@ body: |
; MM: bb.0.entry:
; MM: successors: %bb.2(0x50000000), %bb.1(0x30000000)
; MM: $d0_64 = CMP_EQ_D_MMR6 killed $d12_64, killed $d14_64
- ; MM: BC1EQZC_MMR6 $d0_64, %bb.2, implicit-def $at
+ ; MM: BC1EQZC_MMR6 $f0, %bb.2, implicit-def $at
; MM: bb.1.entry:
; MM: successors: %bb.3(0x80000000)
; MM: BC_MMR6 %bb.3
@@ -87,7 +87,7 @@ body: |
; PIC: bb.0.entry:
; PIC: successors: %bb.3(0x50000000), %bb.1(0x30000000)
; PIC: $d0_64 = CMP_EQ_D_MMR6 killed $d12_64, killed $d14_64
- ; PIC: BC1EQZC_MMR6 $d0_64, %bb.3, implicit-def $at
+ ; PIC: BC1EQZC_MMR6 $f0, %bb.3, implicit-def $at
; PIC: bb.1.entry:
; PIC: successors: %bb.2(0x80000000)
; PIC: $sp = ADDiu $sp, -8
@@ -113,7 +113,7 @@ body: |
liveins: $d12_64, $d14_64
$d0_64 = CMP_EQ_D_MMR6 killed $d12_64, killed $d14_64
- BC1NEZC_MMR6 killed $d0_64, %bb.2, implicit-def $at
+ BC1NEZC_MMR6 killed $f0, %bb.2, implicit-def $at
bb.1.if.then:
INLINEASM &".space 810680", 1, 12, implicit-def dead early-clobber $at
@@ -164,7 +164,7 @@ body: |
; MM: bb.0.entry:
; MM: successors: %bb.2(0x30000000), %bb.1(0x50000000)
; MM: $d0_64 = CMP_UEQ_D_MMR6 killed $d12_64, killed $d14_64
- ; MM: BC1NEZC_MMR6 $d0_64, %bb.2, implicit-def $at
+ ; MM: BC1NEZC_MMR6 $f0, %bb.2, implicit-def $at
; MM: bb.1.entry:
; MM: successors: %bb.3(0x80000000)
; MM: BC_MMR6 %bb.3
@@ -179,7 +179,7 @@ body: |
; PIC: bb.0.entry:
; PIC: successors: %bb.3(0x30000000), %bb.1(0x50000000)
; PIC: $d0_64 = CMP_UEQ_D_MMR6 killed $d12_64, killed $d14_64
- ; PIC: BC1NEZC_MMR6 $d0_64, %bb.3, implicit-def $at
+ ; PIC: BC1NEZC_MMR6 $f0, %bb.3, implicit-def $at
; PIC: bb.1.entry:
; PIC: successors: %bb.2(0x80000000)
; PIC: $sp = ADDiu $sp, -8
@@ -205,7 +205,7 @@ body: |
liveins: $d12_64, $d14_64
$d0_64 = CMP_UEQ_D_MMR6 killed $d12_64, killed $d14_64
- BC1EQZC_MMR6 killed $d0_64, %bb.2, implicit-def $at
+ BC1EQZC_MMR6 killed $f0, %bb.2, implicit-def $at
bb.1.if.then:
INLINEASM &".space 810680", 1, 12, implicit-def dead early-clobber $at
diff --git a/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-mipsr6.mir b/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-mipsr6.mir
index 9ee5f20597fd42..b759c59a5c1541 100644
--- a/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-mipsr6.mir
+++ b/llvm/test/CodeGen/Mips/longbranch/branch-limits-fp-mipsr6.mir
@@ -1,6 +1,6 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=R6
-# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
+# RUN: llc -verify-machineinstrs -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=R6
+# RUN: llc -verify-machineinstrs -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
# Test the long branch expansion of various branches
@@ -73,7 +73,7 @@ body: |
; R6: bb.0.entry:
; R6: successors: %bb.2(0x50000000), %bb.1(0x30000000)
; R6: $d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- ; R6: BC1NEZ $d0_64, %bb.2 {
+ ; R6: BC1NEZ $f0, %bb.2 {
; R6: $zero = SLL $zero, 0
; R6: }
; R6: bb.1.entry:
@@ -92,7 +92,7 @@ body: |
; PIC: bb.0.entry:
; PIC: successors: %bb.3(0x50000000), %bb.1(0x30000000)
; PIC: $d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- ; PIC: BC1NEZ $d0_64, %bb.3 {
+ ; PIC: BC1NEZ $f0, %bb.3 {
; PIC: $zero = SLL $zero, 0
; PIC: }
; PIC: bb.1.entry:
@@ -122,7 +122,7 @@ body: |
liveins: $d12_64, $d14_64
$d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- BC1EQZ killed $d0_64, %bb.2, implicit-def $at
+ BC1EQZ killed $f0, %bb.2, implicit-def $at
bb.1.if.then:
INLINEASM &".space 310680", 1, 12, implicit-def dead early-clobber $at
@@ -173,7 +173,7 @@ body: |
; R6: bb.0.entry:
; R6: successors: %bb.2(0x50000000), %bb.1(0x30000000)
; R6: $d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- ; R6: BC1EQZ $d0_64, %bb.2 {
+ ; R6: BC1EQZ $f0, %bb.2 {
; R6: $zero = SLL $zero, 0
; R6: }
; R6: bb.1.entry:
@@ -192,7 +192,7 @@ body: |
; PIC: bb.0.entry:
; PIC: successors: %bb.3(0x50000000), %bb.1(0x30000000)
; PIC: $d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- ; PIC: BC1EQZ $d0_64, %bb.3 {
+ ; PIC: BC1EQZ $f0, %bb.3 {
; PIC: $zero = SLL $zero, 0
; PIC: }
; PIC: bb.1.entry:
@@ -222,7 +222,7 @@ body: |
liveins: $d12_64, $d14_64
$d0_64 = CMP_EQ_D killed $d12_64, killed $d14_64
- BC1NEZ killed $d0_64, %bb.2, implicit-def $at
+ BC1NEZ killed $f0, %bb.2, implicit-def $at
bb.1.if.then:
INLINEASM &".space 310680", 1, 12, implicit-def dead early-clobber $at
diff --git a/llvm/test/CodeGen/Mips/micromips-mtc-mfc.ll b/llvm/test/CodeGen/Mips/micromips-mtc-mfc.ll
index cf954ee7edb94f..fe5111466d49d6 100644
--- a/llvm/test/CodeGen/Mips/micromips-mtc-mfc.ll
+++ b/llvm/test/CodeGen/Mips/micromips-mtc-mfc.ll
@@ -27,8 +27,6 @@ define double @foo(double %a, double %b) {
; MM6-NEXT: mtc1 $zero, $f1 # encoding: [0x54,0x01,0x28,0x3b]
; MM6-NEXT: mthc1 $zero, $f1 # encoding: [0x54,0x01,0x38,0x3b]
; MM6-NEXT: cmp.ule.d $f1, $f12, $f1 # encoding: [0x54,0x2c,0x09,0xd5]
-; MM6-NEXT: mfc1 $2, $f1 # encoding: [0x44,0x02,0x08,0x00]
-; MM6-NEXT: andi16 $2, $2, 1 # encoding: [0x2d,0x21]
; MM6-NEXT: jrc $ra # encoding: [0x45,0xbf]
entry:
%cmp = fcmp ogt double %a, 0.000000e+00
@@ -63,3 +61,25 @@ entry:
%r = select i1 %z, double %x, double %y
ret double %r
}
+
+; Keep the predicate live as an integer so the MFC1 encoding remains covered
+; even when the redundant branch in foo is eliminated.
+define i32 @compare_result(double %a, double %b) {
+; MM2-LABEL: compare_result:
+; MM2: # %bb.0:
+; MM2-NEXT: li16 $2, 1 # encoding: [0xed,0x01]
+; MM2-NEXT: li16 $3, 0 # encoding: [0xed,0x80]
+; MM2-NEXT: c.olt.d $f12, $f14 # encoding: [0x55,0xcc,0x05,0x3c]
+; MM2-NEXT: jr $ra # encoding: [0x00,0x1f,0x0f,0x3c]
+; MM2-NEXT: movf $2, $3, $fcc0 # encoding: [0x54,0x43,0x01,0x7b]
+;
+; MM6-LABEL: compare_result:
+; MM6: # %bb.0:
+; MM6-NEXT: cmp.lt.d $f0, $f12, $f14 # encoding: [0x55,0xcc,0x01,0x15]
+; MM6-NEXT: mfc1 $2, $f0 # encoding: [0x54,0x40,0x20,0x3b]
+; MM6-NEXT: andi16 $2, $2, 1 # encoding: [0x2d,0x21]
+; MM6-NEXT: jrc $ra # encoding: [0x45,0xbf]
+ %c = fcmp olt double %a, %b
+ %r = zext i1 %c to i32
+ ret i32 %r
+}
diff --git a/llvm/test/CodeGen/Mips/msa/f16-llvm-ir.ll b/llvm/test/CodeGen/Mips/msa/f16-llvm-ir.ll
index b14c88e231413f..2d1f794d7d58f3 100644
--- a/llvm/test/CodeGen/Mips/msa/f16-llvm-ir.ll
+++ b/llvm/test/CodeGen/Mips/msa/f16-llvm-ir.ll
@@ -3560,9 +3560,9 @@ define half @uitofp_i64_f16(i64 %x) {
; MIPSR6-N32-NEXT: dmtc1 $1, $f0
; MIPSR6-N32-NEXT: cvt.s.l $f0, $f0
; MIPSR6-N32-NEXT: add.s $f0, $f0, $f0
-; MIPSR6-N32-NEXT: slti $1, $4, 0
; MIPSR6-N32-NEXT: dmtc1 $4, $f1
; MIPSR6-N32-NEXT: cvt.s.l $f1, $f1
+; MIPSR6-N32-NEXT: slti $1, $4, 0
; MIPSR6-N32-NEXT: mtc1 $1, $f2
; MIPSR6-N32-NEXT: sel.s $f2, $f1, $f0
; MIPSR6-N32-NEXT: splati.w $w0, $w2[0]
@@ -3578,9 +3578,9 @@ define half @uitofp_i64_f16(i64 %x) {
; MIPSR6-N64-NEXT: dmtc1 $1, $f0
; MIPSR6-N64-NEXT: cvt.s.l $f0, $f0
; MIPSR6-N64-NEXT: add.s $f0, $f0, $f0
-; MIPSR6-N64-NEXT: slti $1, $4, 0
; MIPSR6-N64-NEXT: dmtc1 $4, $f1
; MIPSR6-N64-NEXT: cvt.s.l $f1, $f1
+; MIPSR6-N64-NEXT: slti $1, $4, 0
; MIPSR6-N64-NEXT: mtc1 $1, $f2
; MIPSR6-N64-NEXT: sel.s $f2, $f1, $f0
; MIPSR6-N64-NEXT: splati.w $w0, $w2[0]
diff --git a/llvm/test/CodeGen/Mips/r6-fp-branch.ll b/llvm/test/CodeGen/Mips/r6-fp-branch.ll
new file mode 100644
index 00000000000000..d4482253624b8d
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/r6-fp-branch.ll
@@ -0,0 +1,434 @@
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs < %s | FileCheck %s --implicit-check-not='{{^[[:blank:]]+(j|bc)[[:blank:]]}}' --implicit-check-not=mfc1 --implicit-check-not=andi --implicit-check-not="not $"
+
+; Branches test bit zero of the FP comparison mask, without an integer copy
+; or normalization to 0/1. Branch analysis must also eliminate redundant jumps.
+; Cover every nonconstant predicate, including unordered and inverted forms.
+declare void @true_target()
+declare void @false_target()
+
+define void @f32_oeq(float %a, float %b) {
+; CHECK-LABEL: f32_oeq:
+; CHECK: cmp.eq.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1eqz{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp oeq float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ogt(float %a, float %b) {
+; CHECK-LABEL: f32_ogt:
+; CHECK: cmp.ule.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ogt float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_oge(float %a, float %b) {
+; CHECK-LABEL: f32_oge:
+; CHECK: cmp.ult.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp oge float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_olt(float %a, float %b) {
+; CHECK-LABEL: f32_olt:
+; CHECK: cmp.ule.s $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp olt float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ole(float %a, float %b) {
+; CHECK-LABEL: f32_ole:
+; CHECK: cmp.ult.s $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ole float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_one(float %a, float %b) {
+; CHECK-LABEL: f32_one:
+; CHECK: cmp.ueq.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp one float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ord(float %a, float %b) {
+; CHECK-LABEL: f32_ord:
+; CHECK: cmp.un.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ord float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ueq(float %a, float %b) {
+; CHECK-LABEL: f32_ueq:
+; CHECK: cmp.ueq.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %t
+ %c = fcmp ueq float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ugt(float %a, float %b) {
+; CHECK-LABEL: f32_ugt:
+; CHECK: cmp.le.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ugt float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_uge(float %a, float %b) {
+; CHECK-LABEL: f32_uge:
+; CHECK: cmp.lt.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp uge float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ult(float %a, float %b) {
+; CHECK-LABEL: f32_ult:
+; CHECK: cmp.le.s $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ult float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_ule(float %a, float %b) {
+; CHECK-LABEL: f32_ule:
+; CHECK: cmp.lt.s $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ule float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_une(float %a, float %b) {
+; CHECK-LABEL: f32_une:
+; CHECK: cmp.eq.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp une float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f32_uno(float %a, float %b) {
+; CHECK-LABEL: f32_uno:
+; CHECK: cmp.un.s $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %t
+ %c = fcmp uno float %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_oeq(double %a, double %b) {
+; CHECK-LABEL: f64_oeq:
+; CHECK: cmp.eq.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1eqz{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp oeq double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ogt(double %a, double %b) {
+; CHECK-LABEL: f64_ogt:
+; CHECK: cmp.ule.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ogt double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_oge(double %a, double %b) {
+; CHECK-LABEL: f64_oge:
+; CHECK: cmp.ult.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp oge double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_olt(double %a, double %b) {
+; CHECK-LABEL: f64_olt:
+; CHECK: cmp.ule.d $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp olt double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ole(double %a, double %b) {
+; CHECK-LABEL: f64_ole:
+; CHECK: cmp.ult.d $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ole double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_one(double %a, double %b) {
+; CHECK-LABEL: f64_one:
+; CHECK: cmp.ueq.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp one double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ord(double %a, double %b) {
+; CHECK-LABEL: f64_ord:
+; CHECK: cmp.un.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ord double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ueq(double %a, double %b) {
+; CHECK-LABEL: f64_ueq:
+; CHECK: cmp.ueq.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %t
+ %c = fcmp ueq double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ugt(double %a, double %b) {
+; CHECK-LABEL: f64_ugt:
+; CHECK: cmp.le.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ugt double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_uge(double %a, double %b) {
+; CHECK-LABEL: f64_uge:
+; CHECK: cmp.lt.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp uge double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ult(double %a, double %b) {
+; CHECK-LABEL: f64_ult:
+; CHECK: cmp.le.d $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ult double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_ule(double %a, double %b) {
+; CHECK-LABEL: f64_ule:
+; CHECK: cmp.lt.d $f[[CC:[0-9]+]], $f{{13|14}}, $f12
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp ule double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_une(double %a, double %b) {
+; CHECK-LABEL: f64_une:
+; CHECK: cmp.eq.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %f
+ %c = fcmp une double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
+
+define void @f64_uno(double %a, double %b) {
+; CHECK-LABEL: f64_uno:
+; CHECK: cmp.un.d $f[[CC:[0-9]+]], $f12, $f{{13|14}}
+; CHECK: bc1nez{{c?}} $f[[CC]], [[DEST:[.$A-Za-z0-9_]+]]
+; CHECK: [[DEST]]: # %t
+ %c = fcmp uno double %a, %b
+ br i1 %c, label %t, label %f
+t:
+ call void @true_target()
+ ret void
+f:
+ call void @false_target()
+ ret void
+}
diff --git a/llvm/test/CodeGen/Mips/r6-fp-condition-spill.mir b/llvm/test/CodeGen/Mips/r6-fp-condition-spill.mir
new file mode 100644
index 00000000000000..9d0edd078320fe
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/r6-fp-condition-spill.mir
@@ -0,0 +1,45 @@
+# RUN: llc -mtriple=mipsel -mcpu=mips32r6 -run-pass=greedy -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=mips -mcpu=mips32r6 -run-pass=greedy -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=mipsel -mcpu=mips32r6 -start-before=greedy -verify-machineinstrs -filetype=obj %s -o /dev/null
+# RUN: llc -mtriple=mips -mcpu=mips32r6 -start-before=greedy -verify-machineinstrs -filetype=obj %s -o /dev/null
+
+# Spill the low-word predicate to a four-byte slot and the SEL.D result to an
+# eight-byte slot, using the ordinary FPR register classes.
+---
+name: spill_condition
+tracksRegLiveness: true
+# CHECK-LABEL: name: spill_condition
+# CHECK: type: spill-slot, offset: 0, size: 4, alignment: 4
+# CHECK: SWC1
+# CHECK: INLINEASM
+# CHECK: LWC1
+body: |
+ bb.0:
+ liveins: $d12_64, $d14_64
+ %0:fgr64 = COPY $d12_64
+ %1:fgr64 = COPY $d14_64
+ %2:fgr64 = CMP_LT_D %0, %1
+ %3:fgr32 = COPY %2.sub_lo
+ INLINEASM &"", 1, 12, implicit-def dead early-clobber $d0_64, 12, implicit-def dead early-clobber $d1_64, 12, implicit-def dead early-clobber $d2_64, 12, implicit-def dead early-clobber $d3_64, 12, implicit-def dead early-clobber $d4_64, 12, implicit-def dead early-clobber $d5_64, 12, implicit-def dead early-clobber $d6_64, 12, implicit-def dead early-clobber $d7_64, 12, implicit-def dead early-clobber $d8_64, 12, implicit-def dead early-clobber $d9_64, 12, implicit-def dead early-clobber $d10_64, 12, implicit-def dead early-clobber $d11_64, 12, implicit-def dead early-clobber $d12_64, 12, implicit-def dead early-clobber $d13_64, 12, implicit-def dead early-clobber $d14_64, 12, implicit-def dead early-clobber $d15_64, 12, implicit-def dead early-clobber $d16_64, 12, implicit-def dead early-clobber $d17_64, 12, implicit-def dead early-clobber $d18_64, 12, implicit-def dead early-clobber $d19_64, 12, implicit-def dead early-clobber $d20_64, 12, implicit-def dead early-clobber $d21_64, 12, implicit-def dead early-clobber $d22_64, 12, implicit-def dead early-clobber $d23_64, 12, implicit-def dead early-clobber $d24_64, 12, implicit-def dead early-clobber $d25_64, 12, implicit-def dead early-clobber $d26_64, 12, implicit-def dead early-clobber $d27_64, 12, implicit-def dead early-clobber $d28_64, 12, implicit-def dead early-clobber $d29_64, 12, implicit-def dead early-clobber $d30_64, 12, implicit-def dead early-clobber $d31_64
+ $v0 = COPY %3
+ RetRA implicit $v0
+...
+---
+name: spill_select_result
+tracksRegLiveness: true
+# CHECK-LABEL: name: spill_select_result
+# CHECK: type: spill-slot, offset: 0, size: 8, alignment: 8
+# CHECK: SDC164
+# CHECK: INLINEASM
+# CHECK: LDC164
+body: |
+ bb.0:
+ liveins: $d12_64, $d14_64
+ %0:fgr64 = COPY $d12_64
+ %1:fgr64 = COPY $d14_64
+ %2:fgr64 = CMP_LT_D %0, %1
+ %2:fgr64 = SEL_D %2, %1, %0
+ INLINEASM &"", 1, 12, implicit-def dead early-clobber $d0_64, 12, implicit-def dead early-clobber $d1_64, 12, implicit-def dead early-clobber $d2_64, 12, implicit-def dead early-clobber $d3_64, 12, implicit-def dead early-clobber $d4_64, 12, implicit-def dead early-clobber $d5_64, 12, implicit-def dead early-clobber $d6_64, 12, implicit-def dead early-clobber $d7_64, 12, implicit-def dead early-clobber $d8_64, 12, implicit-def dead early-clobber $d9_64, 12, implicit-def dead early-clobber $d10_64, 12, implicit-def dead early-clobber $d11_64, 12, implicit-def dead early-clobber $d12_64, 12, implicit-def dead early-clobber $d13_64, 12, implicit-def dead early-clobber $d14_64, 12, implicit-def dead early-clobber $d15_64, 12, implicit-def dead early-clobber $d16_64, 12, implicit-def dead early-clobber $d17_64, 12, implicit-def dead early-clobber $d18_64, 12, implicit-def dead early-clobber $d19_64, 12, implicit-def dead early-clobber $d20_64, 12, implicit-def dead early-clobber $d21_64, 12, implicit-def dead early-clobber $d22_64, 12, implicit-def dead early-clobber $d23_64, 12, implicit-def dead early-clobber $d24_64, 12, implicit-def dead early-clobber $d25_64, 12, implicit-def dead early-clobber $d26_64, 12, implicit-def dead early-clobber $d27_64, 12, implicit-def dead early-clobber $d28_64, 12, implicit-def dead early-clobber $d29_64, 12, implicit-def dead early-clobber $d30_64, 12, implicit-def dead early-clobber $d31_64
+ $d0_64 = COPY %2
+ RetRA implicit $d0_64
+...
diff --git a/llvm/test/CodeGen/Mips/r6-fp-condition-subregs.ll b/llvm/test/CodeGen/Mips/r6-fp-condition-subregs.ll
new file mode 100644
index 00000000000000..d1bbb208d20c1d
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/r6-fp-condition-subregs.ll
@@ -0,0 +1,217 @@
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -stop-after=finalize-isel -verify-machineinstrs < %s | FileCheck %s --check-prefix=ISEL
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mipsel -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips -mcpu=mips32r6 -mattr=+micromips -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips64el -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+; RUN: llc -mtriple=mips64 -mcpu=mips64r6 -target-abi=n32 -verify-machineinstrs -filetype=obj < %s -o /dev/null
+
+; Coalesce the low-word condition with the full FPR used by SEL.D, avoiding an
+; mfc1/mtc1 round trip (llvm/llvm-project#172459).
+define double @compare_select(double %a, double %b) {
+; CHECK-LABEL: compare_select:
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: cmp.lt.d $f[[COND:[0-9]+]],
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: sel.d $f[[COND]],
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: .end compare_select
+;
+; ISEL-LABEL: name: compare_select
+; ISEL: %[[CMP:[0-9]+]]:fgr64 = CMP_LT_D
+; ISEL-NEXT: %[[CC:[0-9]+]]:gpr32 = COPY %[[CMP]].sub_lo
+; ISEL: %[[UNDEF:[0-9]+]]:fgr64 = IMPLICIT_DEF
+; ISEL: %[[EXT:[0-9]+]]:fgr64 = INSERT_SUBREG %[[UNDEF]], killed %[[CC]], %subreg.sub_lo
+; ISEL: %{{[0-9]+}}:fgr64 = SEL_D %[[EXT]],
+ %c = fcmp olt double %a, %b
+ %r = select i1 %c, double %a, double %b
+ ret double %r
+}
+
+; Sharing a predicate across SEL.D instructions requires copies that preserve
+; the FPR width. This previously crashed in copyPhysReg (#223905).
+define void @shared_condition(ptr %out, <2 x double> %a, <2 x double> %b, i1 %c) {
+; CHECK-LABEL: shared_condition:
+; CHECK: mtc1
+; CHECK-COUNT-4: sel.d
+ %selected = select i1 %c, <2 x double> %b, <2 x double> %a
+ %cmp = fcmp olt <2 x double> %a, %selected
+ %result = select <2 x i1> %cmp, <2 x double> %a, <2 x double> %selected
+ store <2 x double> %result, ptr %out, align 16
+ ret void
+}
+
+; A double compare can feed both a single-precision select and an integer use.
+define float @double_condition_float_result(double %a, double %b,
+ float %t, float %f, ptr %out) {
+; CHECK-LABEL: double_condition_float_result:
+; CHECK: cmp.lt.d
+; CHECK-DAG: mfc1
+; CHECK-DAG: sel.s
+ %c = fcmp olt double %a, %b
+ %tv = fadd float %t, 1.0
+ %fv = fmul float %f, 2.0
+ %r = select i1 %c, float %tv, float %fv
+ store i1 %c, ptr %out
+ ret float %r
+}
+
+; SEL.D can use bit zero of a single-precision comparison result.
+define double @float_condition_double_result(float %a, float %b,
+ double %t, double %f) {
+; CHECK-LABEL: float_condition_double_result:
+; CHECK: cmp.lt.s $f[[COND:[0-9]+]],
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: sel.d $f[[COND]],
+ %c = fcmp olt float %a, %b
+ %r = select i1 %c, double %t, double %f
+ ret double %r
+}
+
+; Coalesce the copies between CMP.S and SEL.S without emitting register moves.
+define float @single_compare_select(float %a, float %b) {
+; CHECK-LABEL: single_compare_select:
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: cmp.lt.s $f[[COND:[0-9]+]],
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: sel.s $f[[COND]],
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: .end single_compare_select
+;
+; ISEL-LABEL: name: single_compare_select
+; ISEL: %[[CMP:[0-9]+]]:fgr32 = CMP_LT_S
+; ISEL-NEXT: %[[CC:[0-9]+]]:fgr32 = COPY killed %[[CMP]]
+; ISEL-NEXT: %[[COND:[0-9]+]]:fgr32 = COPY killed %[[CC]]
+; ISEL: %{{[0-9]+}}:fgr32 = SEL_S %[[COND]],
+ %c = fcmp olt float %a, %b
+ %r = select i1 %c, float %a, float %b
+ ret float %r
+}
+
+; Both selects need the same FP predicate. Preserve it across the first tied
+; select with an FPR copy, including when the second select has a different width.
+define void @shared_fp_condition(ptr %outd, ptr %outf, double %a, double %b,
+ float %x, float %y) {
+; CHECK-LABEL: shared_fp_condition:
+; CHECK: cmp.lt.d $f[[COND:[0-9]+]],
+; CHECK-NOT: mfc1
+; CHECK: mov.d $f[[COPY:[0-9]+]], $f[[COND]]
+; CHECK-NOT: mfc1
+; CHECK: sel.d $f[[COPY]],
+; CHECK-NOT: mfc1
+; CHECK: sel.s $f[[COND]],
+; CHECK-NOT: mfc1
+; CHECK: .end shared_fp_condition
+ %c = fcmp olt double %a, %b
+ %t = fadd float %x, 1.0
+ %f = fmul float %y, 2.0
+ %d = select i1 %c, double %a, double %b
+ %s = select i1 %c, float %t, float %f
+ store double %d, ptr %outd
+ store float %s, ptr %outf
+ ret void
+}
+
+; Conditions from different-width compares can also merge through an i32 PHI.
+define double @phi_mixed_conditions(i1 %choose, double %a, double %b,
+ float %x, float %y) {
+; CHECK-LABEL: phi_mixed_conditions:
+; CHECK: cmp.ult.s
+; CHECK: cmp.le.d
+; CHECK: sel.d
+;
+; ISEL-LABEL: name: phi_mixed_conditions
+; ISEL: CMP_ULT_S
+; ISEL: CMP_LE_D
+; ISEL: %[[CC:[0-9]+]]:gpr32 = PHI
+; ISEL: INSERT_SUBREG {{.*}}%[[CC]], %subreg.sub_lo
+; ISEL: SEL_D
+entry:
+ br i1 %choose, label %single, label %double
+single:
+ %cs = fcmp ult float %x, %y
+ br label %join
+double:
+ %cd = fcmp ole double %a, %b
+ br label %join
+join:
+ %c = phi i1 [ %cs, %single ], [ %cd, %double ]
+ %r = select i1 %c, double %a, double %b
+ ret double %r
+}
+
+; An unordered comparison must select the true arm when either operand is NaN.
+define float @unordered_select(float %a, float %b) {
+; CHECK-LABEL: unordered_select:
+; CHECK: cmp.un.s $f[[COND:[0-9]+]], $f[[A:[0-9]+]], $f[[B:[0-9]+]]
+; CHECK-NOT: mfc1
+; CHECK-NOT: mtc1
+; CHECK: sel.s $f[[COND]], $f[[B]], $f[[A]]
+ %c = fcmp uno float %a, %b
+ %r = select i1 %c, float %a, float %b
+ ret float %r
+}
+
+; An arbitrary integer's low bit cannot be replaced by a zero/nonzero test.
+declare void @branch_true()
+declare void @branch_false()
+
+define void @branch_bit0(i32 %x) {
+; CHECK-LABEL: branch_bit0:
+; CHECK: andi{{(16)?}} $[[CC:[0-9]+]], ${{[0-9]+}}, 1
+; CHECK: b{{eqz|nez}}{{c?}} $[[CC]],
+ %c = trunc i32 %x to i1
+ br i1 %c, label %t, label %f
+t:
+ call void @branch_true()
+ ret void
+f:
+ call void @branch_false()
+ ret void
+}
+
+; Share one compare between an FPR branch and an integer use. Only the latter
+; needs to copy and normalize the FP mask to 0/1.
+define void @branch_and_store_boolean(double %a, double %b, ptr %out) {
+; CHECK-LABEL: branch_and_store_boolean:
+; CHECK: cmp.eq.d $f[[COND:[0-9]+]],
+; CHECK: mfc1 {{.*}}, $f[[COND]]
+; CHECK: andi{{(16)?}} {{.*}}, 1
+; CHECK-DAG: bc1eqz{{c?}} $f[[COND]],
+; CHECK-DAG: sw
+;
+; ISEL-LABEL: name: branch_and_store_boolean
+; ISEL: %[[CMP:[0-9]+]]:fgr64 = CMP_EQ_D
+; ISEL-NEXT: %[[CC:[0-9]+]]:gpr32 = COPY %[[CMP]].sub_lo
+; ISEL-NEXT: %[[BOOL:[0-9]+]]:gpr32 = ANDi %[[CC]], 1
+; ISEL: SW killed %[[BOOL]],
+; ISEL: %[[FPCOND:[0-9]+]]:fgr32 = COPY %[[CC]]
+; ISEL-NEXT: BC1EQZ killed %[[FPCOND]],
+ %c = fcmp oeq double %a, %b
+ %b32 = zext i1 %c to i32
+ store i32 %b32, ptr %out
+ br i1 %c, label %t, label %f
+t:
+ call void @branch_true()
+ ret void
+f:
+ call void @branch_false()
+ ret void
+}
diff --git a/llvm/test/CodeGen/Mips/select.ll b/llvm/test/CodeGen/Mips/select.ll
index eee1921d1b8940..e51f3e27c393ce 100644
--- a/llvm/test/CodeGen/Mips/select.ll
+++ b/llvm/test/CodeGen/Mips/select.ll
@@ -194,9 +194,9 @@ define float @i32_icmp_ne_f32_val(i32 signext %s, float %f0, float %f1) nounwind
; 32R6: # %bb.0: # %entry
; 32R6-NEXT: sltu $1, $zero, $4
; 32R6-NEXT: negu $1, $1
+; 32R6-NEXT: mtc1 $1, $f0
; 32R6-NEXT: mtc1 $5, $f1
; 32R6-NEXT: mtc1 $6, $f2
-; 32R6-NEXT: mtc1 $1, $f0
; 32R6-NEXT: jr $ra
; 32R6-NEXT: sel.s $f0, $f2, $f1
;
@@ -248,8 +248,8 @@ define double @i32_icmp_ne_f64_val(i32 signext %s, double %f0, double %f1) nounw
; 32R6-NEXT: mthc1 $7, $f1
; 32R6-NEXT: sltu $1, $zero, $4
; 32R6-NEXT: negu $1, $1
-; 32R6-NEXT: ldc1 $f2, 16($sp)
; 32R6-NEXT: mtc1 $1, $f0
+; 32R6-NEXT: ldc1 $f2, 16($sp)
; 32R6-NEXT: jr $ra
; 32R6-NEXT: sel.d $f0, $f2, $f1
;
@@ -669,6 +669,7 @@ define float @f64_fcmp_ogt_f32_val(float %f0, float %f1, double %f2, double %f3)
; 32R6-NEXT: mthc1 $7, $f0
; 32R6-NEXT: ldc1 $f1, 16($sp)
; 32R6-NEXT: cmp.lt.d $f0, $f1, $f0
+; 32R6-NEXT: # kill: def $f0 killed $f0 killed $d0_64
; 32R6-NEXT: jr $ra
; 32R6-NEXT: sel.s $f0, $f14, $f12
;
@@ -689,6 +690,7 @@ define float @f64_fcmp_ogt_f32_val(float %f0, float %f1, double %f2, double %f3)
; 64R6-LABEL: f64_fcmp_ogt_f32_val:
; 64R6: # %bb.0: # %entry
; 64R6-NEXT: cmp.lt.d $f0, $f15, $f14
+; 64R6-NEXT: # kill: def $f0 killed $f0 killed $d0_64
; 64R6-NEXT: jr $ra
; 64R6-NEXT: sel.s $f0, $f13, $f12
entry:
More information about the llvm-commits
mailing list