diff --git a/lib/CodeGen/RegAllocGreedy.cpp b/lib/CodeGen/RegAllocGreedy.cpp index ca4a941e245..b969dd71757 100644 --- a/lib/CodeGen/RegAllocGreedy.cpp +++ b/lib/CodeGen/RegAllocGreedy.cpp @@ -60,6 +60,17 @@ SplitSpillMode("split-spill-mode", cl::Hidden, clEnumValEnd), cl::init(SplitEditor::SM_Partition)); +static cl::opt +LastChanceRecoloringMaxDepth("lcr-max-depth", cl::Hidden, + cl::desc("Last chance recoloring max depth"), + cl::init(5)); + +static cl::opt LastChanceRecoloringMaxInterference( + "lcr-max-interf", cl::Hidden, + cl::desc("Last chance recoloring maximum number of considered" + " interference at a time"), + cl::init(8)); + static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator", createGreedyRegisterAllocator); @@ -67,6 +78,10 @@ namespace { class RAGreedy : public MachineFunctionPass, public RegAllocBase, private LiveRangeEdit::Delegate { + // Convenient shortcuts. + typedef std::priority_queue > PQueue; + typedef SmallPtrSet SmallLISet; + typedef SmallSet SmallVirtRegSet; // context MachineFunction *MF; @@ -87,7 +102,7 @@ class RAGreedy : public MachineFunctionPass, // state OwningPtr SpillerInstance; - std::priority_queue > Queue; + PQueue Queue; unsigned NextCascade; // Live ranges pass through a number of stages as we try to allocate them. @@ -261,9 +276,14 @@ public: static char ID; private: + unsigned selectOrSplitImpl(LiveInterval &, SmallVectorImpl &, + SmallVirtRegSet &, unsigned = 0); + bool LRE_CanEraseVirtReg(unsigned); void LRE_WillShrinkVirtReg(unsigned); void LRE_DidCloneVirtReg(unsigned, unsigned); + void enqueue(PQueue &CurQueue, LiveInterval *LI); + LiveInterval *dequeue(PQueue &CurQueue); BlockFrequency calcSpillCost(); bool addSplitConstraints(InterferenceCache::Cursor, BlockFrequency&); @@ -278,6 +298,9 @@ private: bool canEvictInterference(LiveInterval&, unsigned, bool, EvictionCost&); void evictInterference(LiveInterval&, unsigned, SmallVectorImpl&); + bool mayRecolorAllInterferences(unsigned PhysReg, LiveInterval &VirtReg, + SmallLISet &RecoloringCandidates, + const SmallVirtRegSet &FixedRegisters); unsigned tryAssign(LiveInterval&, AllocationOrder&, SmallVectorImpl&); @@ -293,6 +316,11 @@ private: SmallVectorImpl&); unsigned trySplit(LiveInterval&, AllocationOrder&, SmallVectorImpl&); + unsigned tryLastChanceRecoloring(LiveInterval &, AllocationOrder &, + SmallVectorImpl &, + SmallVirtRegSet &, unsigned); + bool tryRecoloringCandidates(PQueue &, SmallVectorImpl &, + SmallVirtRegSet &, unsigned); }; } // end anonymous namespace @@ -406,7 +434,9 @@ void RAGreedy::releaseMemory() { GlobalCand.clear(); } -void RAGreedy::enqueue(LiveInterval *LI) { +void RAGreedy::enqueue(LiveInterval *LI) { enqueue(Queue, LI); } + +void RAGreedy::enqueue(PQueue &CurQueue, LiveInterval *LI) { // Prioritize live ranges by size, assigning larger ranges first. // The queue holds (size, reg) pairs. const unsigned Size = LI->getSize(); @@ -453,14 +483,16 @@ void RAGreedy::enqueue(LiveInterval *LI) { } // The virtual register number is a tie breaker for same-sized ranges. // Give lower vreg numbers higher priority to assign them first. - Queue.push(std::make_pair(Prio, ~Reg)); + CurQueue.push(std::make_pair(Prio, ~Reg)); } -LiveInterval *RAGreedy::dequeue() { - if (Queue.empty()) +LiveInterval *RAGreedy::dequeue() { return dequeue(Queue); } + +LiveInterval *RAGreedy::dequeue(PQueue &CurQueue) { + if (CurQueue.empty()) return 0; - LiveInterval *LI = &LIS->getInterval(~Queue.top().second); - Queue.pop(); + LiveInterval *LI = &LIS->getInterval(~CurQueue.top().second); + CurQueue.pop(); return LI; } @@ -1810,6 +1842,220 @@ unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, return tryBlockSplit(VirtReg, Order, NewVRegs); } +//===----------------------------------------------------------------------===// +// Last Chance Recoloring +//===----------------------------------------------------------------------===// + +/// mayRecolorAllInterferences - Check if the virtual registers that +/// interfere with \p VirtReg on \p PhysReg (or one of its aliases) may be +/// recolored to free \p PhysReg. +/// When true is returned, \p RecoloringCandidates has been augmented with all +/// the live intervals that need to be recolored in order to free \p PhysReg +/// for \p VirtReg. +/// \p FixedRegisters contains all the virtual registers that cannot be +/// recolored. +bool +RAGreedy::mayRecolorAllInterferences(unsigned PhysReg, LiveInterval &VirtReg, + SmallLISet &RecoloringCandidates, + const SmallVirtRegSet &FixedRegisters) { + const TargetRegisterClass *CurRC = MRI->getRegClass(VirtReg.reg); + + for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { + LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, *Units); + // If there is LastChanceRecoloringMaxInterference or more interferences, + // chances are one would not be recolorable. + if (Q.collectInterferingVRegs(LastChanceRecoloringMaxInterference) >= + LastChanceRecoloringMaxInterference) { + DEBUG(dbgs() << "Early abort: too many interferences.\n"); + return false; + } + for (unsigned i = Q.interferingVRegs().size(); i; --i) { + LiveInterval *Intf = Q.interferingVRegs()[i - 1]; + // If Intf is done and sit on the same register class as VirtReg, + // it would not be recolorable as it is in the same state as VirtReg. + if ((getStage(*Intf) == RS_Done && + MRI->getRegClass(Intf->reg) == CurRC) || + FixedRegisters.count(Intf->reg)) { + DEBUG(dbgs() << "Early abort: the inteference is not recolorable.\n"); + return false; + } + RecoloringCandidates.insert(Intf); + } + } + return true; +} + +/// tryLastChanceRecoloring - Try to assign a color to \p VirtReg by recoloring +/// its interferences. +/// Last chance recoloring chooses a color for \p VirtReg and recolors every +/// virtual register that was using it. The recoloring process may recursively +/// use the last chance recoloring. Therefore, when a virtual register has been +/// assigned a color by this mechanism, it is marked as Fixed, i.e., it cannot +/// be last-chance-recolored again during this recoloring "session". +/// E.g., +/// Let +/// vA can use {R1, R2 } +/// vB can use { R2, R3} +/// vC can use {R1 } +/// Where vA, vB, and vC cannot be split anymore (they are reloads for +/// instance) and they all interfere. +/// +/// vA is assigned R1 +/// vB is assigned R2 +/// vC tries to evict vA but vA is already done. +/// Regular register allocation fails. +/// +/// Last chance recoloring kicks in: +/// vC does as if vA was evicted => vC uses R1. +/// vC is marked as fixed. +/// vA needs to find a color. +/// None are available. +/// vA cannot evict vC: vC is a fixed virtual register now. +/// vA does as if vB was evicted => vA uses R2. +/// vB needs to find a color. +/// R3 is available. +/// Recoloring => vC = R1, vA = R2, vB = R3 +/// +/// \p Order defines the prefered allocation order for \p VirtReg. +/// \p NewRegs will contain any new virtual register that have been created +/// (split, spill) during the process and that must be assigned. +/// \p FixedRegisters contains all the virtual registers that cannot be +/// recolored. +/// \p Depth gives the current depth of the last chance recoloring. +/// \return a physical register that can be used for VirtReg or ~0u if none +/// exists. +unsigned RAGreedy::tryLastChanceRecoloring(LiveInterval &VirtReg, + AllocationOrder &Order, + SmallVectorImpl &NewVRegs, + SmallVirtRegSet &FixedRegisters, + unsigned Depth) { + DEBUG(dbgs() << "Try last chance recoloring for " << VirtReg << '\n'); + // Ranges must be Done. + assert(getStage(VirtReg) >= RS_Done && + "Last chance recoloring should really be last chance"); + // Set the max depth to LastChanceRecoloringMaxDepth. + // We may want to reconsider that if we end up with a too large search space + // for target with hundreds of registers. + // Indeed, in that case we may want to cut the search space earlier. + if (Depth >= LastChanceRecoloringMaxDepth) { + DEBUG(dbgs() << "Abort because max depth has been reached.\n"); + return ~0u; + } + + // Set of Live intervals that will need to be recolored. + SmallLISet RecoloringCandidates; + // Record the original mapping virtual register to physical register in case + // the recoloring fails. + DenseMap VirtRegToPhysReg; + // Mark VirtReg as fixed, i.e., it will not be recolored pass this point in + // this recoloring "session". + FixedRegisters.insert(VirtReg.reg); + + Order.rewind(); + while (unsigned PhysReg = Order.next()) { + DEBUG(dbgs() << "Try to assign: " << VirtReg << " to " + << PrintReg(PhysReg, TRI) << '\n'); + RecoloringCandidates.clear(); + VirtRegToPhysReg.clear(); + + // It is only possible to recolor virtual register interference. + if (Matrix->checkInterference(VirtReg, PhysReg) > + LiveRegMatrix::IK_VirtReg) { + DEBUG(dbgs() << "Some inteferences are not with virtual registers.\n"); + + continue; + } + + // Early give up on this PhysReg if it is obvious we cannot recolor all + // the interferences. + if (!mayRecolorAllInterferences(PhysReg, VirtReg, RecoloringCandidates, + FixedRegisters)) { + DEBUG(dbgs() << "Some inteferences cannot be recolored.\n"); + continue; + } + + // RecoloringCandidates contains all the virtual registers that interfer + // with VirtReg on PhysReg (or one of its aliases). + // Enqueue them for recoloring and perform the actual recoloring. + PQueue RecoloringQueue; + for (SmallLISet::iterator It = RecoloringCandidates.begin(), + EndIt = RecoloringCandidates.end(); + It != EndIt; ++It) { + unsigned ItVirtReg = (*It)->reg; + enqueue(RecoloringQueue, *It); + assert(VRM->hasPhys(ItVirtReg) && + "Interferences are supposed to be with allocated vairables"); + + // Record the current allocation. + VirtRegToPhysReg[ItVirtReg] = VRM->getPhys(ItVirtReg); + // unset the related struct. + Matrix->unassign(**It); + } + + // Do as if VirtReg was assigned to PhysReg so that the underlying + // recoloring has the right information about the interferes and + // available colors. + Matrix->assign(VirtReg, PhysReg); + + // Save the current recoloring state. + // If we cannot recolor all the interferences, we will have to start again + // at this point for the next physical register. + SmallVirtRegSet SaveFixedRegisters(FixedRegisters); + if (tryRecoloringCandidates(RecoloringQueue, NewVRegs, FixedRegisters, + Depth)) { + // Do not mess up with the global assignment process. + // I.e., VirtReg must be unassigned. + Matrix->unassign(VirtReg); + return PhysReg; + } + + DEBUG(dbgs() << "Fail to assign: " << VirtReg << " to " + << PrintReg(PhysReg, TRI) << '\n'); + + // The recoloring attempt failed, undo the changes. + FixedRegisters = SaveFixedRegisters; + Matrix->unassign(VirtReg); + + for (SmallLISet::iterator It = RecoloringCandidates.begin(), + EndIt = RecoloringCandidates.end(); + It != EndIt; ++It) { + unsigned ItVirtReg = (*It)->reg; + if (VRM->hasPhys(ItVirtReg)) + Matrix->unassign(**It); + Matrix->assign(**It, VirtRegToPhysReg[ItVirtReg]); + } + } + + // Last chance recoloring did not worked either, give up. + return ~0u; +} + +/// tryRecoloringCandidates - Try to assign a new color to every register +/// in \RecoloringQueue. +/// \p NewRegs will contain any new virtual register created during the +/// recoloring process. +/// \p FixedRegisters[in/out] contains all the registers that have been +/// recolored. +/// \return true if all virtual registers in RecoloringQueue were successfully +/// recolored, false otherwise. +bool RAGreedy::tryRecoloringCandidates(PQueue &RecoloringQueue, + SmallVectorImpl &NewVRegs, + SmallVirtRegSet &FixedRegisters, + unsigned Depth) { + while (!RecoloringQueue.empty()) { + LiveInterval *LI = dequeue(RecoloringQueue); + DEBUG(dbgs() << "Try to recolor: " << *LI << '\n'); + unsigned PhysReg; + PhysReg = selectOrSplitImpl(*LI, NewVRegs, FixedRegisters, Depth + 1); + if (PhysReg == ~0u || !PhysReg) + return false; + DEBUG(dbgs() << "Recoloring of " << *LI + << " succeeded with: " << PrintReg(PhysReg, TRI) << '\n'); + Matrix->assign(*LI, PhysReg); + FixedRegisters.insert(LI->reg); + } + return true; +} //===----------------------------------------------------------------------===// // Main Entry Point @@ -1817,6 +2063,14 @@ unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, SmallVectorImpl &NewVRegs) { + SmallVirtRegSet FixedRegisters; + return selectOrSplitImpl(VirtReg, NewVRegs, FixedRegisters); +} + +unsigned RAGreedy::selectOrSplitImpl(LiveInterval &VirtReg, + SmallVectorImpl &NewVRegs, + SmallVirtRegSet &FixedRegisters, + unsigned Depth) { // First try assigning a free register. AllocationOrder Order(VirtReg.reg, *VRM, RegClassInfo); if (unsigned PhysReg = tryAssign(VirtReg, Order, NewVRegs)) @@ -1848,7 +2102,8 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, // If we couldn't allocate a register from spilling, there is probably some // invalid inline assembly. The base class wil report it. if (Stage >= RS_Done || !VirtReg.isSpillable()) - return ~0u; + return tryLastChanceRecoloring(VirtReg, Order, NewVRegs, FixedRegisters, + Depth); // Try splitting VirtReg or interferences. unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs); diff --git a/test/CodeGen/X86/ragreedy-last-chance-recoloring.ll b/test/CodeGen/X86/ragreedy-last-chance-recoloring.ll new file mode 100644 index 00000000000..f3669fbdbdd --- /dev/null +++ b/test/CodeGen/X86/ragreedy-last-chance-recoloring.ll @@ -0,0 +1,168 @@ +; RUN: llc -regalloc=greedy -relocation-model=pic < %s 2>&1 | FileCheck %s +; Without the last chance recoloring, this test fails with: +; "ran out of registers". + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128" +target triple = "i386-apple-macosx" + +@fp_dh_36985b17790d59a27994eaab5dcb00ee = external constant [499 x i32] +@fp_dh_18716afa4a5354de0a302c8edb3b0ee1 = external global i32 +@fp_dh_20a33cdeefab8f4c8887e82766cb9dcb = external global i8* +@fp_dh_9d93c897906e39883c58b034c8e786b2 = external global [5419648 x i8], align 16 + +; Function Attrs: nounwind ssp +; CHECK-NOT: ran out of registers during register allocation +define void @fp_dh_f870bf31fd8ffe068450366e3f05389a(i8* %arg) #0 { +bb: + indirectbr i8* undef, [label %bb85, label %bb206] + +bb85: ; preds = %bb222, %bb85, %bb + store i8* blockaddress(@fp_dh_f870bf31fd8ffe068450366e3f05389a, %bb206), i8** undef, align 4 + indirectbr i8* undef, [label %bb439, label %bb85] + +bb206: ; preds = %bb + %tmp = getelementptr [499 x i32]* @fp_dh_36985b17790d59a27994eaab5dcb00ee, i32 0, i32 undef + %tmp207 = load i32* %tmp + %tmp208 = add i32 %tmp207, 1 + %tmp209 = inttoptr i32 %tmp208 to i8* + indirectbr i8* %tmp209, [label %bb213] + +bb213: ; preds = %bb206 + %tmp214 = load i32* @fp_dh_18716afa4a5354de0a302c8edb3b0ee1, align 4 + %tmp215 = load i8** @fp_dh_20a33cdeefab8f4c8887e82766cb9dcb, align 4 + %tmp216 = urem i32 -717428541, %tmp214 + %tmp217 = getelementptr i8* %tmp215, i32 %tmp216 + %tmp218 = bitcast i8* %tmp217 to i32* + %tmp219 = load i32* %tmp218, align 4 + store i32 %tmp219, i32* undef, align 4 + %tmp220 = select i1 false, i32 359373646, i32 1677237955 + %tmp221 = add i32 %tmp220, 0 + indirectbr i8* undef, [label %bb432, label %bb222] + +bb222: ; preds = %bb213 + %tmp224 = load i32* undef, align 4 + %tmp225 = load i32* undef, align 4 + %tmp226 = xor i32 %tmp225, %tmp224 + %tmp227 = shl i32 %tmp226, 1 + %tmp228 = and i32 %tmp227, -2048880334 + %tmp229 = sub i32 0, %tmp228 + %tmp230 = add i32 0, %tmp229 + %tmp231 = xor i32 %tmp230, 1059356227 + %tmp232 = mul i32 %tmp231, 1603744721 + %tmp233 = urem i32 %tmp232, 259 + %tmp234 = getelementptr [259 x i8]* bitcast (i8* getelementptr inbounds ([5419648 x i8]* @fp_dh_9d93c897906e39883c58b034c8e786b2, i32 0, i32 2039075) to [259 x i8]*), i32 0, i32 %tmp233 + %tmp235 = load i8* %tmp234, align 1 + %tmp236 = add i32 %tmp233, 2 + %tmp237 = getelementptr [264 x i8]* bitcast (i8* getelementptr inbounds ([5419648 x i8]* @fp_dh_9d93c897906e39883c58b034c8e786b2, i32 0, i32 3388166) to [264 x i8]*), i32 0, i32 %tmp236 + %tmp238 = load i8* %tmp237, align 1 + %tmp239 = getelementptr [265 x i8]* bitcast (i8* getelementptr inbounds ([5419648 x i8]* @fp_dh_9d93c897906e39883c58b034c8e786b2, i32 0, i32 1325165) to [265 x i8]*), i32 0, i32 0 + %tmp240 = load i8* %tmp239, align 1 + %tmp241 = add i32 %tmp233, 6 + %tmp242 = trunc i32 %tmp241 to i8 + %tmp243 = mul i8 %tmp242, -3 + %tmp244 = add i8 %tmp243, 3 + %tmp245 = mul i8 %tmp242, -6 + %tmp246 = and i8 %tmp245, 6 + %tmp247 = sub i8 0, %tmp246 + %tmp248 = add i8 %tmp244, %tmp247 + %tmp249 = load i8* undef, align 1 + %tmp250 = xor i8 %tmp235, 17 + %tmp251 = xor i8 %tmp250, %tmp238 + %tmp252 = xor i8 %tmp251, %tmp240 + %tmp253 = xor i8 %tmp252, %tmp249 + %tmp254 = xor i8 %tmp253, %tmp248 + %tmp255 = zext i8 %tmp254 to i16 + %tmp256 = shl nuw i16 %tmp255, 8 + %tmp257 = load i8* null, align 1 + %tmp258 = load i32* @fp_dh_18716afa4a5354de0a302c8edb3b0ee1, align 4 + %tmp259 = load i8** @fp_dh_20a33cdeefab8f4c8887e82766cb9dcb, align 4 + %tmp260 = urem i32 -717428541, %tmp258 + %tmp261 = getelementptr i8* %tmp259, i32 %tmp260 + %tmp262 = bitcast i8* %tmp261 to i32* + %tmp263 = load i32* %tmp262, align 4 + %tmp264 = xor i32 %tmp263, 0 + %tmp265 = shl i32 %tmp264, 1 + %tmp266 = and i32 %tmp265, -1312119832 + %tmp267 = sub i32 0, %tmp266 + %tmp268 = add i32 0, %tmp267 + %tmp269 = xor i32 %tmp268, 623994670 + %tmp270 = mul i32 %tmp269, 1603744721 + %tmp271 = urem i32 %tmp270, 259 + %tmp274 = add i32 %tmp271, 3 + %tmp275 = getelementptr [265 x i8]* bitcast (i8* getelementptr inbounds ([5419648 x i8]* @fp_dh_9d93c897906e39883c58b034c8e786b2, i32 0, i32 1325165) to [265 x i8]*), i32 0, i32 %tmp274 + %tmp276 = load i8* %tmp275, align 1 + %tmp277 = add i32 %tmp271, 6 + %tmp278 = trunc i32 %tmp277 to i8 + %tmp279 = mul i8 %tmp278, -3 + %tmp280 = add i8 %tmp279, 31 + %tmp281 = add i8 %tmp280, 0 + %tmp282 = xor i8 %tmp257, 13 + %tmp283 = xor i8 %tmp282, 0 + %tmp284 = xor i8 %tmp283, 0 + %tmp285 = xor i8 %tmp284, %tmp276 + %tmp286 = xor i8 %tmp285, %tmp281 + %tmp287 = zext i8 %tmp286 to i16 + %tmp288 = or i16 %tmp287, %tmp256 + %tmp289 = xor i16 %tmp288, 14330 + %tmp290 = add i16 0, %tmp289 + %tmp291 = add i16 %tmp290, -14330 + %tmp292 = zext i16 %tmp291 to i32 + %tmp293 = add i16 %tmp290, -14330 + %tmp294 = lshr i16 %tmp293, 12 + %tmp295 = zext i16 %tmp294 to i32 + %tmp296 = sub i32 0, %tmp295 + %tmp297 = xor i32 %tmp296, 16 + %tmp298 = add i32 0, %tmp297 + %tmp299 = and i32 %tmp298, 31 + %tmp300 = and i32 %tmp292, 30864 + %tmp301 = shl i32 %tmp300, %tmp299 + %tmp302 = xor i32 0, %tmp301 + %tmp303 = add i32 0, %tmp302 + %tmp304 = and i32 %tmp298, 31 + %tmp305 = and i32 %tmp303, 25568 + %tmp306 = lshr i32 %tmp305, %tmp304 + %tmp307 = xor i32 0, %tmp306 + %tmp308 = add i32 0, %tmp307 + %tmp309 = trunc i32 %tmp308 to i16 + %tmp310 = shl i16 %tmp309, 1 + %tmp311 = and i16 %tmp310, -4648 + %tmp312 = shl i16 %tmp309, 1 + %tmp313 = and i16 %tmp312, 4646 + %tmp314 = xor i16 %tmp311, 17700 + %tmp315 = xor i16 %tmp313, 17700 + %tmp316 = add i16 %tmp314, %tmp315 + %tmp317 = and i16 %tmp314, %tmp315 + %tmp318 = shl nuw i16 %tmp317, 1 + %tmp319 = sub i16 0, %tmp318 + %tmp320 = add i16 %tmp316, %tmp319 + %tmp321 = and i16 %tmp320, 29906 + %tmp322 = xor i16 %tmp309, 14953 + %tmp323 = add i16 0, %tmp322 + %tmp324 = sub i16 0, %tmp321 + %tmp325 = xor i16 %tmp324, %tmp323 + %tmp326 = add i16 0, %tmp325 + %tmp327 = add i32 %tmp221, 1161362661 + %tmp333 = icmp eq i16 %tmp326, 14953 + %tmp334 = add i32 %tmp327, -1456704142 + %tmp335 = zext i1 %tmp333 to i32 + %tmp336 = add i32 %tmp334, %tmp335 + %tmp337 = getelementptr [499 x i32]* @fp_dh_36985b17790d59a27994eaab5dcb00ee, i32 0, i32 %tmp336 + %tmp338 = load i32* %tmp337 + %tmp339 = add i32 %tmp338, 1 + %tmp340 = inttoptr i32 %tmp339 to i8* + indirectbr i8* %tmp340, [label %bb85, label %bb439] + +bb432: ; preds = %bb432, %bb213 + %tmp433 = phi i32 [ %tmp221, %bb213 ], [ %tmp433, %bb432 ] + %tmp434 = add i32 %tmp433, 1022523279 + %tmp435 = getelementptr [499 x i32]* @fp_dh_36985b17790d59a27994eaab5dcb00ee, i32 0, i32 %tmp434 + %tmp436 = load i32* %tmp435 + %tmp437 = add i32 %tmp436, 1 + %tmp438 = inttoptr i32 %tmp437 to i8* + indirectbr i8* %tmp438, [label %bb432] + +bb439: ; preds = %bb222, %bb85 + ret void +} + +attributes #0 = { nounwind ssp "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }