Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -3748,7 +3748,14 @@ case Mips::BLTZC: case Mips::BEQZC: case Mips::BNEZC: - if (Inst.getOperand(0).getReg() == Mips::ZERO) + case Mips::BLEZC64: + case Mips::BGEZC64: + case Mips::BGTZC64: + case Mips::BLTZC64: + case Mips::BEQZC64: + case Mips::BNEZC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; return Match_Success; case Mips::BGEC: @@ -3757,9 +3764,17 @@ case Mips::BLTUC: case Mips::BEQC: case Mips::BNEC: - if (Inst.getOperand(0).getReg() == Mips::ZERO) + case Mips::BGEC64: + case Mips::BLTC64: + case Mips::BGEUC64: + case Mips::BLTUC64: + case Mips::BEQC64: + case Mips::BNEC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; - if (Inst.getOperand(1).getReg() == Mips::ZERO) + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) return Match_RequiresDifferentOperands; Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -117,7 +117,8 @@ unsigned Reg0 = Ctx.getRegisterInfo()->getEncodingValue(RegOp0); unsigned Reg1 = Ctx.getRegisterInfo()->getEncodingValue(RegOp1); - if (Inst.getOpcode() == Mips::BNEC || Inst.getOpcode() == Mips::BEQC) { + if (Inst.getOpcode() == Mips::BNEC || Inst.getOpcode() == Mips::BEQC || + Inst.getOpcode() == Mips::BNEC64 || Inst.getOpcode() == Mips::BEQC64) { assert(Reg0 != Reg1 && "Instruction has bad operands ($rs == $rt)!"); if (Reg0 < Reg1) return; @@ -125,7 +126,7 @@ if (Reg0 >= Reg1) return; } else - llvm_unreachable("Cannot rewrite unknown branch!"); + llvm_unreachable("Cannot rewrite unknown branch!"); Inst.getOperand(0).setReg(RegOp1); Inst.getOperand(1).setReg(RegOp0); @@ -190,6 +191,8 @@ // Compact branches, enforce encoding restrictions. case Mips::BEQC: case Mips::BNEC: + case Mips::BEQC64: + case Mips::BNEC64: case Mips::BOVC: case Mips::BNVC: LowerCompactBranch(TmpInst); Index: lib/Target/Mips/Mips64r6InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64r6InstrInfo.td +++ lib/Target/Mips/Mips64r6InstrInfo.td @@ -76,6 +76,19 @@ class SELEQZ64_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR64Opnd>; class SELNEZ64_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR64Opnd>; +class BGEC64_DESC : CMP_BC_DESC_BASE<"bgec", brtarget, GPR64Opnd>; +class BGEUC64_DESC : CMP_BC_DESC_BASE<"bgeuc", brtarget, GPR64Opnd>; +class BEQC64_DESC : CMP_BC_DESC_BASE<"beqc", brtarget, GPR64Opnd>; +class BNEC64_DESC : CMP_BC_DESC_BASE<"bnec", brtarget, GPR64Opnd>; +class BLTC64_DESC : CMP_BC_DESC_BASE<"bltc", brtarget, GPR64Opnd>; +class BLTUC64_DESC : CMP_BC_DESC_BASE<"bltuc", brtarget, GPR64Opnd>; +class BLTZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzc", brtarget, GPR64Opnd>; +class BGEZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezc", brtarget, GPR64Opnd>; +class BLEZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezc", brtarget, GPR64Opnd>; +class BGTZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzc", brtarget, GPR64Opnd>; +class BEQZC64_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21, GPR64Opnd>; +class BNEZC64_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21, GPR64Opnd>; + class JIALC64_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16, GPR64Opnd> { bit isCall = 1; @@ -123,10 +136,28 @@ def SELEQZ64 : SELEQZ_ENC, SELEQZ64_DESC, ISA_MIPS32R6, GPR_64; def SELNEZ64 : SELNEZ_ENC, SELNEZ64_DESC, ISA_MIPS32R6, GPR_64; } -let isCodeGenOnly = 1 in { -def JIALC64 : JIALC_ENC, JIALC64_DESC, ISA_MIPS64R6; -def JIC64 : JIC_ENC, JIC64_DESC, ISA_MIPS64R6; + +let DecoderNamespace = "Mips32r6_64r6_GP64" in { +// Jump and Branch Instructions +def JIALC64 : JIALC_ENC, JIALC64_DESC, ISA_MIPS64R6, GPR_64; +def JIC64 : JIC_ENC, JIC64_DESC, ISA_MIPS64R6, GPR_64; + +def BEQC64 : BEQC_ENC, BEQC64_DESC, ISA_MIPS64R6, GPR_64; +def BEQZC64 : BEQZC_ENC, BEQZC64_DESC, ISA_MIPS64R6, GPR_64; +def BGEC64 : BGEC_ENC, BGEC64_DESC, ISA_MIPS64R6, GPR_64; +def BGEUC64 : BGEUC_ENC, BGEUC64_DESC, ISA_MIPS64R6, GPR_64; +def BGTZC64 : BGTZC_ENC, BGTZC64_DESC, ISA_MIPS64R6, GPR_64; +def BLEZC64 : BLEZC_ENC, BLEZC64_DESC, ISA_MIPS64R6, GPR_64; +def BLTC64 : BLTC_ENC, BLTC64_DESC, ISA_MIPS64R6, GPR_64; +def BLTUC64 : BLTUC_ENC, BLTUC64_DESC, ISA_MIPS64R6, GPR_64; +def BNEC64 : BNEC_ENC, BNEC64_DESC, ISA_MIPS64R6, GPR_64; +def BNEZC64 : BNEZC_ENC, BNEZC64_DESC, ISA_MIPS64R6, GPR_64; +} +let DecoderNamespace = "Mips32r6_64r6_BranchZero" in { +def BLTZC64 : BLTZC_ENC, BLTZC64_DESC, ISA_MIPS64R6, GPR_64; +def BGEZC64 : BGEZC_ENC, BGEZC64_DESC, ISA_MIPS64R6, GPR_64; } + //===----------------------------------------------------------------------===// // // Instruction Aliases Index: lib/Target/Mips/MipsInstrInfo.cpp =================================================================== --- lib/Target/Mips/MipsInstrInfo.cpp +++ lib/Target/Mips/MipsInstrInfo.cpp @@ -334,6 +334,22 @@ return Mips::BLTUC; case Mips::BLTZ: return Mips::BLTZC; + case Mips::BEQ64: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; + return Mips::BEQC64; + case Mips::BNE64: + if (I->getOperand(0).getReg() == I->getOperand(1).getReg()) + return 0; + return Mips::BNEC64; + case Mips::BGTZ64: + return Mips::BGTZC64; + case Mips::BGEZ64: + return Mips::BGEZC64; + case Mips::BLTZ64: + return Mips::BLTZC64; + case Mips::BLEZ64: + return Mips::BLEZC64; // For MIPSR6, the instruction 'jic' can be used for these cases. Some // tools will accept 'jrc reg' as an alias for 'jic 0, $reg'. case Mips::JR: @@ -396,7 +412,7 @@ MachineBasicBlock::iterator I) const { MachineInstrBuilder MIB; - // Certain branches have two forms: e.g beq $1, $zero, dst vs beqz $1, dest + // Certain branches have two forms: e.g beq $1, $zero, dest vs beqz $1, dest // Pick the zero form of the branch for readable assembly and for greater // branch distance in non-microMIPS mode. // FIXME: Certain atomic sequences on mips64 generate 32bit references to @@ -422,6 +438,12 @@ case Mips::BLTC: NewOpc = Mips::BLTZC; break; + case Mips::BEQC64: + NewOpc = Mips::BEQZC64; + break; + case Mips::BNEC64: + NewOpc = Mips::BNEZC64; + break; } } Index: lib/Target/Mips/MipsSEInstrInfo.cpp =================================================================== --- lib/Target/Mips/MipsSEInstrInfo.cpp +++ lib/Target/Mips/MipsSEInstrInfo.cpp @@ -428,6 +428,18 @@ case Mips::BGEZC: return Mips::BLTZC; case Mips::BLTZC: return Mips::BGEZC; case Mips::BLEZC: return Mips::BGTZC; + case Mips::BEQZC64: return Mips::BNEZC64; + case Mips::BNEZC64: return Mips::BEQZC64; + case Mips::BEQC64: return Mips::BNEC64; + case Mips::BNEC64: return Mips::BEQC64; + case Mips::BGEC64: return Mips::BLTC64; + case Mips::BGEUC64: return Mips::BLTUC64; + case Mips::BLTC64: return Mips::BGEC64; + case Mips::BLTUC64: return Mips::BGEUC64; + case Mips::BGTZC64: return Mips::BLEZC64; + case Mips::BGEZC64: return Mips::BLTZC64; + case Mips::BLTZC64: return Mips::BGEZC64; + case Mips::BLEZC64: return Mips::BGTZC64; } } @@ -506,7 +518,11 @@ 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::BC) ? Opc : 0; + 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 : 0; } void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB, Index: test/CodeGen/Mips/compactbranches/beqc-bnec-register-constraint.ll =================================================================== --- test/CodeGen/Mips/compactbranches/beqc-bnec-register-constraint.ll +++ test/CodeGen/Mips/compactbranches/beqc-bnec-register-constraint.ll @@ -1,4 +1,6 @@ ; RUN: llc -march=mips -mcpu=mips32r6 -O1 -start-after=dwarfehprepare < %s | FileCheck %s +; RUN: llc -march=mips64 -mcpu=mips64r6 -O1 -start-after=dwarfehprepare < %s | FileCheck %s + ; beqc/bnec have the constraint that $rs < $rt && $rs != 0 && $rt != 0 ; Cases where $rs == 0 and $rt != 0 should be transformed into beqzc/bnezc. @@ -12,6 +14,7 @@ ; may simplify out the crucical bnec $4, $4 instruction. define internal void @_ZL14TestRemoveLastv(i32* %alist.sroa.0.4) { +; CHECK-LABEL: _ZL14TestRemoveLastv entry: %ascevgep = getelementptr i32, i32* %alist.sroa.0.4, i64 99 br label %do.body121 @@ -46,6 +49,43 @@ br i1 %alnot151, label %for.cond117, label %if.then143, !prof !11 } + +define internal void @_ZL14TestRemoveLastv64(i64* %alist.sroa.0.4) { +; CHECK-LABEL: _ZL14TestRemoveLastv64 +entry: + %ascevgep = getelementptr i64, i64* %alist.sroa.0.4, i64 99 + br label %do.body121 + +for.cond117: + %alsr.iv.next = add nsw i64 %alsr.iv, -1 + %ascevgep340 = getelementptr i64, i64* %alsr.iv339, i64 -1 + %acmp118 = icmp sgt i64 %alsr.iv.next, 0 + br i1 %acmp118, label %do.body121, label %if.then143 + +do.body121: + %alsr.iv339 = phi i64* [ %ascevgep, %entry ], [ %ascevgep340, %for.cond117 ] + %alsr.iv = phi i64 [ 100, %entry ], [ %alsr.iv.next, %for.cond117 ] + %a9 = add i64 %alsr.iv, -1 + %alnot124 = icmp eq i64 %alsr.iv, %alsr.iv + br i1 %alnot124, label %do.body134, label %if.then143, !prof !11 + +do.body134: + %a10 = add i64 %alsr.iv, -1 + %a11 = load i64, i64* %alsr.iv339, align 4, !tbaa !5 +; CHECK-NOT: bnec $[[R0:[0-9]+]], $[[R0]] +; CHECK-NOT: beqc $[[R1:[0-9]+]], $[[R1]] + %alnot137 = icmp eq i64 %a9, %a11 + br i1 %alnot137, label %do.end146, label %if.then143, !prof !11 + +if.then143: + ret void + unreachable + +do.end146: + %alnot151 = icmp eq i64 %a9, %a10 + br i1 %alnot151, label %for.cond117, label %if.then143, !prof !11 + +} !3 = !{!"omnipotent char", !4, i64 0} !4 = !{!"Simple C++ TBAA"} !5 = !{!6, !6, i64 0} Index: test/CodeGen/Mips/compactbranches/compact-branches-64.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/compactbranches/compact-branches-64.ll @@ -0,0 +1,205 @@ +; RUN: llc -march=mipsel -mcpu=mips64r6 -disable-mips-delay-filler < %s | FileCheck %s -check-prefix=PIC + +; Function Attrs: nounwind +define void @l() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() +; PIC: jalrc $25 + %call1 = tail call i64 @j() + %cmp = icmp eq i64 %call, %call1 +; CHECK: bnec + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext -2) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +declare i64 @k() + +declare i64 @j() + +declare void @f(i64 signext) + +; Function Attrs: define void @l2() { +define void @l2() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() +; PIC: jalrc $25 + %call1 = tail call i64 @i() + %cmp = icmp eq i64 %call, %call1 +; CHECK beqc + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext -1) + br label %if.end + +if.end: ; preds = %entry, %if.then +; CHECK: jrc $ra + ret void +} + +declare i64 @i() + +; Function Attrs: nounwind +define void @l3() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() + %cmp = icmp slt i64 %call, 0 +; CHECK : bgez + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext 0) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +; Function Attrs: nounwind +define void @l4() { +entry: + %call = tail call i64 @k() + %cmp = icmp slt i64 %call, 1 +; CHECK: bgtzc + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal + tail call void @f(i64 signext 1) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +; Function Attrs: nounwind +define void @l5() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() +; PIC: jalrc $25 + %cmp = icmp sgt i64 %call, 0 +; CHECK: blezc + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext 2) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +; Function Attrs: nounwind +define void @l6() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() +; PIC: jalrc $25 + %cmp = icmp sgt i64 %call, -1 +; CHECK: bltzc + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext 3) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +; Function Attrs: nounwind +define void @l7() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() + %cmp = icmp eq i64 %call, 0 +; CHECK: bnezc + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext 4) + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret void +} + +; Function Attrs: nounwind +define void @l8() { +entry: +; PIC: jalrc $25 + %call = tail call i64 @k() + %cmp = icmp eq i64 %call, 0 +; CHECK: beqzc + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %entry: +; STATIC: nop +; STATIC: jal +; PIC: jalrc $25 + tail call void @f(i64 signext 5) + br label %if.end + +if.end: ; preds = %entry, %if.then +; CHECK: jrc $ra + ret void +} + +define i64 @l9(i8* ()* %i) { +entry: + %i.addr = alloca i8* ()*, align 4 + store i8* ()* %i, i8* ()** %i.addr, align 4 +; STATIC64: jal +; STATIC64: nop +; PIC: jalrc $25 + %call = call i64 @k() +; PIC: jalrc $25 + %cmp = icmp ne i64 %call, 0 +; CHECK: beqzc + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %0 = load i8* ()*, i8* ()** %i.addr, align 4 +; CHECK: jalrc $25 + %call1 = call i8* %0() + br label %if.end + +if.end: ; preds = %if.then, %entry +; CHECK: jrc $ra + ret i64 -1 +} Index: test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll =================================================================== --- test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll +++ test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll @@ -1,5 +1,8 @@ ; 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 +; RUN: llc -march=mipsel -mcpu=mips64r6 -disable-mips-delay-filler < %s | FileCheck %s +; RUN: llc -march=mips -mcpu=mips64r6 -disable-mips-delay-filler < %s -filetype=obj -o - | llvm-objdump -arch=mips -mcpu=mips64r6 -d - | FileCheck %s -check-prefix=ENCODING + ; bnezc and beqzc have restriction that $rt != 0 @@ -50,3 +53,49 @@ ret i32 0 } +define i64 @f3() { +; CHECK-LABEL: f +; CHECK-NOT: bnezc $0 + + %cmp = icmp eq i64 1, 1 + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i64 1 + + if.end: + ret i64 0 +} + +define i64 @f4() { +; CHECK-LABEL: f1 +; CHECK-NOT: beqzc $0 + + %cmp = icmp eq i64 0, 0 + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i64 1 + + if.end: + ret i64 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 i64 @f5(i64 %a, i64 %b) { +; ENCODING-LABEL: f2 +; ENCODING-NOT: beqc $5, $4 +; ENCODING-NOT: bnec $5, $4 + + %cmp = icmp eq i64 %b, %a + br i1 %cmp, label %if.then, label %if.end + + if.then: + ret i64 1 + + if.end: + ret i64 0 +}