CMP or Five Rungs: One Expression Against the Discrete Compare Instructions
Page 358 of 1756-RM018A puts the bitwise AND at order 7 of a CMP expression and the comparison operators at order 10. So an expression reading level > 20 AND level < 80 is not the band test it looks like — the controller evaluates 20 AND level first, compares level against that, and hands the rung a result nobody can reconstruct from the text on the screen.
The operator that joins two comparisons is &&.
That is the single most useful thing to know about this instruction, and the rest follows from it. CMP earns its place when the decision contains arithmetic, or a string, or more terms than will fit comfortably across a rung. The discrete compares — EQ, NE, LT, LE, GT, GE — earn theirs everywhere else, mostly because each is a separate box that can be edited, cross-referenced and read on its own. Both live only in ladder diagram. Neither exists in structured text, where you write the operators directly instead.

Thirteen levels, printed on page 358 of the instruction reference. The two highlighted rows are four levels apart, and everything that goes wrong with a CMP expression happens between them.
What the expression actually buys
One operand can hold a whole decision, and sometimes that is the right shape for it.
The clearest case is arithmetic that exists only to be compared. (weight - tare) > 500 is one instruction; as discrete compares it is a SUB into a scratch tag on one rung and a GT on the next, which means two instructions, an extra tag, and a scan-order dependency between them that somebody will eventually break by moving a routine. Parentheses work the way you expect, functions like ABS, TRUNC, SQRT and the trigonometric set are available inside the expression, and the whole thing evaluates before the rung output is decided. For a test that is genuinely one thought — is this measurement, after correction, past this threshold — CMP is the honest representation of that thought.

Rung 21 is four boxes in series, each of which can be edited and cross-referenced by itself. Rung 20 is one operand that contains the whole decision.
One instruction, one tag fewer, and no rung between the subtraction and the test.
Strings are the other thing CMP does that is awkward anywhere else.
An expression can compare two string tags with =, <, <=, >, >= or <>, strings are equal when their characters match, and the comparison is case-sensitive — the reference is specific that uppercase A, $41, is not equal to lowercase a, $61. Ordering follows the hexadecimal values of the characters, which is the telephone-directory order for plain ASCII and is not the order a person would pick for anything containing digits. The EQ instruction handles string comparison too, and immediate string literals are available on the CompactLogix 5380, ControlLogix 5580, Compact GuardLogix 5380, GuardLogix 5580 and ControlLogix 5590 only, so a rung that compares a barcode against a typed-in literal will not move backwards onto a 5570 without a tag to hold the literal.
The order of operations, and the expression that lies to you
Read the order table once with a specific question in mind: where do the bitwise operators sit relative to the comparisons?
They sit above them. AND is order 7, XOR is 8, OR is 9, and the six comparison operators are all order 10, which means a bitwise operator inside an expression is resolved before any comparison it sits next to. That is exactly what you want in status AND 16#0F = 3
level > 20 AND level < 80, where the same rule produces nonsense that compiles. The operators for joining whole tests are &&, ^^ and || at orders 11, 12 and 13, below the comparisons, and they are there precisely so that (level > 20) && (level < 80) groups the way it reads.
The second row compiles, runs every scan and is wrong. Nothing in the software will tell you; the parentheses in rows three and four are what make the intent survive.
Use parentheses even where the table says you do not need them.
Why people still reach for five boxes
The argument against CMP is not correctness. It is what happens to the rung six months later.
A discrete compare puts each operand on the screen as its own field, so a GT with 20.0 in it is visibly a GT with 20.0 in it from three metres away, and the cross-reference lists that tag against that instruction. A CMP hides the same information inside a string — cross-reference still finds the tags, but the printout shows one long operand and the person reading it has to parse the expression in their head, including the precedence, to work out what the rung does. Online editing pulls the same way: with four boxes in series you can replace one and leave the other three untouched, while a CMP is one operand that gets retyped whole, and a typo in the middle of that retyping produces a syntactically valid expression that means something else. That is the same readability argument that decides when an alias tag helps and when it hides the problem, and it lands the same way: the version that is easier to write is not automatically the version that is easier to be wrong about.
The five-rung count in the title is not rhetorical either.
Boxes in series give you AND for free, so three conditions joined by AND are three boxes on one rung. The moment the logic contains an OR you need a branch, and the moment two of the terms need different one-shots or different latching you need separate rungs, which is how a condition that reads as one sentence in a CMP expression becomes four or five rungs of ladder. That is a real cost and it is the strongest argument for the expression.
The REAL conversion that turns an equality into a near miss
This one is documented, easy to miss, and it destroys equality tests on large integers.
The CMP page states the rule at the top: when the expression is evaluated, all non-REAL operands are converted to REAL before the calculation if any operand in the expression is REAL, or if the expression contains SIN, COS, TAN, ASIN, ACOS, ATAN, LN, LOG, DEG or RAD. So one REAL setpoint in a comparison drags every DINT in that expression through a REAL conversion. The common attributes chapter says what that costs: a REAL uses up to 24 bits for the base value — 23 stored plus a hidden bit — while a DINT uses 31 bits and a sign, and if the DINT value requires more than 24 significant bits it might not convert to the same value, in which case the controller stores the uppermost 24 bits rounded to the nearest even value. Past 16,777,216 the integers stop being individually representable. A production counter at 20,000,001 compared against a REAL target of 20000001.0 compares as 20,000,000 against 20,000,000 — equal, one count early, every time.

The last row is the one to remember: a DINT near the top of its range shifts by dozens after the conversion, and no flag is set because nothing overflowed.
Past 16,777,216 a REAL cannot hold every integer, and the comparison is the place it shows.
Keep integers with integers in an expression. A DINT compared against a DINT stays exact to the full range, and if the setpoint has to be a REAL because an HMI wrote it there, compare with >= rather than = and let the count cross the line rather than land on it. The same arithmetic is why a count used as evidence rather than as control wants its own treatment, which is the argument in sortation verification.
Every one of those rungs can carry a comment. An expression cannot.
What your printout will call these instructions
The mnemonics changed in one release and the old ones are still everywhere.
In Logix Designer version 36, EQU became EQ, NEQ became NE, GRT became GT, GEQ became GE, LES became LT and LEQ became LE — alongside MOV to MOVE, LIM to LIMIT and SQR to SQRT. The instructions are unchanged; only the names on the toolbar moved. Worth knowing that the reference itself slips here: the note on the LE page reads “the mnemonic for this instruction changed from LES to LE”, repeating the LT page’s old name, which is a typo rather than a second meaning for LES. CMP and MEQ kept their names throughout.
What to check next
Open every CMP in the project and search the expressions for a bare AND, OR or XOR sitting between two comparisons. Each one is either a deliberate bitwise operation — in which case it will have a mask constant next to it and will make sense — or it is a join that should have been &&, and the rung has been quietly wrong since it was written. Then check the operand types: any expression mixing a REAL with a DINT that can exceed sixteen million needs a second look, and any expression longer than about sixty characters wants to be boxes instead. A cross-reference on the tags inside those expressions is the fastest way to find them, and cross-referencing a tag in Studio 5000 to find every rung that writes it is the same two-minute job pointed at reads instead of writes. If the whole routine is heading for structured text anyway, the compare instructions do not come with it and the operators replace them one for one, which is covered in structured text for people who write ladder — along with the rest of the traps in common PLC programming mistakes.