9

What's the difference between or eax,eax and test eax,eax? I've seen different compilers produce both for the same comparison and as far as documentation goes they do exactly the same thing, so I'm wondering why they don't all use test eax,eax. Thinking about it and eax,eax would set the flags in an identical fashion as either but I haven't seen it in either freepascal, delphi, or msVC++.

I did compile some asm blocks in delphi and checked out the assembler source and all 3 forms are the exact same length in opcodes and also checked the intel performance PDF and it says they have the same latency and throughput.

Edit:
The question is specifically about the difference between the specific cases test eax,eax, or eax,eax and and eax,eax. All 3 give completely identical results for registers, flags, opcode length, latency, throughput. And yet for testing if 0, if not zero, or if signed, some compilers will use test eax,eax while some use or eax,eax, and I was wondering why they aren't all using test eax,eax since it makes the code very slightly clearer.

Edit2:
For reference I'm at home and only have and older msvc++ and Delphi here, but testing a variable if zero, msvc++ does test eax,eax, while Delphi does or eax,eax.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Marladu
  • 545
  • 5
  • 11
  • Based on register name, I've guessed [tag:x86]. If that's wrong, please re-tag your question with appropriate processor architecture. There's more than one, and they each have different assembly languages. – Damien_The_Unbeliever May 16 '14 at 06:17
  • You were right it was for x86, my bad for not putting it there. – Marladu May 16 '14 at 13:34
  • My answer on the linked duplicate has more detail about why `test` is better, including some reasons that weren't mentioned anywhere. The only reason these days to even consider `or same,same` is for P6-family CPUs where rewriting a register with itself keeps it "live" in out-of-order core, possibly avoiding / reducing register-read stalls when later instructions read the same register. But macro-fusion of test/jcc usually outweighs that, unless experiments show a specific hotspot benefits. But perhaps that, and not simply inertia, is why Delphi uses `or`. – Peter Cordes Jan 31 '18 at 22:37
  • `and` would be better than `or` (or at least never worse) because it can macro-fuse with jcc on Sandybridge-family. But it's still worse than `test` on more CPUs most of the time, and does still add a cycle of latency before later instructions can read the register. If you want to avoid register-read stalls on P6 and still get macro-fusion on SnB, use `and`. `or` / `jcc` is *always* sub-optimal if your code can run on CPUs that includes Sandybridge-family. – Peter Cordes Jan 31 '18 at 22:39

3 Answers3

7

In general, the only difference between test and and is that test <reg>, <reg> doesn't modify its operands. Essentially test applies an and operation, discarding the non-flags part of the result. If the operands are identical, the results will be the same (as will or).

test can be a superior instruction choice because of things like micro-op fusion. As a result, test is usually preferred unless the computation would have to be repeated. The same thing goes for cmp/sub.

Search Intel's doc for "fusion" and you should find the details.

gsg
  • 9,167
  • 1
  • 21
  • 23
  • 1
    I'll put more text in the main question in a sec, but the question was for the specific case "test eax,eax" "or eax,eax" "and eax,eax", which give completely identical results for registers, flags and opcode length. – Marladu May 16 '14 at 13:37
  • 2
    `or eax, eax` doesn't modify `eax` either. – Russell Borogove May 16 '14 at 19:16
  • Oh I _see_, you're talking about the specific case when the operands are the same. Sorry, I should have picked up on that. I'll edit a bit. – gsg May 17 '14 at 05:10
  • I guess this is as good an answer as it gets. I still don't understand why delphi 2006 was using "or eax,eax" instead of "test eax,eax" to test if variable=0. Mysteries! – Marladu May 17 '14 at 18:37
3

The circuitry to determine that the contents of eax after test eax, eax are the same as before the instruction is simpler than the circuitry required to arrive to that conclusion for or eax, eax. For this reason, test is better.

Some compilers may have generated or at a time when it did not make any difference (before out-of-order execution), but it will make a difference with some out-of-order processors nowadays (whereas yet other OOO processors will be so sophisticated that they will recognize or eax, eax as truly equivalent to test eax, eax).

I couldn't find a reference justifying that some modern processors are actually able to infer that or reg, reg does not modify reg, but here is an answer claiming it is the case for xchg reg, reg.

Community
  • 1
  • 1
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • `0x90` (the `xchg eax, reg` opcode with reg=eax) is a special case: it's recognized as a true NOP, but the 2-byte encoding of the same instruction using the opcode for the `xchg r, r/m32`, with a MODRM that encodes `eax,eax` (or any other same,same) is not special. In 32-bit mode `0x90` is also `xchg eax,eax`, but in 64-bit mode `xchg eax,eax` would zero-extend EAX into RAX, and `0x90` doesn't do that: [NOP has its own instruction reference manual entry](https://github.com/HJLebbink/asm-dude/wiki/NOP). So if you assemble `xchg eax,eax` in x86-64 mode, it has to use the 2-byte encoding. – Peter Cordes Jan 31 '18 at 22:30
2

Just to reiterate a little of, and add a little to, what @gsg indicated, the TEST instruction does a bitwise logical comparison (essentially ANDing them bitwise internally but not storing the result) of two operands and sets the processor flags according to the result of that operation. The OR instruction does a logical OR of the source with the destination, storing the result in the destination and sets the processor flags according to the result. They both affect the processor flags the same way. So when the operands are identical, the behavior is the same. There is no difference in flags. However, when the operands are different, their behavior is then quite different. You can also test for zero with and eax,eax which also affects the flags identically.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • Can you think of a value of eax where the specific instructions "test eax,eax" "or eax,eax" "and eax,eax" will give a different resulting register or flags? – Marladu May 16 '14 at 13:46
  • @Marladu `or`, `and`, and `test` affect flags *identically* (I corrected my answer) according to the result of the operation. So when the operands are identical (*e.g.*, `or eax,eax`, `test eax,eax`, `and eax,eax`) the flag results are identical. If the operands are different, then `test` and `and` will give the same flag results since they both do the AND operation, but the `test` won't affect the operand values. OR may give different flag results depending upon the different operand values. – lurker May 16 '14 at 14:03