Index: lib/Target/PowerPC/PPCMIPeephole.cpp =================================================================== --- lib/Target/PowerPC/PPCMIPeephole.cpp +++ lib/Target/PowerPC/PPCMIPeephole.cpp @@ -27,6 +27,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" +#include "MCTargetDesc/PPCPredicates.h" using namespace llvm; @@ -56,6 +57,9 @@ // Perform peepholes. bool simplifyCode(void); + // Perform peepholes. + bool eliminateRedundantCompare(void); + // Find the "true" register represented by SrcReg (following chains // of copies and subreg_to_reg operations). unsigned lookThruCopyLike(unsigned SrcReg); @@ -346,6 +350,296 @@ } } + // We try to eliminate redundant compare instruction. + Simplified |= eliminateRedundantCompare(); + + return Simplified; +} + +// helper functions for eliminateRedundantCompare +static bool isEqOrNe(MachineInstr *BI) { + PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm(); + unsigned PredCond = PPC::getPredicateCondition(Pred); + return (PredCond == PPC::PRED_EQ || PredCond == PPC::PRED_NE); +} + +static bool isSupportedCmpOp(unsigned opCode) { + return (opCode == PPC::CMPLD || opCode == PPC::CMPD || + opCode == PPC::CMPLW || opCode == PPC::CMPW || + opCode == PPC::CMPLDI || opCode == PPC::CMPDI || + opCode == PPC::CMPLWI || opCode == PPC::CMPWI); +} + +static bool is64bitCmpOp(unsigned opCode) { + return (opCode == PPC::CMPLD || opCode == PPC::CMPD || + opCode == PPC::CMPLDI || opCode == PPC::CMPDI); +} + +static bool isSignedCmpOp(unsigned opCode) { + return (opCode == PPC::CMPD || opCode == PPC::CMPW || + opCode == PPC::CMPDI || opCode == PPC::CMPWI); +} + +static unsigned getSignedCmpOpCode(unsigned opCode) { + if (opCode == PPC::CMPLD) return PPC::CMPD; + if (opCode == PPC::CMPLW) return PPC::CMPW; + if (opCode == PPC::CMPLDI) return PPC::CMPDI; + if (opCode == PPC::CMPLWI) return PPC::CMPWI; + return opCode; +} + +// We can decrement immediate x in (GE x) by changing it to (GT x-1) or +// (LT x) to (LE x-1) +static unsigned getPredicateToDecImm(MachineInstr *BI, MachineInstr *CMPI) { + uint64_t Imm = CMPI->getOperand(2).getImm(); + bool SignedCmp = isSignedCmpOp(CMPI->getOpcode()); + if ((!SignedCmp && Imm == 0) || (SignedCmp && Imm == 0x8000)) + return 0; + + PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm(); + unsigned PredCond = PPC::getPredicateCondition(Pred); + unsigned PredHint = PPC::getPredicateHint(Pred); + if (PredCond == PPC::PRED_GE) + return PPC::getPredicate(PPC::PRED_GT, PredHint); + if (PredCond == PPC::PRED_LT) + return PPC::getPredicate(PPC::PRED_LE, PredHint); + + return 0; +} + +// We can increment immediate x in (GT x) by changing it to (GE x+1) or +// (LE x) to (LT x+1) +static unsigned getPredicateToIncImm(MachineInstr *BI, MachineInstr *CMPI) { + uint64_t Imm = CMPI->getOperand(2).getImm(); + bool SignedCmp = isSignedCmpOp(CMPI->getOpcode()); + if ((!SignedCmp && Imm == 0xFFFF) || (SignedCmp && Imm == 0x7FFF)) + return 0; + + PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm(); + unsigned PredCond = PPC::getPredicateCondition(Pred); + unsigned PredHint = PPC::getPredicateHint(Pred); + if (PredCond == PPC::PRED_GT) + return PPC::getPredicate(PPC::PRED_GE, PredHint); + if (PredCond == PPC::PRED_LE) + return PPC::getPredicate(PPC::PRED_LT, PredHint); + + return 0; +} + +static bool eligibleForCompareElimination(MachineBasicBlock &MBB, + MachineRegisterInfo *MRI) { + + auto isEligibleBB = [&](MachineBasicBlock &BB) { + auto BII = BB.getFirstInstrTerminator(); + if (BB.succ_size() == 2 && + BII != BB.instr_end() && + ((*BII).getOpcode() == PPC::BCC || (*BII).getOpcode() == PPC::BCCLR) && + (*BII).getOperand(1).isReg()) { + unsigned CndReg = (*BII).getOperand(1).getReg(); + if (!TargetRegisterInfo::isVirtualRegister(CndReg) || + !MRI->hasOneNonDBGUse(CndReg)) + return false; + + MachineInstr *CMPI = MRI->getVRegDef(CndReg); + for (MachineOperand &MO : CMPI->operands()) + if (MO.isReg() && !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return false; + + return true; + } + return false; + }; + + if (MBB.pred_size() != 1) + return false; + + MachineBasicBlock *PredMBB = *MBB.pred_begin(); + if (isEligibleBB(MBB) && isEligibleBB(*PredMBB)) + return true; + + return false; +} + +// If multiple conditional branches are executed based on the (essentially) +// same comparison, we merge compare instructions into one and make multiple +// conditional branches on this comparison. +// For example, +// if (a == 0) { ... } +// else if (a < 0) { ... } +// can be executed by one compare and two conditional branches instead of +// two pairs of a compare and a conditional branch. +// +// This method merges two compare instructions in two MBBs and modifies the +// compare and conditional branch instructions if needed. +// For the above example, the input for this pass looks like: +// cmplwi r3, 0 +// beq 0, .LBB0_3 +// cmpwi r3, -1 +// bgt 0, .LBB0_4 +// So, before merging two compares, we need to modify these instructions as +// cmpwi r3, 0 ; cmplwi and cmpwi yield same result for beq +// beq 0, .LBB0_3 +// cmpwi r3, 0 ; greather than -1 means greater or equal to 0 +// bge 0, .LBB0_4 + +bool PPCMIPeephole::eliminateRedundantCompare(void) { + bool Simplified = false; + + for (MachineBasicBlock &MBB2 : *MF) { + // We only consider two basic blocks MBB1 and MBB2 if + // - both MBBs end with a conditional branch, + // - MBB1 is the only predecessor of MBB2, and + // - compare does not take a physical register as a operand in both MBBs. + if (!eligibleForCompareElimination(MBB2, MRI)) + continue; + + MachineBasicBlock *MBB1 = *MBB2.pred_begin(); + MachineInstr *BI1 = &*MBB1->getFirstInstrTerminator(); + MachineInstr *CMPI1 = MRI->getVRegDef(BI1->getOperand(1).getReg()); + + MachineInstr *BI2 = &*MBB2.getFirstInstrTerminator(); + MachineInstr *CMPI2 = MRI->getVRegDef(BI2->getOperand(1).getReg()); + + // We cannot optimize an unsupported compare opcode or + // a mix of 32-bit and 64-bit comaprisons + if (!isSupportedCmpOp(CMPI1->getOpcode()) || + !isSupportedCmpOp(CMPI2->getOpcode()) || + is64bitCmpOp(CMPI1->getOpcode()) != is64bitCmpOp(CMPI2->getOpcode())) + continue; + + unsigned NewOpCode = 0; + unsigned NewPredicate1 = 0, NewPredicate2 = 0; + int16_t Imm1 = 0, NewImm1 = 0, Imm2 = 0, NewImm2 = 0; + + if (CMPI1->getOpcode() != CMPI2->getOpcode()) { + // Typically, unsigned comparison is used for equality check, but + // we replace it with a signed comparison if the comparison + // to be merged is a signed comparison. + // In other cases of opcode mismatch, we cannot optimize this. + if (isEqOrNe(BI2) && + CMPI1->getOpcode() == getSignedCmpOpCode(CMPI2->getOpcode())) + NewOpCode = CMPI1->getOpcode(); + else if (isEqOrNe(BI1) && + getSignedCmpOpCode(CMPI1->getOpcode()) == CMPI2->getOpcode()) + NewOpCode = CMPI2->getOpcode(); + else continue; + } + + if (CMPI1->getOperand(2).isReg() && CMPI2->getOperand(2).isReg()) { + // In case of comparisons between two registers, these two registers + // must be same to merge two comparisons. + unsigned Cmp1Operand1 = CMPI1->getOperand(1).getReg(); + unsigned Cmp1Operand2 = CMPI1->getOperand(2).getReg(); + unsigned Cmp2Operand1 = CMPI2->getOperand(1).getReg(); + unsigned Cmp2Operand2 = CMPI2->getOperand(2).getReg(); + if (Cmp1Operand1 == Cmp2Operand1 && Cmp1Operand2 == Cmp2Operand2) { + // Same pair of registers in the same order; ready to merge as is. + } + else if (Cmp1Operand1 == Cmp2Operand2 && Cmp1Operand2 == Cmp2Operand1) { + // Same pair of registers in different order. + // We reverse the predicate to merge compare instructions. + PPC::Predicate Pred = (PPC::Predicate)BI2->getOperand(0).getImm(); + NewPredicate2 = (unsigned)PPC::getSwappedPredicate(Pred); + } + else continue; + } + else if (CMPI1->getOperand(2).isImm() && CMPI2->getOperand(2).isImm()){ + // In case of comparisons between a register and an immediate, + // the operand register must be same for two compare instructions. + if (CMPI1->getOperand(1).getReg() != CMPI2->getOperand(1).getReg()) + continue; + + NewImm1 = Imm1 = (int16_t)CMPI1->getOperand(2).getImm(); + NewImm2 = Imm2 = (int16_t)CMPI2->getOperand(2).getImm(); + + // If immediate are not same, we try to adjust by changing predicate; + // e.g. GT imm means GE (imm+1). + if (Imm1 != Imm2 && (!isEqOrNe(BI2) || !isEqOrNe(BI1))) { + int Diff = Imm1 - Imm2; + if (Diff < -2 || Diff > 2) + continue; + + unsigned PredToInc1 = getPredicateToIncImm(BI1, CMPI1); + unsigned PredToDec1 = getPredicateToDecImm(BI1, CMPI1); + unsigned PredToInc2 = getPredicateToIncImm(BI2, CMPI2); + unsigned PredToDec2 = getPredicateToDecImm(BI2, CMPI2); + if (Diff == 2) { + if (PredToInc2 && PredToDec1) { + NewPredicate2 = PredToInc2; + NewPredicate1 = PredToDec1; + NewImm2++; + NewImm1--; + } + } + else if (Diff == 1) { + if (PredToInc2) { + NewImm2++; + NewPredicate2 = PredToInc2; + } + else if (PredToDec1) { + NewImm1--; + NewPredicate1 = PredToDec1; + } + } + else if (Diff == -1) { + if (PredToDec2) { + NewImm2--; + NewPredicate2 = PredToDec2; + } + else if (PredToInc1) { + NewImm1++; + NewPredicate1 = PredToInc1; + } + } + else if (Diff == -2) { + if (PredToDec2 && PredToInc1) { + NewPredicate2 = PredToDec2; + NewPredicate1 = PredToInc1; + NewImm2--; + NewImm1++; + } + } + } + + // We cannnot merge two compares if the immediates are not same. + if (NewImm2 != NewImm1) + continue; + } + + DEBUG(dbgs() << "Optimize two pairs of compare and branch:\n"); + DEBUG(CMPI1->dump()); + DEBUG(BI1->dump()); + DEBUG(CMPI2->dump()); + DEBUG(BI2->dump()); + + // We adjust opcode, predicates and immediate as we determined above. + if (NewOpCode != 0 && NewOpCode != CMPI1->getOpcode()) { + CMPI1->setDesc(TII->get(NewOpCode)); + } + if (NewPredicate1) { + BI1->getOperand(0).setImm(NewPredicate1); + } + if (NewPredicate2) { + BI2->getOperand(0).setImm(NewPredicate2); + } + if (NewImm1 != Imm1) { + CMPI1->getOperand(2).setImm(NewImm1); + } + + // We finally eliminate compare instruction in MBB2. + BI2->getOperand(1).setReg(BI1->getOperand(1).getReg()); + BI2->getOperand(1).setIsKill(true); + BI1->getOperand(1).setIsKill(false); + CMPI2->eraseFromParent(); + + DEBUG(dbgs() << "into a compare and two branches:\n"); + DEBUG(CMPI1->dump()); + DEBUG(BI1->dump()); + DEBUG(BI2->dump()); + + Simplified = true; + } + return Simplified; } Index: test/CodeGen/PowerPC/cmp_elimination.ll =================================================================== --- /dev/null +++ test/CodeGen/PowerPC/cmp_elimination.ll @@ -0,0 +1,720 @@ +; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc64le-unknown-linux-gnu | FileCheck %s + + +define void @func1(i32 signext %a) { +; We should have only one compare instruction +; CHECK-LABEL: @func1 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp slt i32 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func2(i32 signext %a) { +; CHECK-LABEL: @func2 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, 100 + br i1 %cmp1, label %if.end3, label %if.then2 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func3(i32 signext %a) { +; CHECK-LABEL: @func3 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp sgt i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func4(i32 zeroext %a) { +; CHECK-LABEL: @func4 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ult i32 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func5(i32 zeroext %a) { +; CHECK-LABEL: @func5 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, 100 + br i1 %cmp1, label %if.end3, label %if.then2 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func6(i32 zeroext %a) { +; CHECK-LABEL: @func6 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ugt i32 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func7(i64 %a) { +; CHECK-LABEL: @func7 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp slt i64 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func8(i64 %a) { +; CHECK-LABEL: @func8 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, 100 + br i1 %cmp1, label %if.end3, label %if.then2 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func9(i64 %a) { +; CHECK-LABEL: @func9 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp sgt i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func10(i64 %a) { +; CHECK-LABEL: @func10 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ult i64 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func11(i64 %a) { +; CHECK-LABEL: @func11 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, 100 + br i1 %cmp1, label %if.end3, label %if.then2 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func12(i64 %a) { +; CHECK-LABEL: @func12 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ugt i64 %a, 100 + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, 100 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func13(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: @func13 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp slt i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func14(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: @func14 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i32 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func15(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: @func15 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i32 %b, %a + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func16(i32 zeroext %a, i32 zeroext %b) { +; CHECK-LABEL: @func16 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ult i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func17(i32 zeroext %a, i32 zeroext %b) { +; CHECK-LABEL: @func17 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i32 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func18(i32 zeroext %a, i32 zeroext %b) { +; CHECK-LABEL: @func18 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i32 %b, %a + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func19(i64 %a, i64 %b) { +; CHECK-LABEL: @func19 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i64 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp slt i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func20(i64 %a, i64 %b) { +; CHECK-LABEL: @func20 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i64 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp sgt i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func21(i64 %a, i64 %b) { +; CHECK-LABEL: @func21 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i64 %b, %a + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func22(i64 %a, i64 %b) { +; CHECK-LABEL: @func22 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp eq i64 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ult i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func23(i64 %a, i64 %b) { +; CHECK-LABEL: @func23 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i64 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp ugt i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func24(i64 %a, i64 %b) { +; CHECK-LABEL: @func24 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp ult i64 %b, %a + br i1 %cmp, label %if.then, label %if.else + +if.then: + tail call void @dummy1() + br label %if.end3 + +if.else: + %cmp1 = icmp eq i64 %a, %b + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + tail call void @dummy2() + br label %if.end3 + +if.end3: + ret void +} + + +define void @func25(i64 %a, i64 %b) { +; CHECK-LABEL: @func25 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp slt i64 %b, %a + br i1 %cmp, label %if.then, label %if.else, !prof !1 + +if.then: + tail call void @dummy1() + br label %if.end6 + +if.else: + %cmp2 = icmp eq i64 %a, %b + br i1 %cmp2, label %if.then4, label %if.else5 + +if.then4: + tail call void @dummy2() + br label %if.end6 + +if.else5: + tail call void @dummy3() + br label %if.end6 + +if.end6: + ret void +} + + +define void @func26(i32 signext %a) { +; CHECK-LABEL: @func26 +; CHECK: cmp +; CHECK-NOT: cmp +; CHECK: blr +entry: + %cmp = icmp sgt i32 %a, 0 + br i1 %cmp, label %if.then, label %if.else, !prof !2 + +if.then: + tail call void @dummy1() + br label %if.end9 + +if.else: + %cmp2 = icmp eq i32 %a, 0 + br i1 %cmp2, label %if.then7, label %if.else8, !prof !2 + +if.then7: + tail call void @dummy2() + br label %if.end9 + +if.else8: + tail call void @dummy3() + br label %if.end9 + +if.end9: + ret void +} + +@g1 = external local_unnamed_addr global i32, align 4 +@g2 = external local_unnamed_addr global i32, align 4 + +define void @func27(i32 signext %a) { +; CHECK-LABEL: @func27 +; CHECK: cmp +; CHECK: beq +; CHECK-NOT: cmp +; CHECK: bgelr +; CHECK: blr +entry: + %cmp = icmp eq i32 %a, 0 + br i1 %cmp, label %if.end3.sink.split, label %if.else + +if.else: + %cmp1 = icmp slt i32 %a, 0 + br i1 %cmp1, label %if.end3.sink.split, label %if.end + +if.end3.sink.split: + %g2.sink = phi i32* [ @g2, %if.else ], [ @g1, %entry ] + store i32 0, i32* %g2.sink, align 4 + br label %if.end + +if.end: + ret void +} + +declare void @dummy1() +declare void @dummy2() +declare void @dummy3() + +!1 = !{!"branch_weights", i32 2000, i32 1} +!2 = !{!"branch_weights", i32 1, i32 2000}