Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -246,6 +246,8 @@ unsigned getRegisterListOpValue16(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + private: + void LowerCompactBranch(MCInst& Inst) const; }; // class MipsMCCodeEmitter } // namespace llvm. Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -106,6 +106,26 @@ return; } +// Fix a bad compact branch encoding for beqc/bnec. +void MipsMCCodeEmitter::LowerCompactBranch(MCInst& Inst) const { + + // Encoding may be illegal !(rs < rt), but this situation is + // easily fixed. + unsigned RegOp0 = Inst.getOperand(0).getReg(); + unsigned RegOp1 = Inst.getOperand(1).getReg(); + + unsigned Reg0 = Ctx.getRegisterInfo()->getEncodingValue(RegOp0); + unsigned Reg1 = Ctx.getRegisterInfo()->getEncodingValue(RegOp1); + + assert(Reg0 != Reg1 && "Instruction has bad operands ($rs == $rt)!"); + if (Reg0 < Reg1) + return; + + Inst.getOperand(0).setReg(RegOp1); + Inst.getOperand(1).setReg(RegOp0); + +} + bool MipsMCCodeEmitter::isMicroMips(const MCSubtargetInfo &STI) const { return STI.getFeatureBits()[Mips::FeatureMicroMips]; } @@ -160,6 +180,11 @@ // Double extract instruction is chosen by pos and size operands case Mips::DINS: LowerDins(TmpInst); + break; + // Compact branches. + case Mips::BEQC: + case Mips::BNEC: + LowerCompactBranch(TmpInst); } unsigned long N = Fixups.size(); Index: lib/Target/Mips/Mips32r6InstrFormats.td =================================================================== --- lib/Target/Mips/Mips32r6InstrFormats.td +++ lib/Target/Mips/Mips32r6InstrFormats.td @@ -360,7 +360,7 @@ } // This class is ambiguous with other branches: -// BEQC/BNEC require that rs > rt +// BEQC/BNEC require that rs < rt class CMP_BRANCH_2R_OFF16_FM : MipsR6Inst { bits<5> rs; bits<5> rt; Index: lib/Target/Mips/MipsInstrInfo.cpp =================================================================== --- lib/Target/Mips/MipsInstrInfo.cpp +++ lib/Target/Mips/MipsInstrInfo.cpp @@ -282,6 +282,16 @@ } } + // MIPSR6 forbids both operands being the zero register. + if (Subtarget.hasMips32r6() && + (I->getOperand(0).getType() == MachineOperand::MO_Register && + (I->getOperand(0).getReg() == Mips::ZERO || + I->getOperand(0).getReg() == Mips::ZERO_64)) && + (I->getOperand(1).getType() == MachineOperand::MO_Register && + (I->getOperand(1).getReg() == Mips::ZERO || + I->getOperand(1).getReg() == Mips::ZERO_64))) + return 0; + if (Subtarget.hasMips32r6() || canUseShortMicroMipsCTI) { switch (Opcode) { case Mips::B: @@ -299,8 +309,12 @@ else return Mips::BNEC; case Mips::BGE: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; return Mips::BGEC; case Mips::BGEU: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; return Mips::BGEUC; case Mips::BGEZ: return Mips::BGEZC; @@ -309,8 +323,12 @@ case Mips::BLEZ: return Mips::BLEZC; case Mips::BLT: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; return Mips::BLTC; case Mips::BLTU: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; return Mips::BLTUC; case Mips::BLTZ: return Mips::BLTZC; @@ -330,7 +348,7 @@ return Mips::JIC64; case Mips::JALR64Pseudo: return Mips::JIALC64; - default: + default: return 0; } } Index: test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll @@ -0,0 +1,52 @@ +; RUN: llc -march=mipsel -mcpu=mips32r6 -disable-mips-delay-filler < %s | FileCheck %s +; RUN: llc -march=mips -mcpu=mips32r6 -disable-mips-delay-filler < %s -filetype=obj -o - | llvm-objdump -arch=mips -mcpu=mips32r6 -d - | FileCheck %s -check-prefix=ENCODING + +; bnezc and beqzc have restriction that $rt != 0 + +define i32 @f() { +; CHECK-LABEL: f +; CHECK-NOT: bnezc $0 + + %cmp = icmp eq i32 1, 1 + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i32 1 + + if.end: + ret i32 0 +} + +define i32 @f1() { +; CHECK-LABEL: f1 +; CHECK-NOT: beqzc $0 + + %cmp = icmp eq i32 0, 0 + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i32 1 + + if.end: + ret i32 0 +} + +; We silently fixup cases where the register allocator or user has given us +; an instruction with incorrect operands that is trivially acceptable. +; beqc and bnec have the restriction that $rs < $rt. + +define i32 @f2(i32 %a, i32 %b) { +; ENCODING-LABEL: f2 +; ENCODING-NOT: beqc $5, $4 +; ENCODING-NOT: bnec $5, $4 + + %cmp = icmp eq i32 %b, %a + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i32 1 + + if.end: + ret i32 0 +} +