Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -401,6 +401,8 @@ public: enum MipsMatchResultTy { Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresDifferentOperands, + Match_RequiresNoZeroRegister, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -3643,6 +3645,18 @@ // jalr.hb must be different. // It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction // and registers Rd and Base for microMIPS lwp instruction + + // As described the MIPSR6 spec, the compact branches that compare registers + // must: + // a) Not use the zero register. + // b) Not use the same register twice. + // c) rs < rt for bnec, beqc. + // NB: For this case, LLVM's direct object emission will swap the operands + // as their ordering doesn't matter. GAS performs this transformation + // too. Hence, that constraint does not have to be enforced. + // + // The compact branches that branch iff the signed addition of two registers + // would overflow must have rs >= rt. unsigned Opcode = Inst.getOpcode(); if ((Opcode == Mips::JALR_HB || Opcode == Mips::JALRC_HB_MMR6) && @@ -3651,6 +3665,22 @@ else if ((Opcode == Mips::LWP_MM || Opcode == Mips::LWP_MMR6) && (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg())) return Match_RequiresDifferentSrcAndDst; + else if ((Opcode == Mips::BLEZC || Opcode == Mips::BGEZC || + Opcode == Mips::BGEC || Opcode == Mips::BGTZC || + Opcode == Mips::BLTZC || Opcode == Mips::BLTC || + Opcode == Mips::BGEUC || Opcode == Mips::BLTUC || + Opcode == Mips::BEQC || Opcode == Mips::BNEC || + Opcode == Mips::BEQZC || Opcode == Mips::BNEZC) && + (Inst.getOperand(0).getReg() == Mips::ZERO)) + return Match_RequiresNoZeroRegister; + else if (Opcode == Mips::BGEC || Opcode == Mips::BLTC || + Opcode == Mips::BGEUC || Opcode == Mips::BLTUC || + Opcode == Mips::BEQC || Opcode == Mips::BNEC) { + if (Inst.getOperand(1).getReg() == Mips::ZERO) + return Match_RequiresNoZeroRegister; + if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) + return Match_RequiresDifferentOperands; + } return Match_Success; } @@ -3702,6 +3732,10 @@ return Error(IDLoc, "invalid instruction"); case Match_RequiresDifferentSrcAndDst: return Error(IDLoc, "source and destination must be different"); + case Match_RequiresDifferentOperands: + return Error(IDLoc, "registers must be different"); + case Match_RequiresNoZeroRegister: + return Error(IDLoc, "invalid operand ($zero) for instruction"); case Match_Immz: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); case Match_UImm1_0: Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -117,9 +117,15 @@ 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; + if (Inst.getOpcode() == Mips::BNEC || Inst.getOpcode() == Mips::BEQC) { + assert(Reg0 != Reg1 && "Instruction has bad operands ($rs == $rt)!"); + if (Reg0 < Reg1) + return; + } else if (Inst.getOpcode() == Mips::BNVC || Inst.getOpcode() == Mips::BOVC) { + if (Reg0 >= Reg1) + return; + } else + llvm_unreachable("Cannot rewrite unknown branch!"); Inst.getOperand(0).setReg(RegOp1); Inst.getOperand(1).setReg(RegOp0); @@ -181,9 +187,11 @@ case Mips::DINS: LowerDins(TmpInst); break; - // Compact branches. + // Compact branches, enforce encoding restrictions. case Mips::BEQC: case Mips::BNEC: + case Mips::BOVC: + case Mips::BNVC: LowerCompactBranch(TmpInst); } Index: test/MC/Mips/mips32r6/invalid.s =================================================================== --- test/MC/Mips/mips32r6/invalid.s +++ test/MC/Mips/mips32r6/invalid.s @@ -45,6 +45,24 @@ bgeul $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled bgtl $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled bgtul $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled + bgec $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltc $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgeuc $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltuc $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + beqc $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnec $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgec $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgeuc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltuc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + beqc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnec $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + blezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgtzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + beqzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction cache -1, 255($7) # CHECK: :[[@LINE]]:15: error: expected 5-bit unsigned immediate cache 32, 255($7) # CHECK: :[[@LINE]]:15: error: expected 5-bit unsigned immediate jalr.hb $31 # CHECK: :[[@LINE]]:9: error: source and destination must be different Index: test/MC/Mips/mips32r6/valid-xfail.s =================================================================== --- test/MC/Mips/mips32r6/valid-xfail.s +++ /dev/null @@ -1,19 +0,0 @@ -# Instructions that should be valid but currently fail for known reasons (e.g. -# they aren't implemented yet). -# This test is set up to XPASS if any instruction generates an encoding. -# -# RUN: not llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips32r6 | not FileCheck %s -# CHECK-NOT: encoding -# XFAIL: * - - .set noat - bovc $0, $2, 4 # TODO: bovc $0, $2, 4 # encoding: [0x20,0x40,0x00,0x01] - bovc $2, $4, 4 # TODO: bovc $2, $4, 4 # encoding: [0x20,0x82,0x00,0x01] - bnvc $0, $2, 4 # TODO: bnvc $0, $2, 4 # encoding: [0x60,0x40,0x00,0x01] - bnvc $2, $4, 4 # TODO: bnvc $2, $4, 4 # encoding: [0x60,0x82,0x00,0x01] - beqc $0, $6, 256 # TODO: beqc $6, $zero, 256 # encoding: [0x20,0xc0,0x00,0x40] - beqc $5, $0, 256 # TODO: beqc $5, $zero, 256 # encoding: [0x20,0xa0,0x00,0x40] - beqc $6, $5, 256 # TODO: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] - bnec $0, $6, 256 # TODO: bnec $6, $zero, 256 # encoding: [0x60,0xc0,0x00,0x40] - bnec $5, $0, 256 # TODO: bnec $5, $zero, 256 # encoding: [0x60,0xa0,0x00,0x40] - bnec $6, $5, 256 # TODO: bnec $5, $6, 256 # encoding: [0x60,0xa6,0x00,0x40] Index: test/MC/Mips/mips32r6/valid.s =================================================================== --- test/MC/Mips/mips32r6/valid.s +++ test/MC/Mips/mips32r6/valid.s @@ -33,13 +33,13 @@ bc2eqz $31,8 # CHECK: bc2eqz $31, 8 # encoding: [0x49,0x3f,0x00,0x02] bc2nez $0,8 # CHECK: bc2nez $0, 8 # encoding: [0x49,0xa0,0x00,0x02] bc2nez $31,8 # CHECK: bc2nez $31, 8 # encoding: [0x49,0xbf,0x00,0x02] - # beqc requires rs < rt && rs != 0 but we also accept when this is not true. See also bovc - # FIXME: Testcases are in valid-xfail.s at the moment - beqc $5, $6, 256 # CHECK: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] + # beqc requires rs < rt && rs != 0 but we accept this and fix it. See also bovc. + beqc $5, $6, 256 # CHECK: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] + beqc $6, $5, 256 # CHECK: beqc $6, $5, 256 # encoding: [0x20,0xa6,0x00,0x40] beqzalc $2, 1332 # CHECK: beqzalc $2, 1332 # encoding: [0x20,0x02,0x01,0x4d] - # bnec requires rs < rt && rs != 0 but we accept when this is not true. See also bnvc - # FIXME: Testcases are in valid-xfail.s at the moment + # bnec requires rs < rt && rs != 0 but we accept this and fix it. See also bnvc. bnec $5, $6, 256 # CHECK: bnec $5, $6, 256 # encoding: [0x60,0xa6,0x00,0x40] + bnec $6, $5, 256 # CHECK: bnec $6, $5, 256 # encoding: [0x60,0xa6,0x00,0x40] bnezalc $2, 1332 # CHECK: bnezalc $2, 1332 # encoding: [0x60,0x02,0x01,0x4d] beqzc $5, 72256 # CHECK: beqzc $5, 72256 # encoding: [0xd8,0xa0,0x46,0x90] bgec $2, $3, 256 # CHECK: bgec $2, $3, 256 # encoding: [0x58,0x43,0x00,0x40] @@ -56,14 +56,14 @@ blezalc $2, 1332 # CHECK: blezalc $2, 1332 # encoding: [0x18,0x02,0x01,0x4d] bltc $5, $6, 256 # CHECK: bltc $5, $6, 256 # encoding: [0x5c,0xa6,0x00,0x40] bltuc $5, $6, 256 # CHECK: bltuc $5, $6, 256 # encoding: [0x1c,0xa6,0x00,0x40] - # bnvc requires that rs >= rt but we accept both. See also bnec + # bnvc requires that rs >= rt but we accept both and fix this. See also bnec. bnvc $0, $0, 4 # CHECK: bnvc $zero, $zero, 4 # encoding: [0x60,0x00,0x00,0x01] bnvc $2, $0, 4 # CHECK: bnvc $2, $zero, 4 # encoding: [0x60,0x40,0x00,0x01] - bnvc $4, $2, 4 # CHECK: bnvc $4, $2, 4 # encoding: [0x60,0x82,0x00,0x01] - # bovc requires that rs >= rt but we accept both. See also beqc + bnvc $2, $4, 4 # CHECK: bnvc $2, $4, 4 # encoding: [0x60,0x82,0x00,0x01] + # bovc requires that rs >= rt but we accept both and fix this. See also beqc. bovc $0, $0, 4 # CHECK: bovc $zero, $zero, 4 # encoding: [0x20,0x00,0x00,0x01] bovc $2, $0, 4 # CHECK: bovc $2, $zero, 4 # encoding: [0x20,0x40,0x00,0x01] - bovc $4, $2, 4 # CHECK: bovc $4, $2, 4 # encoding: [0x20,0x82,0x00,0x01] + bovc $2, $4, 4 # CHECK: bovc $2, $4, 4 # encoding: [0x20,0x82,0x00,0x01] cache 1, 8($5) # CHECK: cache 1, 8($5) # encoding: [0x7c,0xa1,0x04,0x25] cmp.af.s $f2,$f3,$f4 # CHECK: cmp.af.s $f2, $f3, $f4 # encoding: [0x46,0x84,0x18,0x80] cmp.af.d $f2,$f3,$f4 # CHECK: cmp.af.d $f2, $f3, $f4 # encoding: [0x46,0xa4,0x18,0x80] Index: test/MC/Mips/mips64r6/invalid.s =================================================================== --- test/MC/Mips/mips64r6/invalid.s +++ test/MC/Mips/mips64r6/invalid.s @@ -45,6 +45,20 @@ bgeul $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled bgtl $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled bgtul $7, $8, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: instruction requires a CPU feature not currently enabled + beqc $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnec $0, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgec $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgeuc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltuc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + beqc $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnec $2, $2, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + blezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bgtzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bltzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + beqzc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction + bnezc $0, local_label # -CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand ($zero) for instruction cache -1, 255($7) # CHECK: :[[@LINE]]:15: error: expected 5-bit unsigned immediate cache 32, 255($7) # CHECK: :[[@LINE]]:15: error: expected 5-bit unsigned immediate dalign $4, $2, $3, -1 # CHECK: :[[@LINE]]:29: error: expected 3-bit unsigned immediate Index: test/MC/Mips/mips64r6/valid-xfail.s =================================================================== --- test/MC/Mips/mips64r6/valid-xfail.s +++ /dev/null @@ -1,19 +0,0 @@ -# Instructions that should be valid but currently fail for known reasons (e.g. -# they aren't implemented yet). -# This test is set up to XPASS if any instruction generates an encoding. -# -# RUN: not llvm-mc %s -triple=mips64-unknown-linux -show-encoding -mcpu=mips64r6 | not FileCheck %s -# CHECK-NOT: encoding -# XFAIL: * - - .set noat - bovc $0, $2, 4 # TODO: bovc $0, $2, 4 # encoding: [0x20,0x40,0x00,0x01] - bovc $2, $4, 4 # TODO: bovc $2, $4, 4 # encoding: [0x20,0x82,0x00,0x01] - bnvc $0, $2, 4 # TODO: bnvc $0, $2, 4 # encoding: [0x60,0x40,0x00,0x01] - bnvc $2, $4, 4 # TODO: bnvc $2, $4, 4 # encoding: [0x60,0x82,0x00,0x01] - beqc $0, $6, 256 # TODO: beqc $6, $zero, 256 # encoding: [0x20,0xc0,0x00,0x40] - beqc $5, $0, 256 # TODO: beqc $5, $zero, 256 # encoding: [0x20,0xa0,0x00,0x40] - beqc $6, $5, 256 # TODO: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] - bnec $0, $6, 256 # TODO: bnec $6, $zero, 256 # encoding: [0x60,0xc0,0x00,0x40] - bnec $5, $0, 256 # TODO: bnec $5, $zero, 256 # encoding: [0x60,0xa0,0x00,0x40] - bnec $6, $5, 256 # TODO: bnec $5, $6, 256 # encoding: [0x60,0xa6,0x00,0x40] Index: test/MC/Mips/mips64r6/valid.s =================================================================== --- test/MC/Mips/mips64r6/valid.s +++ test/MC/Mips/mips64r6/valid.s @@ -33,12 +33,10 @@ bc2eqz $31,8 # CHECK: bc2eqz $31, 8 # encoding: [0x49,0x3f,0x00,0x02] bc2nez $0,8 # CHECK: bc2nez $0, 8 # encoding: [0x49,0xa0,0x00,0x02] bc2nez $31,8 # CHECK: bc2nez $31, 8 # encoding: [0x49,0xbf,0x00,0x02] - # beqc requires rs < rt && rs != 0 but we also accept when this is not true. See also bovc - # FIXME: Testcases are in valid-xfail.s at the moment - beqc $5, $6, 256 # CHECK: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] + # beqc requires rs < rt && rs != 0 but we accept this and fix it. See also bovc. + beqc $5, $6, 256 # CHECK: beqc $5, $6, 256 # encoding: [0x20,0xa6,0x00,0x40] + beqc $6, $5, 256 # CHECK: beqc $6, $5, 256 # encoding: [0x20,0xa6,0x00,0x40] beqzalc $2, 1332 # CHECK: beqzalc $2, 1332 # encoding: [0x20,0x02,0x01,0x4d] - # bnec requires rs < rt && rs != 0 but we accept when this is not true. See also bnvc - # FIXME: Testcases are in valid-xfail.s at the moment beqzc $5, 72256 # CHECK: beqzc $5, 72256 # encoding: [0xd8,0xa0,0x46,0x90] bgec $2, $3, 256 # CHECK: bgec $2, $3, 256 # encoding: [0x58,0x43,0x00,0x40] bgeuc $2, $3, 256 # CHECK: bgeuc $2, $3, 256 # encoding: [0x18,0x43,0x00,0x40] @@ -53,17 +51,19 @@ bltuc $5, $6, 256 # CHECK: bltuc $5, $6, 256 # encoding: [0x1c,0xa6,0x00,0x40] bltzalc $2, 1332 # CHECK: bltzalc $2, 1332 # encoding: [0x1c,0x42,0x01,0x4d] bltzc $5, 256 # CHECK: bltzc $5, 256 # encoding: [0x5c,0xa5,0x00,0x40] + # bnec requires rs < rt && rs != 0 but we accept this and fix it. See also bnvc. bnec $5, $6, 256 # CHECK: bnec $5, $6, 256 # encoding: [0x60,0xa6,0x00,0x40] + bnec $6, $5, 256 # CHECK: bnec $6, $5, 256 # encoding: [0x60,0xa6,0x00,0x40] bnezalc $2, 1332 # CHECK: bnezalc $2, 1332 # encoding: [0x60,0x02,0x01,0x4d] bnezc $5, 72256 # CHECK: bnezc $5, 72256 # encoding: [0xf8,0xa0,0x46,0x90] - # bnvc requires that rs >= rt but we accept both. See also bnec + # bnvc requires that rs >= rt but we accept both and fix this. See also bnec. bnvc $0, $0, 4 # CHECK: bnvc $zero, $zero, 4 # encoding: [0x60,0x00,0x00,0x01] bnvc $2, $0, 4 # CHECK: bnvc $2, $zero, 4 # encoding: [0x60,0x40,0x00,0x01] - bnvc $4, $2, 4 # CHECK: bnvc $4, $2, 4 # encoding: [0x60,0x82,0x00,0x01] - # bovc requires that rs >= rt but we accept both. See also beqc + bnvc $2, $4, 4 # CHECK: bnvc $2, $4, 4 # encoding: [0x60,0x82,0x00,0x01] + # bovc requires that rs >= rt but we accept both and fix this. See also beqc. bovc $0, $0, 4 # CHECK: bovc $zero, $zero, 4 # encoding: [0x20,0x00,0x00,0x01] bovc $2, $0, 4 # CHECK: bovc $2, $zero, 4 # encoding: [0x20,0x40,0x00,0x01] - bovc $4, $2, 4 # CHECK: bovc $4, $2, 4 # encoding: [0x20,0x82,0x00,0x01] + bovc $2, $4, 4 # CHECK: bovc $2, $4, 4 # encoding: [0x20,0x82,0x00,0x01] cache 1, 8($5) # CHECK: cache 1, 8($5) # encoding: [0x7c,0xa1,0x04,0x25] class.d $f2, $f4 # CHECK: class.d $f2, $f4 # encoding: [0x46,0x20,0x20,0x9b] class.s $f2, $f4 # CHECK: class.s $f2, $f4 # encoding: [0x46,0x00,0x20,0x9b]