diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 3f30de596a5..29e90098c95 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -29,7 +29,8 @@ namespace RegState { Implicit = 0x4, Kill = 0x8, Dead = 0x10, - EarlyClobber = 0x20, + Undef = 0x20, + EarlyClobber = 0x40, ImplicitDefine = Implicit | Define, ImplicitKill = Implicit | Kill }; @@ -57,8 +58,9 @@ public: flags & RegState::Implicit, flags & RegState::Kill, flags & RegState::Dead, - SubReg, - flags & RegState::EarlyClobber)); + flags & RegState::Undef, + flags & RegState::EarlyClobber, + SubReg)); return *this; } @@ -203,6 +205,9 @@ inline unsigned getKillRegState(bool B) { inline unsigned getDeadRegState(bool B) { return B ? RegState::Dead : 0; } +inline unsigned getUndefRegState(bool B) { + return B ? RegState::Undef : 0; +} } // End llvm namespace diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index 5a7f76b5722..08739a26735 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -75,6 +75,10 @@ private: /// This is only valid on definitions of registers. bool IsDead : 1; + /// IsUndef - True if this is a register def / use of "undef", i.e. register + /// defined by an IMPLICIT_DEF. This is only valid on registers. + bool IsUndef : 1; + /// IsEarlyClobber - True if this MO_Register 'def' operand is written to /// by the MachineInstr before all input registers are read. This is used to /// model the GCC inline asm '&' constraint modifier. @@ -198,6 +202,11 @@ public: return IsKill; } + bool isUndef() const { + assert(isReg() && "Wrong MachineOperand accessor"); + return IsUndef; + } + bool isEarlyClobber() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsEarlyClobber; @@ -248,6 +257,11 @@ public: IsDead = Val; } + void setIsUndef(bool Val = true) { + assert(isReg() && "Wrong MachineOperand accessor"); + IsUndef = Val; + } + void setIsEarlyClobber(bool Val = true) { assert(isReg() && IsDef && "Wrong MachineOperand accessor"); IsEarlyClobber = Val; @@ -337,7 +351,8 @@ public: /// the specified value. If an operand is known to be an register already, /// the setReg method should be used. void ChangeToRegister(unsigned Reg, bool isDef, bool isImp = false, - bool isKill = false, bool isDead = false); + bool isKill = false, bool isDead = false, + bool isUndef = false); //===--------------------------------------------------------------------===// // Construction methods. @@ -357,13 +372,15 @@ public: static MachineOperand CreateReg(unsigned Reg, bool isDef, bool isImp = false, bool isKill = false, bool isDead = false, - unsigned SubReg = 0, - bool isEarlyClobber = false) { + bool isUndef = false, + bool isEarlyClobber = false, + unsigned SubReg = 0) { MachineOperand Op(MachineOperand::MO_Register); Op.IsDef = isDef; Op.IsImp = isImp; Op.IsKill = isKill; Op.IsDead = isDead; + Op.IsUndef = isUndef; Op.IsEarlyClobber = isEarlyClobber; Op.Contents.Reg.RegNo = Reg; Op.Contents.Reg.Prev = 0; @@ -420,6 +437,7 @@ public: IsImp = MO.IsImp; IsKill = MO.IsKill; IsDead = MO.IsDead; + IsUndef = MO.IsUndef; IsEarlyClobber = MO.IsEarlyClobber; SubReg = MO.SubReg; ParentMI = MO.ParentMI; diff --git a/include/llvm/CodeGen/RegisterScavenging.h b/include/llvm/CodeGen/RegisterScavenging.h index a4ed0129eb4..458c2e4487f 100644 --- a/include/llvm/CodeGen/RegisterScavenging.h +++ b/include/llvm/CodeGen/RegisterScavenging.h @@ -69,10 +69,6 @@ class RegScavenger { /// available, unset means the register is currently being used. BitVector RegsAvailable; - /// ImplicitDefed - If bit is set that means the register is defined by an - /// implicit_def instructions. That means it can be clobbered at will. - BitVector ImplicitDefed; - /// CurrDist - Distance from MBB entry to the current instruction MBBI. /// unsigned CurrDist; @@ -117,25 +113,18 @@ public: bool isUsed(unsigned Reg) const { return !RegsAvailable[Reg]; } bool isUnused(unsigned Reg) const { return RegsAvailable[Reg]; } - bool isImplicitlyDefined(unsigned Reg) const { return ImplicitDefed[Reg]; } - /// getRegsUsed - return all registers currently in use in used. void getRegsUsed(BitVector &used, bool includeReserved); /// setUsed / setUnused - Mark the state of one or a number of registers. /// - void setUsed(unsigned Reg, bool ImpDef = false); - void setUsed(BitVector &Regs, bool ImpDef = false) { + void setUsed(unsigned Reg); + void setUsed(BitVector &Regs) { RegsAvailable &= ~Regs; - if (ImpDef) - ImplicitDefed |= Regs; - else - ImplicitDefed &= ~Regs; } void setUnused(unsigned Reg, const MachineInstr *MI); void setUnused(BitVector &Regs) { RegsAvailable |= Regs; - ImplicitDefed &= ~Regs; } /// FindUnusedReg - Find a unused register of the specified register class diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 21bb5dc0127..b017f91e6a4 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -1782,8 +1782,12 @@ LiveIntervals::handleSpilledImpDefs(const LiveInterval &li, VirtRegMap &vrm, NewLIs.push_back(&getOrCreateInterval(NewVReg)); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.getReg() == li.reg) + if (MO.isReg() && MO.getReg() == li.reg) { MO.setReg(NewVReg); + MO.setIsUndef(); + if (MO.isKill()) + MO.setIsKill(false); + } } } } diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index c97750847f2..d44305f3333 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -120,7 +120,7 @@ void MachineOperand::ChangeToImmediate(int64_t ImmVal) { /// the specified value. If an operand is known to be an register already, /// the setReg method should be used. void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp, - bool isKill, bool isDead) { + bool isKill, bool isDead, bool isUndef) { // If this operand is already a register operand, use setReg to update the // register's use/def lists. if (isReg()) { @@ -143,6 +143,7 @@ void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp, IsImp = isImp; IsKill = isKill; IsDead = isDead; + IsUndef = isUndef; IsEarlyClobber = false; SubReg = 0; } @@ -206,11 +207,11 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { OS << "%mreg" << getReg(); } - if (getSubReg() != 0) { + if (getSubReg() != 0) OS << ':' << getSubReg(); - } - if (isDef() || isKill() || isDead() || isImplicit() || isEarlyClobber()) { + if (isDef() || isKill() || isDead() || isImplicit() || isUndef() || + isEarlyClobber()) { OS << '<'; bool NeedComma = false; if (isImplicit()) { @@ -224,10 +225,15 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { OS << "def"; NeedComma = true; } - if (isKill() || isDead()) { + if (isKill() || isDead() || isUndef()) { if (NeedComma) OS << ','; if (isKill()) OS << "kill"; if (isDead()) OS << "dead"; + if (isUndef()) { + if (isKill() || isDead()) + OS << ','; + OS << "undef"; + } } OS << '>'; } diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 41a42fd22d3..2caa2f9d180 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -905,6 +905,17 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) DOUT << tri_->getName(physReg) << '\n'; // Note the register is not really in use. vrm_->assignVirt2Phys(cur->reg, physReg); + // Since the register allocator is allowed to assign this virtual register + // physical register that overlaps other live intervals. Mark these + // operands as "Undef" which means later passes, e.g. register scavenger + // can ignore them. + for (MachineRegisterInfo::reg_iterator RI = mri_->reg_begin(cur->reg), + RE = mri_->reg_end(); RI != RE; ++RI) { + MachineOperand &MO = RI.getOperand(); + MO.setIsUndef(); + if (MO.isKill()) + MO.setIsKill(false); + } return; } diff --git a/lib/CodeGen/RegisterScavenging.cpp b/lib/CodeGen/RegisterScavenging.cpp index 3feb92fc46d..7d8e3afa789 100644 --- a/lib/CodeGen/RegisterScavenging.cpp +++ b/lib/CodeGen/RegisterScavenging.cpp @@ -36,7 +36,7 @@ static bool RedefinesSuperRegPart(const MachineInstr *MI, unsigned SubReg, bool SeenSuperDef = false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg()) + if (!MO.isReg() || MO.isUndef()) continue; if (TRI->isSuperRegister(SubReg, MO.getReg())) { if (MO.isUse()) @@ -57,28 +57,22 @@ static bool RedefinesSuperRegPart(const MachineInstr *MI, } /// setUsed - Set the register and its sub-registers as being used. -void RegScavenger::setUsed(unsigned Reg, bool ImpDef) { +void RegScavenger::setUsed(unsigned Reg) { RegsAvailable.reset(Reg); - ImplicitDefed[Reg] = ImpDef; for (const unsigned *SubRegs = TRI->getSubRegisters(Reg); - unsigned SubReg = *SubRegs; ++SubRegs) { + unsigned SubReg = *SubRegs; ++SubRegs) RegsAvailable.reset(SubReg); - ImplicitDefed[SubReg] = ImpDef; - } } /// setUnused - Set the register and its sub-registers as being unused. void RegScavenger::setUnused(unsigned Reg, const MachineInstr *MI) { RegsAvailable.set(Reg); - ImplicitDefed.reset(Reg); for (const unsigned *SubRegs = TRI->getSubRegisters(Reg); unsigned SubReg = *SubRegs; ++SubRegs) - if (!RedefinesSuperRegPart(MI, Reg, TRI)) { + if (!RedefinesSuperRegPart(MI, Reg, TRI)) RegsAvailable.set(SubReg); - ImplicitDefed.reset(SubReg); - } } void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) { @@ -94,7 +88,6 @@ void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) { if (!MBB) { NumPhysRegs = TRI->getNumRegs(); RegsAvailable.resize(NumPhysRegs); - ImplicitDefed.resize(NumPhysRegs); // Create reserved registers bitvector. ReservedRegs = TRI->getReservedRegs(MF); @@ -113,7 +106,6 @@ void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) { ScavengeRestore = NULL; CurrDist = 0; DistanceMap.clear(); - ImplicitDefed.reset(); // All registers started out unused. RegsAvailable.set(); @@ -195,15 +187,13 @@ void RegScavenger::forward() { ScavengeRestore = NULL; } - bool IsImpDef = MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF; - // Separate register operands into 3 classes: uses, defs, earlyclobbers. SmallVector, 4> UseMOs; SmallVector, 4> DefMOs; SmallVector, 4> EarlyClobberMOs; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg() || MO.getReg() == 0) + if (!MO.isReg() || MO.getReg() == 0 || MO.isUndef()) continue; if (MO.isUse()) UseMOs.push_back(std::make_pair(&MO,i)); @@ -221,14 +211,7 @@ void RegScavenger::forward() { assert(isUsed(Reg) && "Using an undefined register!"); - // Kill of implicit_def defined registers are ignored. e.g. - // entry: 0x2029ab8, LLVM BB @0x1b06080, ID#0: - // Live Ins: %R0 - // %R0 = IMPLICIT_DEF - // %R0 = IMPLICIT_DEF - // STR %R0, %R0, %reg0, 0, 14, %reg0, Mem:ST(4,4) [0x1b06510 + 0] - // %R1 = LDR %R0, %reg0, 24, 14, %reg0, Mem:LD(4,4) [0x1b065bc + 0] - if (MO.isKill() && !isReserved(Reg) && !isImplicitlyDefined(Reg)) { + if (MO.isKill() && !isReserved(Reg)) { KillRegs.set(Reg); // Mark sub-registers as used. @@ -274,10 +257,9 @@ void RegScavenger::forward() { // Implicit def is allowed to "re-define" any register. Similarly, // implicitly defined registers can be clobbered. assert((isReserved(Reg) || isUnused(Reg) || - IsImpDef || isImplicitlyDefined(Reg) || isLiveInButUnusedBefore(Reg, MI, MBB, TRI, MRI)) && "Re-defining a live register!"); - setUsed(Reg, IsImpDef); + setUsed(Reg); } } @@ -297,7 +279,7 @@ void RegScavenger::backward() { SmallVector, 4> EarlyClobberMOs; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg() || MO.getReg() == 0) + if (!MO.isReg() || MO.getReg() == 0 || MO.isUndef()) continue; if (MO.isUse()) UseMOs.push_back(std::make_pair(&MO,i)); diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp index e372b5b7533..79263393a1c 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp @@ -617,7 +617,7 @@ void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone, bool IsCloned, for (; NumVals; --NumVals, ++i) { unsigned Reg = cast(Node->getOperand(i))->getReg(); MI->addOperand(MachineOperand::CreateReg(Reg, true, false, false, - false, 0, true)); + false, false, true)); } break; case 1: // Use of register. diff --git a/lib/CodeGen/VirtRegRewriter.cpp b/lib/CodeGen/VirtRegRewriter.cpp index bd6584a53c1..bbf1e248731 100644 --- a/lib/CodeGen/VirtRegRewriter.cpp +++ b/lib/CodeGen/VirtRegRewriter.cpp @@ -356,7 +356,7 @@ static void InvalidateKills(MachineInstr &MI, SmallVector *KillRegs = NULL) { for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || !MO.isUse() || !MO.isKill()) + if (!MO.isReg() || !MO.isUse() || !MO.isKill() || MO.isUndef()) continue; unsigned Reg = MO.getReg(); if (TargetRegisterInfo::isVirtualRegister(Reg)) @@ -390,12 +390,12 @@ static bool InvalidateRegDef(MachineBasicBlock::iterator I, MachineOperand *DefOp = NULL; for (unsigned i = 0, e = DefMI->getNumOperands(); i != e; ++i) { MachineOperand &MO = DefMI->getOperand(i); - if (MO.isReg() && MO.isDef()) { - if (MO.getReg() == Reg) - DefOp = &MO; - else if (!MO.isDead()) - HasLiveDef = true; - } + if (!MO.isReg() || !MO.isUse() || !MO.isKill() || MO.isUndef()) + continue; + if (MO.getReg() == Reg) + DefOp = &MO; + else if (!MO.isDead()) + HasLiveDef = true; } if (!DefOp) return false; @@ -430,7 +430,7 @@ static void UpdateKills(MachineInstr &MI, const TargetRegisterInfo* TRI, std::vector &KillOps) { for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || !MO.isUse()) + if (!MO.isReg() || !MO.isUse() || MO.isUndef()) continue; unsigned Reg = MO.getReg(); if (Reg == 0) @@ -1289,8 +1289,7 @@ private: if (InvalidateRegDef(PrevMII, *MII, KillRegs[j], HasOtherDef)) { MachineInstr *DeadDef = PrevMII; if (ReMatDefs.count(DeadDef) && !HasOtherDef) { - // FIXME: This assumes a remat def does not have side - // effects. + // FIXME: This assumes a remat def does not have side effects. VRM.RemoveMachineInstrFromMaps(DeadDef); MBB.erase(DeadDef); ++NumDRM; @@ -1569,6 +1568,8 @@ private: if (MO.isImplicit()) // If the virtual register is implicitly defined, emit a implicit_def // before so scavenger knows it's "defined". + // FIXME: This is a horrible hack done the by register allocator to + // remat a definition with virtual register operand. VirtUseOps.insert(VirtUseOps.begin(), i); else VirtUseOps.push_back(i); @@ -1595,6 +1596,7 @@ private: MI.getOperand(i).setReg(RReg); MI.getOperand(i).setSubReg(0); if (VRM.isImplicitlyDefined(VirtReg)) + // FIXME: Is this needed? BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(TargetInstrInfo::IMPLICIT_DEF), RReg); continue; @@ -1604,22 +1606,16 @@ private: if (!MO.isUse()) continue; // Handle defs in the loop below (handle use&def here though) - bool AvoidReload = false; - if (LIs->hasInterval(VirtReg)) { - LiveInterval &LI = LIs->getInterval(VirtReg); - if (!LI.liveAt(LIs->getUseIndex(LI.beginNumber()))) - // Must be defined by an implicit def. It should not be spilled. Note, - // this is for correctness reason. e.g. - // 8 %reg1024 = IMPLICIT_DEF - // 12 %reg1024 = INSERT_SUBREG %reg1024, %reg1025, 2 - // The live range [12, 14) are not part of the r1024 live interval since - // it's defined by an implicit def. It will not conflicts with live - // interval of r1025. Now suppose both registers are spilled, you can - // easily see a situation where both registers are reloaded before - // the INSERT_SUBREG and both target registers that would overlap. - AvoidReload = true; - } - + bool AvoidReload = MO.isUndef(); + // Check if it is defined by an implicit def. It should not be spilled. + // Note, this is for correctness reason. e.g. + // 8 %reg1024 = IMPLICIT_DEF + // 12 %reg1024 = INSERT_SUBREG %reg1024, %reg1025, 2 + // The live range [12, 14) are not part of the r1024 live interval since + // it's defined by an implicit def. It will not conflicts with live + // interval of r1025. Now suppose both registers are spilled, you can + // easily see a situation where both registers are reloaded before + // the INSERT_SUBREG and both target registers that would overlap. bool DoReMat = VRM.isReMaterialized(VirtReg); int SSorRMId = DoReMat ? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg); diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index 21f71ec9a15..e5d84c50778 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -2459,7 +2459,8 @@ bool X86InstrInfo::unfoldMemoryOperand(MachineFunction &MF, MachineInstr *MI, getDefRegState(MO.isDef()) | RegState::Implicit | getKillRegState(MO.isKill()) | - getDeadRegState(MO.isDead())); + getDeadRegState(MO.isDead()) | + getUndefRegState(MO.isUndef())); } // Change CMP32ri r, 0 back to TEST32rr r, r, etc. unsigned NewOpc = 0; diff --git a/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll b/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll new file mode 100644 index 00000000000..27cad7ccf6b --- /dev/null +++ b/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll @@ -0,0 +1,122 @@ +; RUN: llvm-as < %s | llc -march=arm -mtriple=armv6-apple-darwin9 + +@nn = external global i32 ; [#uses=1] +@al_len = external global i32 ; [#uses=2] +@no_mat = external global i32 ; [#uses=2] +@no_mis = external global i32 ; [#uses=2] +@"\01LC12" = external constant [29 x i8], align 1 ; <[29 x i8]*> [#uses=1] +@"\01LC16" = external constant [33 x i8], align 1 ; <[33 x i8]*> [#uses=1] +@"\01LC17" = external constant [47 x i8], align 1 ; <[47 x i8]*> [#uses=1] + +declare arm_apcscc i32 @printf(i8* nocapture, ...) nounwind + +declare arm_apcscc void @diff(i8*, i8*, i32, i32, i32, i32) nounwind + +define arm_apcscc void @SIM(i8* %A, i8* %B, i32 %M, i32 %N, i32 %K, [256 x i32]* %V, i32 %Q, i32 %R, i32 %nseq) nounwind { +entry: + br i1 undef, label %bb5, label %bb + +bb: ; preds = %bb, %entry + br label %bb + +bb5: ; preds = %entry + br i1 undef, label %bb6, label %bb8 + +bb6: ; preds = %bb6, %bb5 + br i1 undef, label %bb8, label %bb6 + +bb8: ; preds = %bb6, %bb5 + br label %bb15 + +bb9: ; preds = %bb15 + br i1 undef, label %bb10, label %bb11 + +bb10: ; preds = %bb9 + unreachable + +bb11: ; preds = %bb9 + %0 = load i32* undef, align 4 ; [#uses=2] + %1 = add i32 %0, 1 ; [#uses=2] + store i32 %1, i32* undef, align 4 + %2 = load i32* undef, align 4 ; [#uses=1] + store i32 %2, i32* @nn, align 4 + store i32 0, i32* @al_len, align 4 + store i32 0, i32* @no_mat, align 4 + store i32 0, i32* @no_mis, align 4 + %3 = getelementptr i8* %B, i32 %0 ; [#uses=1] + tail call arm_apcscc void @diff(i8* undef, i8* %3, i32 undef, i32 undef, i32 undef, i32 undef) nounwind + %4 = sitofp i32 undef to double ; [#uses=1] + %5 = fdiv double %4, 1.000000e+01 ; [#uses=1] + %6 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([29 x i8]* @"\01LC12", i32 0, i32 0), double %5) nounwind ; [#uses=0] + %7 = load i32* @al_len, align 4 ; [#uses=1] + %8 = load i32* @no_mat, align 4 ; [#uses=1] + %9 = load i32* @no_mis, align 4 ; [#uses=1] + %10 = sub i32 %7, %8 ; [#uses=1] + %11 = sub i32 %10, %9 ; [#uses=1] + %12 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([33 x i8]* @"\01LC16", i32 0, i32 0), i32 %11) nounwind ; [#uses=0] + %13 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([47 x i8]* @"\01LC17", i32 0, i32 0), i32 undef, i32 %1, i32 undef, i32 undef) nounwind ; [#uses=0] + br i1 undef, label %bb15, label %bb12 + +bb12: ; preds = %bb11 + br label %bb228.i + +bb74.i: ; preds = %bb228.i + br i1 undef, label %bb138.i, label %bb145.i + +bb138.i: ; preds = %bb74.i + br label %bb145.i + +bb145.i: ; preds = %bb228.i, %bb138.i, %bb74.i + br i1 undef, label %bb146.i, label %bb151.i + +bb146.i: ; preds = %bb145.i + br i1 undef, label %bb228.i, label %bb151.i + +bb151.i: ; preds = %bb146.i, %bb145.i + br i1 undef, label %bb153.i, label %bb228.i + +bb153.i: ; preds = %bb151.i + br i1 undef, label %bb220.i, label %bb.nph.i98 + +bb.nph.i98: ; preds = %bb153.i + br label %bb158.i + +bb158.i: ; preds = %bb218.i, %bb.nph.i98 + br i1 undef, label %bb168.i, label %bb160.i + +bb160.i: ; preds = %bb158.i + br i1 undef, label %bb161.i, label %bb168.i + +bb161.i: ; preds = %bb160.i + br i1 undef, label %bb168.i, label %bb163.i + +bb163.i: ; preds = %bb161.i + br i1 undef, label %bb167.i, label %bb168.i + +bb167.i: ; preds = %bb163.i + br label %bb168.i + +bb168.i: ; preds = %bb167.i, %bb163.i, %bb161.i, %bb160.i, %bb158.i + br i1 undef, label %bb211.i, label %bb218.i + +bb211.i: ; preds = %bb168.i + br label %bb218.i + +bb218.i: ; preds = %bb211.i, %bb168.i + br i1 undef, label %bb220.i, label %bb158.i + +bb220.i: ; preds = %bb218.i, %bb153.i + br i1 undef, label %bb221.i, label %bb228.i + +bb221.i: ; preds = %bb220.i + br label %bb228.i + +bb228.i: ; preds = %bb221.i, %bb220.i, %bb151.i, %bb146.i, %bb12 + br i1 undef, label %bb74.i, label %bb145.i + +bb15: ; preds = %bb11, %bb8 + br i1 undef, label %return, label %bb9 + +return: ; preds = %bb15 + ret void +}