Index: lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- lib/Target/PowerPC/PPCISelLowering.cpp +++ lib/Target/PowerPC/PPCISelLowering.cpp @@ -3388,6 +3388,7 @@ if (GPR_idx != Num_GPR_Regs) { unsigned VReg = MF.addLiveIn(GPR[GPR_idx++], &PPC::G8RCRegClass); + FuncInfo->addLiveInAttr(VReg, Flags); SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT); SDValue Store; @@ -3422,6 +3423,7 @@ break; unsigned VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::G8RCRegClass); + FuncInfo->addLiveInAttr(VReg, Flags); SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT); SDValue Addr = FIN; if (j) { @@ -3458,6 +3460,7 @@ // types to avoid forcing arguments to memory unnecessarily. if (GPR_idx != Num_GPR_Regs) { unsigned VReg = MF.addLiveIn(GPR[GPR_idx++], &PPC::G8RCRegClass); + FuncInfo->addLiveInAttr(VReg, Flags); ArgVal = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i64); if (ObjectVT == MVT::i32 || ObjectVT == MVT::i1) @@ -3503,6 +3506,7 @@ // since otherwise we never run out of FPRs before running out // of GPRs. unsigned VReg = MF.addLiveIn(GPR[GPR_idx++], &PPC::G8RCRegClass); + FuncInfo->addLiveInAttr(VReg, Flags); ArgVal = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i64); if (ObjectVT == MVT::f32) { Index: lib/Target/PowerPC/PPCInstrInfo.h =================================================================== --- lib/Target/PowerPC/PPCInstrInfo.h +++ lib/Target/PowerPC/PPCInstrInfo.h @@ -290,6 +290,20 @@ return Reg >= PPC::V0 && Reg <= PPC::V31; } const TargetRegisterClass *updatedRC(const TargetRegisterClass *RC) const; + + bool isSignOrZeroExtended(const MachineInstr &MI, bool SignExt, const unsigned PhiDepth) const; + + /// Return true if the output of the instruction is always a sign-extended, + /// i.e. 0 to 31-th bits are same as 32-th bit. + bool isSignExtended(const MachineInstr &MI, const unsigned depth = 0) const { + return isSignOrZeroExtended(MI, true, depth); + } + + /// Return true if the output of the instruction is always zero-extended, + /// i.e. 0 to 31-th bits are all zeros + bool isZeroExtended(const MachineInstr &MI, const unsigned depth = 0) const { + return isSignOrZeroExtended(MI, false, depth); + } }; } Index: lib/Target/PowerPC/PPCInstrInfo.cpp =================================================================== --- lib/Target/PowerPC/PPCInstrInfo.cpp +++ lib/Target/PowerPC/PPCInstrInfo.cpp @@ -1931,3 +1931,191 @@ return &PPC::VSRCRegClass; return RC; } + +// This function returns true if the machine instruction +// always outputs a value by extending a 32 bit value, +// i.e. 0 to 31-th bits are same as 32-th bit +static bool +isSignExtendingOp(const MachineInstr &MI) { + int Opcode = MI.getOpcode(); + if (Opcode == PPC::LI || Opcode == PPC::LI8 || + Opcode == PPC::LIS || Opcode == PPC::LIS8 || + Opcode == PPC::SRAW || Opcode == PPC::SRAWo || + Opcode == PPC::SRAWI || Opcode == PPC::SRAWIo || + Opcode == PPC::LWA || Opcode == PPC::LWAX || + Opcode == PPC::LWA_32 || Opcode == PPC::LWAX_32 || + Opcode == PPC::LHA || Opcode == PPC::LHAX || + Opcode == PPC::LHA8 || Opcode == PPC::LHAX8 || + Opcode == PPC::EXTSB || Opcode == PPC::EXTSBo || + Opcode == PPC::EXTSH || Opcode == PPC::EXTSHo || + Opcode == PPC::EXTSB8 || Opcode == PPC::EXTSH8 || + Opcode == PPC::EXTSW || Opcode == PPC::EXTSWo || + Opcode == PPC::EXTSH8_32_64 || Opcode == PPC::EXTSW_32_64 || + Opcode == PPC::EXTSB8_32_64) + return true; + + else if (Opcode == PPC::RLDICL && MI.getOperand(3).getImm() >= 33) + return true; + + else if ((Opcode == PPC::RLWINM || Opcode == PPC::RLWINMo || + Opcode == PPC::RLWNM || Opcode == PPC::RLWNMo) && + MI.getOperand(3).getImm() > 0 && + MI.getOperand(3).getImm() <= MI.getOperand(4).getImm()) + return true; + + return false; +} + +// This function returns true if the machine instruction +// always outputs zeros in higher 32 bits +static bool +isZeroExtendingOp(const MachineInstr &MI) { + int Opcode = MI.getOpcode(); + // The 16-bit immediate is sign-extended in li/lis. + // If the most significant bit is zero, all higher bits are zero. + if (Opcode == PPC::LI || Opcode == PPC::LI8 || + Opcode == PPC::LIS || Opcode == PPC::LIS8) { + int64_t Imm = MI.getOperand(1).getImm(); + if (((uint64_t)Imm & ~0x7FFFuLL) == 0) + return true; + } + + // We have some variations of rotate-and-mask instructions + // that clear higher 32-bits + else if ((Opcode == PPC::RLDICL || Opcode == PPC::RLDICLo || + Opcode == PPC::RLDCL || Opcode == PPC::RLDCLo || + Opcode == PPC::RLDICL_32_64) && + MI.getOperand(3).getImm() >= 32) + return true; + + else if ((Opcode == PPC::RLDIC || Opcode == PPC::RLDICo) && + MI.getOperand(3).getImm() >= 32 && + MI.getOperand(3).getImm() <= 63 - MI.getOperand(2).getImm()) + return true; + + else if ((Opcode == PPC::RLWINM || Opcode == PPC::RLWINMo || + Opcode == PPC::RLWNM || Opcode == PPC::RLWNMo || + Opcode == PPC::RLWINM8 || Opcode == PPC::RLWNM8) && + MI.getOperand(3).getImm() <= MI.getOperand(4).getImm()) + return true; + + // We have some variations of rotate-and-mask instructions + else if (Opcode == PPC::CNTLZW || Opcode == PPC::CNTLZWo || + Opcode == PPC::CNTTZW || Opcode == PPC::CNTTZWo || + Opcode == PPC::CNTLZW8 || Opcode == PPC::CNTTZW8 || + Opcode == PPC::CNTLZD || Opcode == PPC::CNTLZDo || + Opcode == PPC::CNTTZD || Opcode == PPC::CNTTZDo || + Opcode == PPC::POPCNTD || + Opcode == PPC::SLW || Opcode == PPC::SLWo || + Opcode == PPC::SRW || Opcode == PPC::SRWo || + Opcode == PPC::SLW8 || Opcode == PPC::SRW8 || + Opcode == PPC::SLWI || Opcode == PPC::SLWIo || + Opcode == PPC::SRWI || Opcode == PPC::SRWIo || + Opcode == PPC::LWZ || Opcode == PPC::LWZX || + Opcode == PPC::LHZ || Opcode == PPC::LHZX || + Opcode == PPC::LBZ || Opcode == PPC::LBZX || + Opcode == PPC::LWZ8 || Opcode == PPC::LWZX8 || + Opcode == PPC::LHZ8 || Opcode == PPC::LHZX8 || + Opcode == PPC::LBZ8 || Opcode == PPC::LBZX8 || + Opcode == PPC::ANDIo || Opcode == PPC::ANDISo || + Opcode == PPC::ROTRWI || Opcode == PPC::ROTRWIo || + Opcode == PPC::EXTLWI || Opcode == PPC::EXTLWIo) + return true; + + return false; +} + +// We limit the max depth to track incoming values of PHIs/ISELs to avoid exsessive cost. +const unsigned MAX_PHI_DEPTH = 1; + +bool +PPCInstrInfo::isSignOrZeroExtended(const MachineInstr &MI, bool SignExt, + const unsigned PhiDepth) const { + const MachineFunction *MF = MI.getParent()->getParent(); + const MachineRegisterInfo *MRI = &MF->getRegInfo(); + const PPCFunctionInfo *FuncInfo = MF->getInfo(); + const PPCSubtarget &Subtarget = MF->getSubtarget(); + + switch (MI.getOpcode()) { + case PPC::COPY: { + unsigned SrcReg = MI.getOperand(1).getReg(); + + // In both ELFv1 and v2 ABI, method parameters and the return value + // are sign- or zero-extended. + if (Subtarget.isSVR4ABI()) { + // We check the ZExt/SExt flags for a method parameter. + if (MI.getParent()->getBasicBlock() == &MF->getFunction()->getEntryBlock()) { + unsigned VReg = MI.getOperand(0).getReg(); + if (MF->getRegInfo().isLiveIn(VReg)) + return SignExt?FuncInfo->isLiveInSExt(VReg):FuncInfo->isLiveInZExt(VReg); + } + + // For a method return value, we check the ZExt/SExt flags in attribute. + // We assume the following code sequence for method call. + // ADJCALLSTACKDOWN 32, %R1, %R1 + // BL8_NOP ,... + // ADJCALLSTACKUP 32, 0, %R1, %R1 + // %vreg5 = COPY %X3; G8RC:%vreg5 + if (SrcReg == PPC::X3) { + const MachineBasicBlock *MBB = MI.getParent(); + MachineBasicBlock::const_instr_iterator II = MachineBasicBlock::const_instr_iterator(&MI); + if (II != MBB->instr_begin() && (--II)->getOpcode() == PPC::ADJCALLSTACKUP) { + const MachineInstr &CallMI = *(--II); + if (CallMI.isCall() && CallMI.getOperand(0).isGlobal()) { + const Function *CalleeFn = dyn_cast(CallMI.getOperand(0).getGlobal()); + const IntegerType *IntTy = dyn_cast(CalleeFn->getReturnType()); + const AttributeList &Attrs = CalleeFn->getAttributes().getRetAttributes(); + if (IntTy && IntTy->getBitWidth() <= 32) + return Attrs.hasAttribute(AttributeList::ReturnIndex, + SignExt?Attribute::SExt:Attribute::ZExt); + } + } + } + } + + // If this is a copy from another register, we recursively check the source. + if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) + return false; + const MachineInstr *SrcMI = MRI->getVRegDef(SrcReg); + if (SrcMI != NULL) + return isSignOrZeroExtended(*SrcMI, SignExt, PhiDepth); + + return false; + } + + // If all incoming values are sign- or zero-extended, + // the output of the isel or phi is also sign- or zero-extended. + case PPC::ISEL: + case PPC::PHI: { + if (PhiDepth >= MAX_PHI_DEPTH) + return false; + + // The input registers for ISEL are operand 1 and 2. + // The input registers for PHI are operand 1, 3, ... + unsigned e = 3, d = 1; + if (MI.getOpcode() == PPC::PHI) { + e = MI.getNumOperands(); + d = 2; + } + + for (unsigned i = 1; i != e; i += d) { + if (MI.getOperand(i).isReg()) { + unsigned SrcReg = MI.getOperand(i).getReg(); + if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) + return false; + const MachineInstr *SrcMI = MRI->getVRegDef(SrcReg); + if (SrcMI == NULL || !isSignOrZeroExtended(*SrcMI, SignExt, PhiDepth+1)) + return false; + } + else + return false; + } + return true; + } + + default: + return SignExt?isSignExtendingOp(MI): + isZeroExtendingOp(MI); + } + return false; +} Index: lib/Target/PowerPC/PPCMIPeephole.cpp =================================================================== --- lib/Target/PowerPC/PPCMIPeephole.cpp +++ lib/Target/PowerPC/PPCMIPeephole.cpp @@ -23,6 +23,7 @@ #include "PPC.h" #include "PPCInstrBuilder.h" #include "PPCTargetMachine.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -32,6 +33,19 @@ #define DEBUG_TYPE "ppc-mi-peepholes" +STATISTIC(NumEliminatedSExt, "Number of eliminated sign-extensions"); +STATISTIC(NumEliminatedZExt, "Number of eliminated zero-extensions"); + +static cl::opt + EnableSExtElimination("ppc-eliminate-signext", + cl::desc("enable elimination of sign-extensions"), + cl::init(true), cl::Hidden); + +static cl::opt + EnableZExtElimination("ppc-eliminate-zeroext", + cl::desc("enable elimination of zero-extensions"), + cl::init(true), cl::Hidden); + namespace llvm { void initializePPCMIPeepholePass(PassRegistry&); } @@ -336,6 +350,72 @@ } break; } + + case PPC::EXTSW_32_64: { + // We can eliminate EXTSW if the input is known to be already sign-extended. + // expected input code sequence: + // %vreg3 = EXTSW_32_64 %vreg1; G8RC:%vreg3 GPRC:%vreg1 + // expected transformed code sequence: + // %vreg5 = IMPLICIT_DEF; G8RC:%vreg5 # TmpReg + // %vreg3 = INSERT_SUBREG %vreg5, %vreg1, sub_32; G8RC:%vreg3,%vreg5 GPRC:%vreg1 + if (!EnableSExtElimination) break; + + unsigned SrcReg = MI.getOperand(1).getReg(); + if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) + break; + MachineInstr *SrcMI = MRI->getVRegDef(SrcReg); + + if (SrcMI && TII->isSignExtended(*SrcMI)) { + DEBUG(dbgs() << "Removing redundant sign-extension\n"); + unsigned TmpReg = MF->getRegInfo().createVirtualRegister(&PPC::G8RCRegClass); + BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::IMPLICIT_DEF), TmpReg); + BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::INSERT_SUBREG), + MI.getOperand(0).getReg()) + .addReg(TmpReg) + .addReg(SrcReg) + .addImm(PPC::sub_32); + ToErase = &MI; + Simplified = true; + NumEliminatedSExt++; + } + break; + } + + case PPC::RLDICL: { + // We can eliminate RLDICL for zero-extension + // if the input is known to be already zero-extended. + // exptected input pattern for zero extension for %vreg1: + // %vreg4 = IMPLICIT_DEF; G8RC:%vreg4 + // %vreg3 = INSERT_SUBREG %vreg4, %vreg1, sub_32; G8RC:%vreg3,%vreg4 GPRC:%vreg1 + // %vreg5 = RLDICL %vreg3, 0, 32; G8RC:%vreg5,%vreg3 + if (!EnableZExtElimination) break; + if (MI.getOperand(2).getImm() != 0 || + MI.getOperand(3).getImm() > 32) + break; + unsigned SrcReg = MI.getOperand(1).getReg(); + if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) + break; + MachineInstr *SrcMI = MRI->getVRegDef(SrcReg); + + if (!(SrcMI && SrcMI->getOpcode() == PPC::INSERT_SUBREG && + SrcMI->getOperand(0).isReg() && SrcMI->getOperand(1).isReg())) + break; + + MachineInstr *ImpDefMI = MRI->getVRegDef(SrcMI->getOperand(1).getReg()); + MachineInstr *SubRegMI = MRI->getVRegDef(SrcMI->getOperand(2).getReg()); + if (ImpDefMI->getOpcode() != PPC::IMPLICIT_DEF) break; + + if (TII->isZeroExtended(*SubRegMI)) { + DEBUG(dbgs() << "Removing redundant zero-extension\n"); + BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY), + MI.getOperand(0).getReg()) + .addReg(SrcReg); + ToErase = &MI; + Simplified = true; + NumEliminatedZExt++; + } + break; + } } } // If the last instruction was marked for elimination, Index: lib/Target/PowerPC/PPCMachineFunctionInfo.h =================================================================== --- lib/Target/PowerPC/PPCMachineFunctionInfo.h +++ lib/Target/PowerPC/PPCMachineFunctionInfo.h @@ -16,6 +16,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Target/TargetCallingConv.h" namespace llvm { @@ -113,6 +114,10 @@ /// copies bool IsSplitCSR = false; + /// We keep track attributes for each live-in virtual registers + /// to use SExt/ZExt flags in later optimization. + std::vector> LiveInAttrs; + public: explicit PPCFunctionInfo(MachineFunction &MF) : MF(MF) {} @@ -175,6 +180,19 @@ unsigned getVarArgsNumFPR() const { return VarArgsNumFPR; } void setVarArgsNumFPR(unsigned Num) { VarArgsNumFPR = Num; } + /// This function associates attributes for each live-in virtual register. + void addLiveInAttr(unsigned VReg, ISD::ArgFlagsTy Flags) { + LiveInAttrs.push_back(std::make_pair(VReg, Flags)); + } + + /// This function returns true if the spesified vreg is + /// a live-in register and sign-extended. + bool isLiveInSExt(unsigned VReg) const; + + /// This function returns true if the spesified vreg is + /// a live-in register and zero-extended. + bool isLiveInZExt(unsigned VReg) const; + int getCRSpillFrameIndex() const { return CRSpillFrameIndex; } void setCRSpillFrameIndex(int idx) { CRSpillFrameIndex = idx; } Index: lib/Target/PowerPC/PPCMachineFunctionInfo.cpp =================================================================== --- lib/Target/PowerPC/PPCMachineFunctionInfo.cpp +++ lib/Target/PowerPC/PPCMachineFunctionInfo.cpp @@ -43,3 +43,17 @@ "func_toc" + Twine(MF.getFunctionNumber())); } + +bool PPCFunctionInfo::isLiveInSExt(unsigned VReg) const { + for (const std::pair &LiveIn : LiveInAttrs) + if (LiveIn.first == VReg) + return LiveIn.second.isSExt(); + return false; +} + +bool PPCFunctionInfo::isLiveInZExt(unsigned VReg) const { + for (const std::pair &LiveIn : LiveInAttrs) + if (LiveIn.first == VReg) + return LiveIn.second.isZExt(); + return false; +} Index: test/CodeGen/PowerPC/eliminate_ext.ll =================================================================== --- /dev/null +++ test/CodeGen/PowerPC/eliminate_ext.ll @@ -0,0 +1,206 @@ +; RUN: llc -verify-machineinstrs -O1 -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -O1 -mtriple=powerpc64-unknown-linux-gnu < %s | FileCheck %s + +define signext i32 @sext_test(i32 signext %a) { +; We can eliminate extsw before and after the call for int_func. +; CHECK-LABEL: sext_test: +; CHECK-NOT: extsw +; CHECK: bl int_func +; CHECK-NOT: extsw +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %return, label %if.then + +if.then: + %call = tail call signext i32 @int_func(i32 signext %a) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then ], [ 0, %entry ] + ret i32 %retval.0 +} + +define signext i32 @sext_test2(i32 signext %a) { +; We can eliminate extsw before the call for long_func. +; We should not eliminate extsw after the call. +; CHECK-LABEL: sext_test2: +; CHECK-NOT: extsw +; CHECK: bl long_func +; CHECK: extsw +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %return, label %if.then + +if.then: + %conv = sext i32 %a to i64 + %call = tail call i64 @long_func(i64 %conv) + %conv1 = trunc i64 %call to i32 + br label %return + +return: + %retval.0 = phi i32 [ %conv1, %if.then ], [ 0, %entry ] + ret i32 %retval.0 +} + +define zeroext i32 @zext_test(i32 zeroext %a) { +; We can eliminate zero-extension before and after the call for uint_func. +; CHECK-LABEL: zext_test: +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +; CHECK: bl uint_func +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %return, label %if.then + +if.then: + %call = tail call zeroext i32 @uint_func(i32 zeroext %a) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then ], [ 0, %entry ] + ret i32 %retval.0 +} + +define zeroext i32 @zext_test2(i32 zeroext %a) { +; We can eliminate zero-extension before the call for ulong_func. +; CHECK-LABEL: zext_test2: +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +; CHECK: bl ulong_func +; CHECK: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %return, label %if.then + +if.then: + %conv = zext i32 %a to i64 + %call = tail call i64 @ulong_func(i64 %conv) + %conv1 = trunc i64 %call to i32 + br label %return + +return: + %retval.0 = phi i32 [ %conv1, %if.then ], [ 0, %entry ] + ret i32 %retval.0 +} + +define signext i32 @sext_test3(i32 signext %a, i32 signext %b) { +; We can eliminate extsw for output of li and rlwinm. +; CHECK-LABEL: sext_test3: +; CHECK-DAG: li {{[0-9]+}}, 255 +; CHECK-DAG: rlwinm {{[0-9]+}}, {{[0-9]+}}, 0, 1, 15 +; CHECK-NOT: extsw +; CHECK: bl int_func +; CHECK-NOT: extsw +entry: + %and2 = and i32 %a, 2 + %tobool3 = icmp eq i32 %and2, 0 + br i1 %tobool3, label %return, label %if.then4 + +if.then4: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + %and1 = and i32 %b, 2147418112 + %b.addr.0 = select i1 %tobool, i32 %and1, i32 255 + %call = tail call signext i32 @int_func(i32 signext %b.addr.0) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then4 ], [ 0, %entry ] + ret i32 %retval.0 +} + +define signext i32 @sext_test4(i32 signext %a, i32 signext %b) { +; We can eliminate extsw for output of li and srawi. +; CHECK-LABEL: sext_test4: +; CHECK-DAG: lis {{[0-9]+}}, 4660 +; CHECK-DAG: srawi {{[0-9]+}}, {{[0-9]+}}, 3 +; CHECK-NOT: extsw +; CHECK: bl int_func +; CHECK-NOT: extsw +entry: + %and1 = and i32 %a, 2 + %tobool2 = icmp eq i32 %and1, 0 + br i1 %tobool2, label %return, label %if.then3 + +if.then3: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + %shr = ashr i32 %b, 3 + %b.addr.0 = select i1 %tobool, i32 305397760, i32 %shr + %call = tail call signext i32 @int_func(i32 signext %b.addr.0) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then3 ], [ 0, %entry ] + ret i32 %retval.0 +} + +define zeroext i32 @zext_test3(i32 zeroext %a, i32 zeroext %b) { +; We can eliminate zero-extension for output of li and slwi. +; CHECK-LABEL: zext_test3: +; CHECK-DAG: li {{[0-9]+}}, 255 +; CHECK-DAG: slwi {{[0-9]+}}, {{[0-9]+}}, 3 +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +; CHECK: bl uint_func +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +entry: + %and1 = and i32 %a, 2 + %tobool2 = icmp eq i32 %and1, 0 + br i1 %tobool2, label %return, label %if.then3 + +if.then3: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + %shl = shl i32 %b, 3 + %b.addr.0 = select i1 %tobool, i32 %shl, i32 255 + %call = tail call zeroext i32 @uint_func(i32 zeroext %b.addr.0) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then3 ], [ 0, %entry ] + ret i32 %retval.0 +} + +define zeroext i32 @zext_test4(i32 zeroext %a, i32 zeroext %b, i32* nocapture readonly %p) { +; We can eliminate zero-extension for output of lwz and andi. +; CHECK-LABEL: zext_test4: +; CHECK-DAG: lwz {{[0-9]+}}, 0(5) +; CHECK-DAG: andi. {{[0-9]+}}, {{[0-9]+}}, 4660 +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +; CHECK: bl uint_func +; CHECK-NOT: clrldi {{[0-9]+}}, {{[0-9]+}}, 32 +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %if.else, label %if.then + +if.then: + %0 = load i32, i32* %p + br label %if.end + +if.else: + %and1 = and i32 %b, 4660 + br label %if.end + +if.end: + %b.addr.0 = phi i32 [ %0, %if.then ], [ %and1, %if.else ] + %and2 = and i32 %a, 2 + %tobool3 = icmp eq i32 %and2, 0 + br i1 %tobool3, label %return, label %if.then4 + +if.then4: + %call = tail call zeroext i32 @uint_func(i32 zeroext %b.addr.0) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then4 ], [ 0, %if.end ] + ret i32 %retval.0 +} + +declare signext i32 @int_func(i32 signext) +declare zeroext i32 @uint_func(i32 zeroext) +declare i64 @long_func(i64) +declare i64 @ulong_func(i64)