diff options
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp | 353 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonFrameLowering.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp | 21 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonInstrInfo.td | 12 | ||||
-rw-r--r-- | llvm/test/CodeGen/Hexagon/avoid-predspill.ll | 42 |
5 files changed, 352 insertions, 78 deletions
diff --git a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp index c7b06d22fd4..8de116e6bf4 100644 --- a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp @@ -19,6 +19,7 @@ #include "HexagonTargetMachine.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -1072,80 +1073,65 @@ static bool needToReserveScavengingSpillSlots(MachineFunction &MF, } -/// Replaces the predicate spill code pseudo instructions by valid instructions. -bool HexagonFrameLowering::replacePredRegPseudoSpillCode(MachineFunction &MF) - const { - auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget()); - auto &HII = *HST.getInstrInfo(); - MachineRegisterInfo &MRI = MF.getRegInfo(); - bool HasReplacedPseudoInst = false; - // Replace predicate spill pseudo instructions by real code. - // Loop over all of the basic blocks. - for (MachineFunction::iterator MBBb = MF.begin(), MBBe = MF.end(); - MBBb != MBBe; ++MBBb) { - MachineBasicBlock *MBB = &*MBBb; - // Traverse the basic block. - MachineBasicBlock::iterator NextII; - for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end(); - MII = NextII) { - MachineInstr *MI = MII; - NextII = std::next(MII); - int Opc = MI->getOpcode(); - if (Opc == Hexagon::STriw_pred) { - HasReplacedPseudoInst = true; - // STriw_pred FI, 0, SrcReg; - unsigned VirtReg = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); - unsigned SrcReg = MI->getOperand(2).getReg(); - bool IsOrigSrcRegKilled = MI->getOperand(2).isKill(); - - assert(MI->getOperand(0).isFI() && "Expect a frame index"); - assert(Hexagon::PredRegsRegClass.contains(SrcReg) && - "Not a predicate register"); - - // Insert transfer to general purpose register. - // VirtReg = C2_tfrpr SrcPredReg - BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr), - VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled)); - - // Change instruction to S2_storeri_io. - // S2_storeri_io FI, 0, VirtReg - MI->setDesc(HII.get(Hexagon::S2_storeri_io)); - MI->getOperand(2).setReg(VirtReg); - MI->getOperand(2).setIsKill(); - - } else if (Opc == Hexagon::LDriw_pred) { - // DstReg = LDriw_pred FI, 0 - MachineOperand &M0 = MI->getOperand(0); - if (M0.isDead()) { - MBB->erase(MII); - continue; - } - - unsigned VirtReg = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); - unsigned DestReg = MI->getOperand(0).getReg(); - - assert(MI->getOperand(1).isFI() && "Expect a frame index"); - assert(Hexagon::PredRegsRegClass.contains(DestReg) && - "Not a predicate register"); - - // Change instruction to L2_loadri_io. - // VirtReg = L2_loadri_io FI, 0 - MI->setDesc(HII.get(Hexagon::L2_loadri_io)); - MI->getOperand(0).setReg(VirtReg); - - // Insert transfer to general purpose register. - // DestReg = C2_tfrrp VirtReg - const MCInstrDesc &D = HII.get(Hexagon::C2_tfrrp); - BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), D, DestReg) - .addReg(VirtReg, getKillRegState(true)); - HasReplacedPseudoInst = true; - } +/// Find a GPR register that's available in the range from It to any use of +/// the 'spill' in FI. +static bool findAvailableReg(int FI, MachineBasicBlock::iterator It, + MachineBasicBlock::iterator End, + unsigned *AvailReg, + unsigned *NumUses, + const TargetRegisterInfo *TRI, + RegScavenger *Scavenger) { + assert(Scavenger->getCurrentPosition() == It && + "Unexpected scavenger position!"); + + BitVector Avail(Scavenger->getRegsAvailable(&Hexagon::IntRegsRegClass)); + if (Avail.none()) + return false; + + BitVector AvailByLastLoad(Avail.size()); + + while (++It != End) { + MachineInstr *MI = It; + if (MI->isDebugValue()) + continue; + + // Remove all registers modified by this inst from Avail + int Reg = Avail.find_first(); + while (Reg != -1) { + if (MI->modifiesRegister(Reg, TRI)) + Avail[Reg] = false; + else + assert(!MI->readsRegister(Reg, TRI) && "Inst reads undefined register"); + + Reg = Avail.find_next(Reg); + } + + int Opc = MI->getOpcode(); + // Stop if we find a store that overwrites the current spill in FI + if ((Opc == Hexagon::STriw_pred || Opc == Hexagon::STriw_mod) && + MI->getOperand(0).getIndex() == FI) + break; + + if ((Opc == Hexagon::LDriw_pred || Opc == Hexagon::LDriw_mod) && + MI->getOperand(1).getIndex() == FI && !MI->getOperand(0).isDead()) { + AvailByLastLoad = Avail; + ++(*NumUses); } + + // Give up early if there are no registers available + if (AvailByLastLoad.none() && Avail.none()) + break; } - return HasReplacedPseudoInst; + + if (AvailByLastLoad.none()) + return false; + + *AvailReg = (unsigned) AvailByLastLoad.find_first(); + return true; } + void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { @@ -1167,13 +1153,13 @@ void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF, const TargetRegisterClass &RC = Hexagon::IntRegsRegClass; // Replace predicate register pseudo spill code. - bool HasReplacedPseudoInst = replacePredRegPseudoSpillCode(MF); + bool HasReplacedPseudoInst = replacePseudoRegTransferCode(MF); // We need to reserve a a spill slot if scavenging could potentially require // spilling a scavenged register. if (HasReplacedPseudoInst && needToReserveScavengingSpillSlots(MF, HRI)) { MachineFrameInfo *MFI = MF.getFrameInfo(); - for (int i=0; i < NumberScavengerSlots; i++) + for (int i = 0; i < NumberScavengerSlots; i++) RS->addScavengingFrameIndex( MFI->CreateSpillStackObject(RC.getSize(), RC.getAlignment())); } @@ -1327,6 +1313,231 @@ bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF, } +/// Expands pseudo instructions that copy/spill/restore registers that cannot +/// have these operations done directly. For spills/restores, it will attempt +/// to spill into a general-purpose register, instead of spilling to memory. +bool HexagonFrameLowering::replacePseudoRegTransferCode(MachineFunction &MF) + const { + auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget()); + auto &HII = *HST.getInstrInfo(); + auto &HRI = *HST.getRegisterInfo(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + bool HasReplacedPseudoInst = false; + + // We use the register scavenger purely for tracking of available registers + // here, but do the 'scavenging' on our own. + RegScavenger Scavenger; + + // Map from PredReg spill FIs to GPRs and remaining number of uses + DenseMap<int,std::pair<unsigned, unsigned>> FItoRegUses; + + // PredReg FIs that cannot be 'spilled' into GPRs because they are live + // across BB boundaries. + SmallSet<int, 8> AlwaysSpill; + + // Pred Reg FIs that have been spilled in a block due to shortage of GPRs + SmallSet<int, 8> LocallySpilled; + + // Do an SCC traversal of the MachineFunction. This is to make sure we detect + // cases where a PredReg *must* be spilled to memory because it is live across + // BasicBlock boundaries: we see the reload before the spill and can mark the + // PredReg's FI in AlwaysSpill. + for (auto It = scc_begin(&MF); !It.isAtEnd(); ++It) { + const std::vector<MachineBasicBlock *> &Scc = *It; + for (MachineBasicBlock *MBB : Scc) { + if (MBB->empty()) + continue; + + Scavenger.enterBasicBlock(MBB); + Scavenger.forward(); + + LocallySpilled.clear(); + + // Traverse the basic block. + MachineBasicBlock::iterator NextII; + for (auto MII = MBB->begin(); MII != MBB->end(); MII = NextII) { + MachineInstr *MI = MII; + NextII = std::next(MII); + + assert(Scavenger.getCurrentPosition() == MII && + "Unexpected scavenger position"); + + unsigned Opc = MI->getOpcode(); + DebugLoc DL = MI->getDebugLoc(); + + if (Opc == TargetOpcode::COPY) { + unsigned DestReg = MI->getOperand(0).getReg(); + unsigned SrcReg = MI->getOperand(1).getReg(); + MachineInstr *EraseMI = nullptr; + if (Hexagon::ModRegsRegClass.contains(DestReg) && + Hexagon::ModRegsRegClass.contains(SrcReg)) { + unsigned T = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); + BuildMI(*MBB, MII, DL, HII.get(TargetOpcode::COPY), T) + .addOperand(MI->getOperand(1)); + BuildMI(*MBB, MII, DL, HII.get(TargetOpcode::COPY), DestReg) + .addReg(T, RegState::Kill); + EraseMI = &*MII; + HasReplacedPseudoInst = true; + } + if (NextII != MBB->end()) + Scavenger.forward(); // Move to next instruction + if (EraseMI) + MBB->erase(EraseMI); + } else if (Opc == Hexagon::STriw_pred || Opc == Hexagon::STriw_mod) { + // STriw_pred FI, 0, SrcReg + unsigned SrcReg = MI->getOperand(2).getReg(); + bool IsOrigSrcRegKilled = MI->getOperand(2).isKill(); + + assert(MI->getOperand(0).isFI() && "Expect a frame index"); + assert((Hexagon::PredRegsRegClass.contains(SrcReg) || + Hexagon::ModRegsRegClass.contains(SrcReg)) && + "Not a predicate or modifier register"); + int FI = MI->getOperand(0).getIndex(); + + assert(!FItoRegUses.count(FI) && + "Still expecting a load of this spilled predicate register!"); + + // Check whether we have an available GPR here and all the way to the + // reload(s) of this spill + unsigned AvailReg, NumUses = 0; + if (!AlwaysSpill.count(FI) && findAvailableReg(FI, MII, MBB->end(), + &AvailReg, &NumUses, &HRI, &Scavenger)) { + // Found a register we can move this into instead of spilling + if (Opc == Hexagon::STriw_pred) + BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr), + AvailReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled)); + else + BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::A2_tfrcrr), + AvailReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled)); + + // Mark the register as used in the function (important for callee + // saved registers). + BitVector UsedPhysRegsMask = MRI.getUsedPhysRegsMask(); + UsedPhysRegsMask.set(AvailReg); + MRI.setUsedPhysRegMask(UsedPhysRegsMask); + + Scavenger.setRegUsed(AvailReg); + if (NextII != MBB->end()) + Scavenger.forward(); + + FItoRegUses[FI] = std::make_pair(AvailReg, NumUses); + LocallySpilled.erase(FI); + + MBB->erase(MII); + } else { + // No register available. Insert actual spill. + // VirtReg = C2_tfrpr SrcPredReg + unsigned VirtReg = + MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); + if (Opc == Hexagon::STriw_pred) + BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::C2_tfrpr), + VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled)); + else + BuildMI(*MBB, MII, MI->getDebugLoc(), HII.get(Hexagon::A2_tfrcrr), + VirtReg).addReg(SrcReg, getKillRegState(IsOrigSrcRegKilled)); + + // Change instruction to S2_storeri_io. + // S2_storeri_io FI, 0, VirtReg + MI->setDesc(HII.get(Hexagon::S2_storeri_io)); + MI->getOperand(2).setReg(VirtReg); + MI->getOperand(2).setIsKill(); + + HasReplacedPseudoInst = true; + + if (NextII != MBB->end()) + Scavenger.forward(); + + if (!AlwaysSpill.count(FI)) + LocallySpilled.insert(FI); + } + } else if (Opc == Hexagon::LDriw_pred || Opc == Hexagon::LDriw_mod) { + // DstReg = LDriw_pred FI, 0 + unsigned DestReg = MI->getOperand(0).getReg(); + assert(MI->getOperand(1).isFI() && "Expect a frame index"); + assert((Hexagon::PredRegsRegClass.contains(DestReg) || + Hexagon::ModRegsRegClass.contains(DestReg)) && + "Not a predicate or modifier register"); + + int FI = MI->getOperand(1).getIndex(); + + MachineOperand &M0 = MI->getOperand(0); + if (M0.isDead()) { + if (NextII != MBB->end()) + Scavenger.forward(); + MBB->erase(MII); + continue; + } + + if (FItoRegUses.count(FI)) { + // Reload from GPR + std::pair<unsigned,unsigned> &SpillInfo = FItoRegUses[FI]; + + --SpillInfo.second; + bool IsKill = SpillInfo.second == 0; + if (Opc == Hexagon::LDriw_pred) + BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), + HII.get(Hexagon::C2_tfrrp), DestReg).addReg(SpillInfo.first, + getKillRegState(IsKill)); + else + BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), + HII.get(Hexagon::A2_tfrrcr), DestReg).addReg(SpillInfo.first, + getKillRegState(IsKill)); + + if (IsKill) + FItoRegUses.erase(FI); + + Scavenger.forward(); // Process the newly inserted instruction + if (NextII != MBB->end()) + Scavenger.forward(); // Move to next instruction + + MBB->erase(MII); + } else { + // Reload from memory + + // If this wasn't spilled previously in this block, the PredReg in + // this FI is live across blocks. Make sure it never ends up in a + // register. + if (!LocallySpilled.count(FI)) + AlwaysSpill.insert(FI); + + unsigned VirtReg = + MRI.createVirtualRegister(&Hexagon::IntRegsRegClass); + + // Change instruction to L2_loadri_io. + // VirtReg = L2_loadri_io FI, 0 + MI->setDesc(HII.get(Hexagon::L2_loadri_io)); + MI->getOperand(0).setReg(VirtReg); + + // Insert transfer to general purpose register. + // DestReg = C2_tfrrp VirtReg + if (Opc == Hexagon::LDriw_pred) + BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), + HII.get(Hexagon::C2_tfrrp), DestReg).addReg(VirtReg, + getKillRegState(true)); + else + BuildMI(*MBB, std::next(MII), MI->getDebugLoc(), + HII.get(Hexagon::A2_tfrrcr), DestReg).addReg(VirtReg, + getKillRegState(true)); + + Scavenger.forward(); // Process newly inserted instruction + if (NextII != MBB->end()) + Scavenger.forward(); // Move to next instruction + + HasReplacedPseudoInst = true; + } + } else if (NextII != MBB->end()) + Scavenger.forward(); + } + + assert(FItoRegUses.empty() && "PredRegs in GPRs outlast this block!"); + } + } + + return HasReplacedPseudoInst; +} + + + void HexagonFrameLowering::expandAlloca(MachineInstr *AI, const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const { MachineBasicBlock &MB = *AI->getParent(); diff --git a/llvm/lib/Target/Hexagon/HexagonFrameLowering.h b/llvm/lib/Target/Hexagon/HexagonFrameLowering.h index 683b303d43e..8a5d41433f1 100644 --- a/llvm/lib/Target/Hexagon/HexagonFrameLowering.h +++ b/llvm/lib/Target/Hexagon/HexagonFrameLowering.h @@ -93,7 +93,7 @@ private: MachineBasicBlock::iterator At) const; void adjustForCalleeSavedRegsSpillCall(MachineFunction &MF) const; - bool replacePredRegPseudoSpillCode(MachineFunction &MF) const; + bool replacePseudoRegTransferCode(MachineFunction &MF) const; bool replaceVecPredRegPseudoSpillCode(MachineFunction &MF) const; void findShrunkPrologEpilog(MachineFunction &MF, MachineBasicBlock *&PrologB, diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp index c911b041ebd..84395c2a191 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -728,8 +728,12 @@ void HexagonInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); } else if (Hexagon::PredRegsRegClass.hasSubClassEq(RC)) { BuildMI(MBB, I, DL, get(Hexagon::STriw_pred)) - .addFrameIndex(FI).addImm(0) - .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); + .addFrameIndex(FI).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); + } else if (Hexagon::ModRegsRegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Hexagon::STriw_mod)) + .addFrameIndex(FI).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); } else { llvm_unreachable("Unimplemented"); } @@ -747,15 +751,18 @@ void HexagonInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, MachineMemOperand *MMO = MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad, MFI.getObjectSize(FI), Align); - if (RC == &Hexagon::IntRegsRegClass) { + if (Hexagon::IntRegsRegClass.hasSubClassEq(RC)) { BuildMI(MBB, I, DL, get(Hexagon::L2_loadri_io), DestReg) .addFrameIndex(FI).addImm(0).addMemOperand(MMO); - } else if (RC == &Hexagon::DoubleRegsRegClass) { + } else if (Hexagon::DoubleRegsRegClass.hasSubClassEq(RC)) { BuildMI(MBB, I, DL, get(Hexagon::L2_loadrd_io), DestReg) .addFrameIndex(FI).addImm(0).addMemOperand(MMO); - } else if (RC == &Hexagon::PredRegsRegClass) { + } else if (Hexagon::PredRegsRegClass.hasSubClassEq(RC)) { BuildMI(MBB, I, DL, get(Hexagon::LDriw_pred), DestReg) - .addFrameIndex(FI).addImm(0).addMemOperand(MMO); + .addFrameIndex(FI).addImm(0).addMemOperand(MMO); + } else if (Hexagon::ModRegsRegClass.hasSubClassEq(RC)) { + BuildMI(MBB, I, DL, get(Hexagon::LDriw_mod), DestReg) + .addFrameIndex(FI).addImm(0).addMemOperand(MMO); } else { llvm_unreachable("Can't store this register to stack slot"); } @@ -2461,6 +2468,8 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset, // any size. Later pass knows how to handle it. case Hexagon::STriw_pred: case Hexagon::LDriw_pred: + case Hexagon::STriw_mod: + case Hexagon::LDriw_mod: return true; case Hexagon::TFR_FI: diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.td b/llvm/lib/Target/Hexagon/HexagonInstrInfo.td index 421403f4972..e37f4a79da3 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.td +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.td @@ -2010,6 +2010,12 @@ let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13, def LDriw_pred : LDInst<(outs PredRegs:$dst), (ins IntRegs:$addr, s11_2Ext:$off), ".error \"should not emit\"", []>; +// Load modifier. +let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13, + isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in +def LDriw_mod : LDInst<(outs ModRegs:$dst), + (ins IntRegs:$addr, s11_2Ext:$off), + ".error \"should not emit\"", []>; let Defs = [R29, R30, R31], Uses = [R30], hasSideEffects = 0 in def L2_deallocframe : LDInst<(outs), (ins), @@ -3651,6 +3657,12 @@ let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13, def STriw_pred : STInst<(outs), (ins IntRegs:$addr, s11_2Ext:$off, PredRegs:$src1), ".error \"should not emit\"", []>; +// Store modifier. +let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13, + isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in +def STriw_mod : STInst<(outs), + (ins IntRegs:$addr, s11_2Ext:$off, ModRegs:$src1), + ".error \"should not emit\"", []>; // S2_allocframe: Allocate stack frame. let Defs = [R29, R30], Uses = [R29, R31, R30], diff --git a/llvm/test/CodeGen/Hexagon/avoid-predspill.ll b/llvm/test/CodeGen/Hexagon/avoid-predspill.ll new file mode 100644 index 00000000000..159c149c442 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/avoid-predspill.ll @@ -0,0 +1,42 @@ +; RUN: llc -march=hexagon -O2 < %s | FileCheck %s +; +; This checks that predicate registers are moved to GPRs instead of spilling +; where possible. + +; CHECK: p0 = +; CHECK-NOT: memw(r29 + +define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { +entry: + %cmp = icmp eq i32 %a, 1 + %cmp1 = icmp eq i32 %b, 2 + %or.cond = and i1 %cmp, %cmp1 + %cmp3 = icmp eq i32 %c, 3 + %or.cond30 = and i1 %or.cond, %cmp3 + %cmp5 = icmp eq i32 %d, 4 + %or.cond31 = and i1 %or.cond30, %cmp5 + %cmp7 = icmp eq i32 %e, 5 + %or.cond32 = and i1 %or.cond31, %cmp7 + %ret.0 = zext i1 %or.cond32 to i32 + %cmp8 = icmp eq i32 %a, 3 + %cmp10 = icmp eq i32 %b, 4 + %or.cond33 = and i1 %cmp8, %cmp10 + %cmp12 = icmp eq i32 %c, 5 + %or.cond34 = and i1 %or.cond33, %cmp12 + %cmp14 = icmp eq i32 %d, 6 + %or.cond35 = and i1 %or.cond34, %cmp14 + %cmp16 = icmp eq i32 %e, 7 + %or.cond36 = and i1 %or.cond35, %cmp16 + %ret.1 = select i1 %or.cond36, i32 2, i32 %ret.0 + %cmp21 = icmp eq i32 %b, 8 + %or.cond37 = and i1 %cmp, %cmp21 + %cmp23 = icmp eq i32 %c, 2 + %or.cond38 = and i1 %or.cond37, %cmp23 + %cmp25 = icmp eq i32 %d, 1 + %or.cond39 = and i1 %or.cond38, %cmp25 + %cmp27 = icmp eq i32 %e, 3 + %or.cond40 = and i1 %or.cond39, %cmp27 + %ret.2 = select i1 %or.cond40, i32 3, i32 %ret.1 + ret i32 %ret.2 +} + |