Index: llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp +++ llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" @@ -48,14 +49,37 @@ const TargetInstrInfo *TII; +private: + const MachineBranchProbabilityInfo *MBPI; + + // The old branch instruction BranchMI in \pPI will be earsed. we need to + // create a new basic block if the \pNeedCreateNewMBB is true, since a + // non-terminator is not allowed after a terminator. + void removeAndSplice(MachineBasicBlock::pred_iterator PI, + MachineBasicBlock::iterator &BranchMI, + const MachineBasicBlock &ReturnMBB, + bool NeedCreateNewMBB); + protected: bool processBlock(MachineBasicBlock &ReturnMBB) { bool Changed = false; MachineBasicBlock::iterator I = ReturnMBB.begin(); I = ReturnMBB.SkipPHIsLabelsAndDebug(I); + MachineBasicBlock::iterator LIInst = NULL; + + // The block must be either essentially empty except for the blr or + // (li r3, Imm) + blr. + if (I != ReturnMBB.end() && + ((I->getOpcode() == PPC::LI && + I->getOperand(0).getReg() == PPC::R3) || + (I->getOpcode() == PPC::LI8 && + I->getOperand(0).getReg() == PPC::X3))) { + LIInst = I++; + I = ReturnMBB.SkipPHIsLabelsAndDebug(I); + } - // The block must be essentially empty except for the blr. + // Check the last instruction blr. if (I == ReturnMBB.end() || (I->getOpcode() != PPC::BLR && I->getOpcode() != PPC::BLR8) || I != ReturnMBB.getLastNonDebugInstr()) @@ -75,18 +99,42 @@ if (J->getOpcode() == PPC::B) { if (J->getOperand(0).getMBB() == &ReturnMBB) { + + bool NeedCreateNewMBB = false; + if (LIInst != NULL) { + if ((*PI)->getFirstTerminator() != J) { + // If the branch instruction is not the first terminator and + // ReturnMBB is (li r3, Imm) + blr, we should create a new + // MachineBasicBlock, because the non-terminator can't be + // after the terminator for a MachineBasicBlock. + NeedCreateNewMBB = true; + } + + BuildMI(**PI, J, J->getDebugLoc(), + TII->get(LIInst->getOpcode()), + LIInst->getOperand(0).getReg()) + .addImm(LIInst->getOperand(1).getImm()); + } + // This is an unconditional branch to the return. Replace the // branch with a blr. BuildMI(**PI, J, J->getDebugLoc(), TII->get(I->getOpcode())) .copyImplicitOps(*I); - MachineBasicBlock::iterator K = J--; - K->eraseFromParent(); + BlockChanged = true; + removeAndSplice(PI, J, ReturnMBB, NeedCreateNewMBB); + ++NumBLR; continue; } } else if (J->getOpcode() == PPC::BCC) { if (J->getOperand(2).getMBB() == &ReturnMBB) { + // It's complex to do the EarlyRet, we do nothing. + if (LIInst != NULL) { + --J; + continue; + } + // This is a conditional branch to the return. Replace the branch // with a bclr. BuildMI(**PI, J, J->getDebugLoc(), TII->get(PPC::BCCLR)) @@ -101,6 +149,11 @@ } } else if (J->getOpcode() == PPC::BC || J->getOpcode() == PPC::BCn) { if (J->getOperand(1).getMBB() == &ReturnMBB) { + if (LIInst != NULL) { + --J; + continue; + } + // This is a conditional branch to the return. Replace the branch // with a bclr. BuildMI( @@ -180,6 +233,7 @@ if (MF.size() < 2) return Changed; + MBPI = &getAnalysis(); // We can't use a range-based for loop due to clobbering the iterator. for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E;) { MachineBasicBlock &B = *I++; @@ -195,6 +249,7 @@ } void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } }; @@ -206,3 +261,69 @@ char PPCEarlyReturn::ID = 0; FunctionPass* llvm::createPPCEarlyReturnPass() { return new PPCEarlyReturn(); } + +// The old branch instruction BranchMI in \pPI will be earsed. we need to create +// a new basic block if the \pNeedCreateNewMBB is true, since a non-terminator +// is not allowed after a terminator. +void PPCEarlyReturn::removeAndSplice( + MachineBasicBlock::pred_iterator PI, + MachineBasicBlock::iterator &BranchMI, + const MachineBasicBlock &ReturnMBB, + bool NeedCreateNewMBB) { + // Below is an example when the branch instruction is the first terminator: + // + // # %bb.0: | # %bb.0: + // ... | ... + // | li 3, 100 + // b ReturnMBB | blr + // # %bb.1: ====> | # %bb.1: + // ... | ... + // ReturnMBB: | ReturnMBB: + //ReturnMBB li 3, 100 | li 3, 100 + // blr | blr + MachineBasicBlock::iterator K = BranchMI--; + K->eraseFromParent(); + + if (NeedCreateNewMBB) { + // Create a new MachineBasicBlock for (li r3, Imm) + blr, if the branch + // instruction we want EarlyRet is not the last terminator. + // + // Below is an example for (li r3, Imm) + blr. + // # %bb.0: | # %bb.0: + // ... | ... + // bne 0, .LBB1 | bne 0, .LBB1 + // | .LBB2 + // | li 3, 100 + // b ReturnMBB | blr + // # %bb.1: ====> | # %bb.1: + // ... | ... + // ReturnMBB: | ReturnMBB: + // li 3, 100 | li 3, 100 + // blr | blr + // .LBB1 | .LBB1 + // ... | ... + MachineFunction *MF = (*PI)->getParent(); + MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(); + MF->insert(std::next(MachineFunction::iterator(*PI)), NMBB); + + MachineBasicBlock *SuccPI = (*PI)->getFallThrough(); + if (SuccPI) { + (*PI)->replaceSuccessor(SuccPI, NMBB); + BranchProbability ProbNMBBToSuccPI = + MBPI ? BranchProbability::getUnknown() : + MBPI->getEdgeProbability(*PI, SuccPI); + + NMBB->addSuccessor(SuccPI, ProbNMBBToSuccPI); + } else { + BranchProbability ProbPIToNMBB = + MBPI ? BranchProbability::getUnknown() : + MBPI->getEdgeProbability(*PI, &ReturnMBB); + + (*PI)->addSuccessor(NMBB, ProbPIToNMBB); + } + + // Move the (li r3, Imm) + blr to the new MachineBasicBlock. + NMBB->splice(NMBB->end(), (*PI), (--BranchMI)--, (*PI)->end()); + } +} + Index: llvm/test/CodeGen/PowerPC/early-ret.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/early-ret.mir @@ -0,0 +1,104 @@ +# RUN: llc -mtriple powerpc64le-unknown-linux-gnu -run-pass ppc-early-ret -o - %s -verify-machineinstrs | FileCheck %s + +--- | + ; ModuleID = 'early-ret.ll' + source_filename = "early-ret.ll" + target datalayout = "e-m:e-i64:64-n32:64" + target triple = "powerpc64le-unknown-linux-gnu" + + define i1 @EarlyRet1(double %t0) { + entry: + %t1 = fcmp oge double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + + bad: ; preds = %entry + ret i1 false + + good: ; preds = %entry + ret i1 true + } + +... +--- +name: EarlyRet1 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: [] +liveins: + - { reg: '$f1', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.0.entry: + successors: %bb.2(0x40000000), %bb.1(0x40000000) + liveins: $f1 + + renamable $f0 = XXLXORdpz + renamable $cr7 = XSCMPUDP renamable $f1, killed renamable $f0, implicit $rm + renamable $r3 = MFOCRF killed $cr7 + renamable $r3 = RLWINM killed renamable $r3, 29, 31, 31 + renamable $r3 = XORI killed renamable $r3, 1 + renamable $cr7 = XSCMPUDP renamable $f1, killed renamable $f1, implicit $rm + renamable $r4 = MFOCRF killed $cr7 + renamable $r4 = RLWINM killed renamable $r4, 0, 31, 31 + renamable $r4 = XORI killed renamable $r4, 1 + renamable $r3 = AND killed renamable $r3, killed renamable $r4 + renamable $cr0 = CMPLWI killed renamable $r3, 0 + BCC 68, killed renamable $cr0, %bb.2 + B %bb.1 + + ; CHECK-LABEL: name: EarlyRet1 + ; + ; The last unconditional branch instruction shoud have been removed. + ; CHECK: bb.0.entry: + ; CHECK: renamable $cr0 = CMPLWI killed renamable $r3, 0 + ; CHECK: BCC 68, killed renamable $cr0, %bb.2 + ; CHECK-NOT: B + + bb.1.bad: + renamable $x3 = LI8 0 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + + ; The bb.1.bad should have been removed, and a new BasicBlock bb.3 should be created. + ; CHECK-NOT: bb.1.bad: + ; CHECK: bb.3: + ; CHECK: $x3 = LI8 0 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit $lr8, implicit $rm, implicit killed $x3 + + bb.2.good: + renamable $x3 = LI8 -1 + BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + + ; bb.2.good should not be modified. + ; CHECK: bb.2.good: + ; CHECK: renamable $x3 = LI8 -1 + ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 + +...