FOR and BRK on a ControlLogix: The Indexed Loop in Ladder, and the Scan It Eats
A 50 ms periodic task that had been running at 3.6 ms started reporting 41 ms, and the only change in the project was one new rung holding a FOR instruction with a terminal value of 499. Nothing was wrong. FOR calls a named routine once per index value, all of it inside a single scan of that one rung, so 500 passes of a routine costing 75 µs each is 37.5 ms of task time that was not there yesterday.
That is the trade. You get an indexed loop in ladder without writing five rungs of your own index arithmetic, and you pay for it in one lump, in one scan, in the task that holds the rung.
Everything here is a 1756-L83E on v34, ladder, with the array living at controller scope.
The five operands, and which one the instruction writes
Four of them you set. One of them the instruction owns.
Routine name is a ROUTINE tag — the routine you want executed, not a JSR call, and no parameters travel with it in either direction. Index is a SINT, INT or DINT tag, and this is the one that matters: the FOR instruction writes to it on every pass, adding the step size before it tests against the terminal value. Initial value is where the index starts, terminal value is where it stops, and the rule is exceeds, not equals, so 0 to 499 with a step of 1 gives you 500 passes and not 499. A negative step reverses the test and the loop ends once the index drops below the terminal value, which is how you sweep an array backwards without writing a second routine. Because there are no parameters, the called routine works on whatever it can see — controller-scoped tags, or program-scoped tags in the program that owns it — and two FOR instructions pointed at the same routine share every one of them.
The index tag is not yours to reuse. Write to it inside the called routine and you have changed the loop while it is running.

Terminal value 499 with step 1 runs indexes 0 through 499. The highlighted rows are the two that catch people: the instruction writes the index, and nothing is passed to the routine.
Where the scan actually goes
One number decides whether this instruction is free or fatal, and it is not the loop count.
It is the cost of one pass, and the only honest way to get it is to measure. Put a GSV on the Task object for the task that holds the FOR rung, read LastScanTime and MaxScanTime — both in microseconds — with the loop bypassed, then read them again with it running, and divide the difference by the number of passes. On a 50 ms periodic task, 500 passes at 75 µs leaves you 12 ms of headroom, which sounds comfortable until a higher-priority task interrupts partway through and MaxScanTime jumps. Watch OverlapCount on the same object: it counts the times the task was triggered while it was still executing, and it is the first number to move when a loop has quietly grown. The watchdog is the hard wall, configurable from 1 ms to 2,000,000 ms with a default of 500 ms, and when the loop takes longer than that the controller raises a major fault; the ControlLogix major fault codes page has the type and code lookup for what lands in the fault log.
Watchdog time includes interruptions by other tasks. Your loop did not have to be slow to blow it.

Arithmetic, not a measurement of your machine. The row that decides the answer is the cost of one pass, and it is the one you have to go and read.
BRK, and the latch that stops the second sweep
BRK ends the loop early and returns to the instruction that follows the calling FOR.
Not to the next rung of the calling routine, not to the top of the task — to the instruction after the FOR, which usually means the FOR rung finishes and the scan carries on as though the loop had run to its terminal value. That is what you want when you are searching an array and can stop at the first hit. The trap is in what you use as the break condition. Latch a bit inside the called routine, break on it, and you have written a loop that works perfectly the first time and then stops at index 0 on every execution afterwards, because nothing ever unlatched it. The symptom is beautifully misleading: the sweep reports one result, forever, and the array it is reading changes all day long. Clear the flag on the rung above the FOR, or use a tag the loop itself writes fresh each pass.
Only one loop level is affected. BRK breaks the loop that called this routine, and nothing above it.

The OTL on rung 1 of Scan_Buffer is the bug drawn deliberately. It is what makes rung 3 break the loop on pass 0 the second time the sweep runs.
The two faults with codes printed next to them
Most instructions in this chapter fault only through their operands. FOR has two of its own.
Nest routines more than 25 levels deep and you get a major fault of type 4, code 94. Point a FOR at an SFC routine that is already executing, which is a recursive call, and you get type 4, code 82. Twenty-five levels sounds unreachable until you remember that every JSR counts as well, and that a FOR inside a routine that was itself called by a FOR inside an AOI-free stack of utility routines adds up faster than anyone expects on a machine that has been maintained by four people over six years. Prescan and postscan behave differently from what the nesting suggests: the named routine is prescanned only once no matter how many FOR or JSR instructions call it, and it is postscanned exactly once.
Twenty-five is the count of levels, not the count of passes. The loop running 500 times is one level.
Where you cannot put it
Three restrictions, all of them structural.
FOR and BRK exist in ladder only — there is no function block version, and in structured text the equivalent is the FOR_DO construct with EXIT doing BRK’s job. Relay ladder Add-On Instructions cannot contain them at all, which is the one that bites when somebody tries to wrap a working array sweep into a reusable AOI and finds the instruction is not in the list. And the manual’s own advice on FOR_DO is worth reading across to the ladder instruction: the controller does not execute other statements in the routine until the loop completes, and it suggests considering a different construct such as IF_THEN instead. That is not a throwaway. Splitting a 500-element sweep into 50 elements per scan, with the index kept in a retentive tag, turns 37.5 ms in one scan into 3.75 ms in ten, and the machine does not care which one you chose. Structured Text for people who write ladder covers the six constructs if you want the loop in ST instead.
The dead end: blaming the loop
When a task starts overrunning after a loop goes in, the loop gets the blame and the loop is often not the problem.
Check first whether the FOR rung is true every scan when it only needs to be true on an edge. A sweep that exists to build a report does not need to run at 20 Hz; one-shot it, or drive it from a request bit the HMI sets, and the 37.5 ms becomes 37.5 ms once rather than 37.5 ms per period. The second thing to check is the array itself — a UDT with more members than the loop touches costs nothing to index but plenty to copy, and people frequently discover that the routine inside the loop is doing a COP of a whole structure when it needed two members. Moving a recipe into the PLC goes through the copy that breaks in exactly that shape. Only after those two is it worth optimising the instructions inside the loop, and by then the measurement from the Task object will tell you whether it was worth it.
Go and read LastScanTime and MaxScanTime on the task that holds your loop before you change anything. If MaxScanTime is inside a third of the period you are fine; if it is not, split the sweep across scans before the watchdog does it for you. For what those numbers mean in the wider picture, scan time and cycle time is the measurement method, and rung-by-rung ladder troubleshooting covers finding the rung that is actually costing you.