diff options
Diffstat (limited to 'lib/Target/PowerPC/PPC32ISelSimple.cpp')
-rw-r--r-- | lib/Target/PowerPC/PPC32ISelSimple.cpp | 191 |
1 files changed, 169 insertions, 22 deletions
diff --git a/lib/Target/PowerPC/PPC32ISelSimple.cpp b/lib/Target/PowerPC/PPC32ISelSimple.cpp index e5f5728585..a49f2538e1 100644 --- a/lib/Target/PowerPC/PPC32ISelSimple.cpp +++ b/lib/Target/PowerPC/PPC32ISelSimple.cpp @@ -33,6 +33,7 @@ using namespace llvm; namespace { Statistic<> GEPFolds("ppc-codegen", "Number of GEPs folded"); + Statistic<> NumSetCC("ppc-codegen", "Number of SetCC straight-lined"); /// TypeClass - Used by the PowerPC backend to group LLVM types by their basic /// PPC Representation. @@ -280,6 +281,10 @@ namespace { abort(); } + unsigned ExtendOrClear(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned Reg, const Type *CompTy); + /// promote32 - Make a value 32-bits wide, and put it somewhere. /// void promote32(unsigned targetReg, const ValueRecord &VR); @@ -959,36 +964,43 @@ void ISel::emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, BuildMI(*MBB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(LHS).addReg(RHS); } -/// EmitComparison - emits a comparison of the two operands, returning the -/// extended setcc code to use. The result is in CR0. -/// -unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, - MachineBasicBlock *MBB, - MachineBasicBlock::iterator IP) { - // The arguments are already supposed to be of the same type. - const Type *CompTy = Op0->getType(); +unsigned ISel::ExtendOrClear(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned Reg, const Type *CompTy) { unsigned Class = getClassB(CompTy); - unsigned Op0r = getReg(Op0, MBB, IP); - // Before we do a comparison, we have to make sure that we're truncating our - // registers appropriately. + // Before we do a comparison or SetCC, we have to make sure that we truncate + // the source registers appropriately. if (Class == cByte) { unsigned TmpReg = makeAnotherReg(CompTy); if (CompTy->isSigned()) - BuildMI(*MBB, IP, PPC::EXTSB, 1, TmpReg).addReg(Op0r); + BuildMI(*MBB, IP, PPC::EXTSB, 1, TmpReg).addReg(Reg); else - BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Reg).addImm(0) .addImm(24).addImm(31); - Op0r = TmpReg; + Reg = TmpReg; } else if (Class == cShort) { unsigned TmpReg = makeAnotherReg(CompTy); if (CompTy->isSigned()) - BuildMI(*MBB, IP, PPC::EXTSH, 1, TmpReg).addReg(Op0r); + BuildMI(*MBB, IP, PPC::EXTSH, 1, TmpReg).addReg(Reg); else - BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Reg).addImm(0) .addImm(16).addImm(31); - Op0r = TmpReg; + Reg = TmpReg; } + return Reg; +} + +/// EmitComparison - emits a comparison of the two operands, returning the +/// extended setcc code to use. The result is in CR0. +/// +unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, + MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP) { + // The arguments are already supposed to be of the same type. + const Type *CompTy = Op0->getType(); + unsigned Class = getClassB(CompTy); + unsigned Op0r = ExtendOrClear(MBB, IP, getReg(Op0, MBB, IP), CompTy); // Use crand for lt, gt and crandc for le, ge unsigned CROpcode = (OpNum == 2 || OpNum == 4) ? PPC::CRAND : PPC::CRANDC; @@ -1098,13 +1110,148 @@ void ISel::visitSetCondInst(SetCondInst &I) { if (canFoldSetCCIntoBranchOrSelect(&I)) return; + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + const Type *Ty = Op0->getType(); + unsigned Class = getClassB(Ty); + unsigned Opcode = I.getOpcode(); unsigned DestReg = getReg(I); - unsigned OpNum = I.getOpcode(); - const Type *Ty = I.getOperand (0)->getType(); - EmitComparison(OpNum, I.getOperand(0), I.getOperand(1), BB, BB->end()); + // If the comparison type is byte, short, or int, then we can emit a + // branchless version of the SetCC that puts 0 (false) or 1 (true) in the + // destination register. + if (Class <= cInt) { + ++NumSetCC; + MachineBasicBlock::iterator MI = BB->end(); + unsigned OpNum = getSetCCNumber(Opcode); + unsigned Op0Reg = getReg(Op0, BB, MI); + Op0Reg = ExtendOrClear(BB, MI, Op0Reg, Ty); + + // comparisons against constant zero often have shorter sequences than the + // general case, handled below. + ConstantInt *CI = dyn_cast<ConstantInt>(Op1); + if (CI && CI->getRawValue() == 0) { + switch(OpNum) { + case 0: { // eq0 + unsigned TempReg = makeAnotherReg(Type::IntTy); + BuildMI(*BB, MI, PPC::CNTLZW, 1, TempReg).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(TempReg).addImm(5); + break; + } + case 1: { // ne0 + unsigned TempReg = makeAnotherReg(Type::IntTy); + BuildMI(*BB, MI, PPC::ADDIC, 2, TempReg).addReg(Op0Reg).addSImm(-1); + BuildMI(*BB, MI, PPC::SUBFE, 2, DestReg).addReg(TempReg).addReg(Op0Reg); + break; + } + case 2: { // lt0, always false if unsigned + if (Ty->isSigned()) + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(Op0Reg).addImm(31); + else + BuildMI(*BB, MI, PPC::LI, 1, DestReg).addSImm(0); + break; + } + case 3: { // ge0, always true if unsigned + if (Ty->isSigned()) { + unsigned TempReg = makeAnotherReg(Type::IntTy); + BuildMI(*BB, MI, PPC::SRWI, 2, TempReg).addReg(Op0Reg).addImm(31); + BuildMI(*BB, MI, PPC::XORI, 2, DestReg).addReg(TempReg).addImm(1); + } else { + BuildMI(*BB, MI, PPC::LI, 1, DestReg).addSImm(1); + } + break; + } + case 4: { // gt0, equivalent to ne0 if unsigned + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + if (Ty->isSigned()) { + BuildMI(*BB, MI, PPC::NEG, 2, Temp1).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::ANDC, 2, Temp2).addReg(Temp1).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(Temp2).addImm(31); + } else { + BuildMI(*BB, MI, PPC::ADDIC, 2, Temp1).addReg(Op0Reg).addSImm(-1); + BuildMI(*BB, MI, PPC::SUBFE, 2, DestReg).addReg(Temp1).addReg(Op0Reg); + } + break; + } + case 5: { // le0, equivalent to eq0 if unsigned + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + if (Ty->isSigned()) { + BuildMI(*BB, MI, PPC::NEG, 2, Temp1).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::ORC, 2, Temp2).addReg(Op0Reg).addReg(Temp1); + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(Temp2).addImm(31); + } else { + BuildMI(*BB, MI, PPC::CNTLZW, 1, Temp1).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(Temp1).addImm(5); + } + break; + } + } // switch + return; + } + unsigned Op1Reg = getReg(Op1, BB, MI); + switch(OpNum) { + case 0: { // eq + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + BuildMI(*BB, MI, PPC::SUBF, 2, Temp1).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, MI, PPC::CNTLZW, 1, Temp2).addReg(Temp1); + BuildMI(*BB, MI, PPC::SRWI, 2, DestReg).addReg(Temp2).addImm(5); + break; + } + case 1: { // ne + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + BuildMI(*BB, MI, PPC::SUBF, 2, Temp1).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, MI, PPC::ADDIC, 2, Temp2).addReg(Temp1).addSImm(-1); + BuildMI(*BB, MI, PPC::SUBFE, 2, DestReg).addReg(Temp2).addReg(Temp1); + break; + } + case 2: + case 4: { // lt, gt + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + unsigned Temp3 = makeAnotherReg(Type::IntTy); + unsigned Temp4 = makeAnotherReg(Type::IntTy); + if (OpNum == 4) std::swap(Op0Reg, Op1Reg); + if (Ty->isSigned()) { + BuildMI(*BB, MI, PPC::SUBFC, 2, Temp1).addReg(Op1Reg).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::EQV, 2, Temp2).addReg(Op1Reg).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::SRWI, 2, Temp3).addReg(Temp2).addImm(31); + BuildMI(*BB, MI, PPC::ADDZE, 1, Temp4).addReg(Temp3); + BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(Temp4).addImm(0) + .addImm(31).addImm(31); + } else { + BuildMI(*BB, MI, PPC::SUBFC, 2, Temp1).addReg(Op1Reg).addReg(Op0Reg); + BuildMI(*BB, MI, PPC::SUBFE, 2, Temp2).addReg(Temp1).addReg(Temp1); + BuildMI(*BB, MI, PPC::NEG, 2, DestReg).addReg(Temp2); + } + break; + } + case 3: + case 5: { // le, ge + unsigned Temp1 = makeAnotherReg(Type::IntTy); + unsigned Temp2 = makeAnotherReg(Type::IntTy); + unsigned Temp3 = makeAnotherReg(Type::IntTy); + if (OpNum == 3) std::swap(Op0Reg, Op1Reg); + if (Ty->isSigned()) { + BuildMI(*BB, MI, PPC::SRWI, 2, Temp1).addReg(Op0Reg).addImm(31); + BuildMI(*BB, MI, PPC::SRAWI, 2, Temp2).addReg(Op1Reg).addImm(31); + BuildMI(*BB, MI, PPC::SUBFC, 2, Temp3).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, MI, PPC::ADDE, 2, DestReg).addReg(Temp2).addReg(Temp1); + } else { + BuildMI(*BB, MI, PPC::LI, 1, Temp2).addSImm(-1); + BuildMI(*BB, MI, PPC::SUBFC, 2, Temp1).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, MI, PPC::SUBFZE, 1, DestReg).addReg(Temp2); + } + break; + } + } // switch + return; + } + EmitComparison(Opcode, Op0, Op1, BB, BB->end()); - unsigned Opcode = getPPCOpcodeForSetCCNumber(OpNum); + unsigned PPCOpcode = getPPCOpcodeForSetCCNumber(Opcode); MachineBasicBlock *thisMBB = BB; const BasicBlock *LLVM_BB = BB->getBasicBlock(); ilist<MachineBasicBlock>::iterator It = BB; @@ -1121,7 +1268,7 @@ void ISel::visitSetCondInst(SetCondInst &I) { // bCC. But MBB->getFirstTerminator() can't understand this. MachineBasicBlock *copy1MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy1MBB); - BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); + BuildMI(BB, PPCOpcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy0MBB); BuildMI(BB, PPC::B, 1).addMBB(copy0MBB); |