Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CMP vs TEST

6,817 views
Skip to first unread message

Brett Wilson

unread,
Mar 13, 1997, 3:00:00 AM3/13/97
to

Hello:

I have always just used CMP when I need to test numbers. I have seen
TEST also used in many places. Can someone explain what the
advantages/disadvantages of these instructions are?

Thanks in advance.

-- Brett Wilson --

Paul Mesken

unread,
Mar 13, 1997, 3:00:00 AM3/13/97
to

With TEST you can check for one or more certain bits to be set (or all
of the certain bits to be cleared). TEST is an AND function that
doesn't change the destination operand but sets the flags.

With CMP you can check a value to be below, equal, above etc. a
certain value. CMP is a SUB function that doesn't change the
destination operand but sets the flags.


"Tough talk for a guy who was fooled into believing he
was in real mode by a mere memory manager."

usu...@euronet.nl Paul Mesken aka Technocrate

Rick Warner

unread,
Mar 13, 1997, 3:00:00 AM3/13/97
to

Brett Wilson wrote:
>
> Hello:
>
> I have always just used CMP when I need to test numbers. I have seen
> TEST also used in many places. Can someone explain what the
> advantages/disadvantages of these instructions are?
>
> Thanks in advance.
>
> -- Brett Wilson --
CMP does a subtration or the second parm from the first, w/o changing
them. TEST does an AND w/o changing them. I don't know what TEST does
to the flags though. Sorry I can't help more

michael james perry

unread,
Mar 14, 1997, 3:00:00 AM3/14/97
to

Rick Warner <ninm...@ma.ultranet.com> writes:

>Brett Wilson wrote:
>>
>> Hello:
>>
>> I have always just used CMP when I need to test numbers. I have seen
>> TEST also used in many places. Can someone explain what the
>> advantages/disadvantages of these instructions are?
>>

test peforms the logical AND of its two operands without storing the result.
the overflow and carry flags are cleared, and the sign, zero and parity
flags are updated. The auxillary carry flag is undefined after the operation.

Always use TEST when testing for bits. The reason for this is that the processor knows that this instruction doesnt write its result and hence will not
stall the pipeline in cases where using CMP (or AND, or some instruction.. I forget the example) would cause a pipeline stall.

--
// "C makes it easy to shoot yourself in the foot. C++ makes it
// harder, but when you do, it blows away your whole leg."
//
// -- Bjarne Stroustrup on C++

SAMUEL IGWE

unread,
Mar 14, 1997, 3:00:00 AM3/14/97
to bre...@uclink4.berkeley.edu

The TEST instruction performs a logical "AND" which sets the flag
registers but does not affect the destination. TEST is used to determine
the value of bits in a byte

for example: given 10000001 in al

TEST al,01h ;clears the zero flag since bit 0 is 1 (set)
;follow with a
jnz @@bit_is_set
;else
jz @@bits_is_cleared
;or just use an unconditional jump here


;you can use the TEST instruction to determine whether or not a register
;or memory location contains the value 0

TEST al,0ffh ;
jz @@result_zero
;else
jmp @@not_zero

below is the truth table for the "AND" logic. remember that TEST is the
equivalent relationship between the SUB command and the CMP command. one
preserves the destination and source while the other does not.

operand 1 operand2 and result
0 0 0
0 1 0
1 0 0
1 1 1 ;result is 1 only if both bits are 1
(logical high)


contact me if in need of more detailed info. hope this helps
SAM...@worldnet.att.net

SAMUEL IGWE

unread,
Mar 14, 1997, 3:00:00 AM3/14/97
to bre...@uclink4.berkeley.edu

SAMUEL IGWE

unread,
Mar 14, 1997, 3:00:00 AM3/14/97
to bre...@uclink4.berkeley.edu

Simon Hosie

unread,
Mar 14, 1997, 3:00:00 AM3/14/97
to

michael james perry:

> Always use TEST when testing for bits. The reason for this is that the
> processor knows that this instruction doesnt write its result and hence
> will not stall the pipeline in cases where using CMP (or AND, or some
> instruction.. I forget the example) would cause a pipeline stall.

Why should CMP cause a pipeline stall? Have you got AND and CMP crossed
over, or what?

Bastin,kim

unread,
Mar 15, 1997, 3:00:00 AM3/15/97
to

Brett Wilson (bre...@uclink4.berkeley.edu) wrote:
: Hello:

: I have always just used CMP when I need to test numbers. I have seen
: TEST also used in many places. Can someone explain what the
: advantages/disadvantages of these instructions are?

There are only a couple of cases where either CMP or TEST could be used.
The most important one is testing for zero, e.g. CMP AL,0 or TEST AL,AL.
The latter is better because, as indicated, you can TEST the register
against itself instead of against the immediate value 0, resulting in a
smaller instruction. OR AL,AL and AND AL,AL could also be used in a
similar way but should be avoided as they cause the CPU to write a result
to AL, which can cause a delay in the execution of a subsequent
instruction that uses the contents of EAX. In all of these cases, ZF
is set if the register is equal to zero.

The other case where you can sometimes use TEST instead of CMP is an
unsigned compare with a power of 2. TEST is only useful if you want to
know if a register value is below or equal_or_greater. E.g. CMP AL,8 sets
CF iff AL < 8. TEST AL,11111000b sets ZF iff AL < 8. On the other hand,
if you want to know whether AL = 8, use CMP AL,8.

Kim

Daniel Mantione

unread,
Mar 17, 1997, 3:00:00 AM3/17/97
to

Nonsense. cmp al,0 and test al,al take both two bytes. On a 8086 the
latter way saves you one clock cycle, that's all. Does anyone program
for a 8086 in 1997? This is not true for cmp ax,0 ; in that case the
test ax,ax saves you one byte.

Daniel Mantione

David Cotgrave

unread,
Mar 17, 1997, 3:00:00 AM3/17/97
to

gum...@airdmhor.gen.nz.NOSPAM,Internet writes:

> Why should CMP cause a pipeline stall? Have you got AND and CMP
>crossed
>over, or what?

i didnt think AND or CMP would cause a pipeline stall??

enlighten me please

Maitre d'

unread,
Mar 18, 1997, 3:00:00 AM3/18/97
to

> I have always just used CMP when I need to test numbers. I have seen
> TEST also used in many places. Can someone explain what the
> advantages/disadvantages of these instructions are?

CMP is used to check a known value (eg 1, 134, 20, etc)
TEST is used to check a known bit value, also 0, or [undefined but
non-zero]
eg cmp ax, 40 ;see if ax = 40
test al, 40 ;see if bit 6 is set
test ax, ax ;see if ax is 0 or non-zero (faster than CMP, faster than OR)

Randy Hyde

unread,
Mar 19, 1997, 3:00:00 AM3/19/97
to

>>>>
The most important one is testing for zero, e.g. CMP AL,0 or TEST AL,AL.
The latter is better because, as indicated, you can TEST the register
against itself instead of against the immediate value 0, resulting in a
smaller instruction.
<<<<<

Actually, CMP AL, 0 is always better than TEST AL,AL
because
(1) they are both the same length (2 bytes).
(2) CMP is more readable.

I think you meant CMP AX,0 vs. TEST AX,AX.

If so, you've fallen for a trap I warn my students about
all the time- machine idiosyncrasies (i.e., tricks)
don't generalize. So be careful when you use them.

As a general rule, I've stopped telling students about
tricks like xor AX, AX and TEST AX, AX. I much
prefer readable and *CORRECT* code, something they
rarely produce when they resort to tricks. While I
do not question the fact that a good assembly language
programmer should know these tricks (if for no other
reason than to be able to read other's code), I
don't believe one should slip in TEST AX, AX everywhere
a CMP AX, 0 is required. One should carefully
consider if the loss of readability is worth the
one byte you are saving.
Randy Hyde


Vesa Karvonen

unread,
Mar 20, 1997, 3:00:00 AM3/20/97
to

Randy Hyde wrote:
[snip]

> Actually, CMP AL, 0 is always better than TEST AL,AL
> because
> (1) they are both the same length (2 bytes).
> (2) CMP is more readable.

Hmmn... I'm so used to the "trick" that I find TEST reg,reg
more readable. This is probably because it implies which
conditions can be tested. I.e. after seeing an TEST reg,reg
I expect to see E/NE, Z/NZ or S/NS. After CMP reg,constant
there are much more "legal" branches: E/NE, S/NS, LE/G, L/GE,
JB/JAE,... IMHO the use of TEST in many situation makes it
easier to verify the correctness of the branch.

[snip]


> As a general rule, I've stopped telling students about
> tricks like xor AX, AX and TEST AX, AX. I much
> prefer readable and *CORRECT* code, something they
> rarely produce when they resort to tricks.

Why not tell them about SUB reg,reg? For beginner
programmers it might be somewhat more readable than
XOR reg,reg, because most people learn how to
subtract much earlier than how to xor.

--
==> Vesa Karvonen

An optimizing programmer can always beat a C programmer.

Brian Meitiner

unread,
Mar 20, 1997, 3:00:00 AM3/20/97
to

Maitre d' wrote:

> eg cmp ax, 40 ;see if ax = 40
> test al, 40 ;see if bit 6 is set
> test ax, ax ;see if ax is 0 or non-zero (faster than CMP, faster than OR)

The cmp explaination is a bit wrong! cmp ax,40 will tell you if :-
ax = 40
ax < 40
ax > 40
and any combination of the 3

Brian

Scott Nudds

unread,
Mar 20, 1997, 3:00:00 AM3/20/97
to

Brett Wilson wrote:
: I have always just used CMP when I need to test numbers. I have seen

: TEST also used in many places. Can someone explain what the
: advantages/disadvantages of these instructions are?

Test is used to test if a bit is set. It ands the operands together,
sets the zero flag if all bits of the result are zero and then throws
away the result of the "and" operation, keeping the status bits.


--
<---->


Randy Hyde

unread,
Mar 21, 1997, 3:00:00 AM3/21/97
to

>>>>>>
Hmmn... I'm so used to the "trick" that I find TEST reg,reg
more readable. This is probably because it implies which
conditions can be tested. I.e. after seeing an TEST reg,reg
I expect to see E/NE, Z/NZ or S/NS. After CMP reg,constant
there are much more "legal" branches: E/NE, S/NS, LE/G, L/GE,
JB/JAE,... IMHO the use of TEST in many situation makes it
easier to verify the correctness of the branch.
<<<<<<<

Please don't take offense at what I'm about to say, because
you're suffering from a common assembly language programmer
ailment -- you've grown so accustomed to using tricks that
it doesn't occur to you that this is tricky code.
This is fine, as long as you're the only person reading your
code. In the real world, however, most programs wind up
being read by someone other than the original program. And
their bag of "standard tricks" may not exactly coincide with
yours.

It is no wonder "normal" (non-assembly language) programmers
feel that assembly language programs are so hard to read
when a typical assembly language programmer feels that the
obvious way to write something is the "unobvious" way to
do something.

I used to be this way. Gee, I remember hiding instructions
inside the immediate operand field of other instructions, jumping
into the middle of that instruction, and thinking that this was
perfectly readable code (at least I never thought that writing
self-modifying code was a good idea :-).

Then I started teaching assembly
language to (disinterested) students and quickly realized
the error of my ways.

BTW, you leave me unconvinced that

test ax, ax
je ItsZero

is really better or more verifiable than

cmp ax, 0
je ItsZero

TEST sets all the same flags as CMP (if I recall, it clears
carry and overflow and sets the sign flag to the result
of the logical and of the H.O. bits). Sure, it sets the
flags differently than CMP, but I don't see how this makes
the code any more verifiable. The (stated) purpose of
the TEST instruction is to see if one or more bits are
set. A side-effect of its operation is that you can
use it in some special cases to test for zero. Elevating
that special case to the main purpose (over a straight
comparison against zero) doesn't seem entirely reasonable
to me.

Don't get me wrong, I'm not suggesting that there isn't
ever a good reason for using TEST in this manner, it's
just that saving a few bytes when the average machine contains
16 million of them doesn't make a whole lot of sense.
BTW, if saving space is a big concern (and it sometimes
is a concern), then I'd suggest a macro like the following:

JAXZ macro target
test ax, ax
jz target
endm

Granted, now someone has to read the macro to figure out
what this does, but it does hide the trickiness and
replaces with with something more meaningful
(hopefully, they could relate JAXZ with JCXZ and figure
it out, also, hopefully, you use meaningful names).


I used to operate in this mode ("a trick used three times
is standard procedure."). After teaching assembly language
to beginners for about a year I realized the problems.
Write your code readable first. If it needs to be shortened
or sped up (inevitably producing harder to read code), that
can always be done later, when it's more appropriate to do so.

>>>>>>
[snip]
> As a general rule, I've stopped telling students about
> tricks like xor AX, AX and TEST AX, AX. I much
> prefer readable and *CORRECT* code, something they
> rarely produce when they resort to tricks.

Why not tell them about SUB reg,reg? For beginner
programmers it might be somewhat more readable than
XOR reg,reg, because most people learn how to
subtract much earlier than how to xor.
<<<<<<

SUB is definitely more readable than XOR, but MOV AX, 0
is more readable still. Why not leave it at that?

I should rephrase what I said in the previous post.
Of course I teach my assembly language students about
XOR and SUB to zero out registers -- they will need to
be able to read other's code after all. What I don't
do is tell them that's the way to write code. There
is very little efficiency to be gained by writing
XOR AX, AX or SUB AX, AX rather than MOV AX, 0.
Furthermore, I have been bitten by the fact that
XOR clears the flags whereas MOV does not. For most
programs, the trick just isn't worth it so I strongly
encourage my students not to use it.
Chapter Nine of "The Art of Assembly Language Programming"
used to contain a *ton* of these types of tricks. A couple
of years ago I went in and removed a good number of them.
Architectural advances have rendered many of these tricks
ineffective (deoptimizations rather than optimizations).
Future advances may very well eliminate many of the tricks
that are currently in AoA (e.g., multiplying by shifts, adds,
and subtracts).

Several years ago I sat out on a goal to make assembly
language programming easier for the average person. This
started with the LISA assembler I wrote for the Apple II;
I continued these efforts by developing the UCR Standard
Library for 80x86 Assembly Language Programmers. I have
been able to measure the success of the stdlib by the progress
my assembly language students have made over the years.
The biggest problem I face today is that students write
very difficult to read code (this is without them screwing
things up by using all kinds of tricks!). For this reason,
I started switching my emphasis from making assembly language
easy to making assembly language readable. I have posted
a set of assembly language style guidelines on Webster
(see http://webster.ucr.edu/Page_asm/moreasm/MoreASM.html)
for general comment; you should take a look at these to see
where I'm coming from. The HLA (high level assembler) project
I'm mulling over right now may extend this work.

Randy Hyde

An optimizing programmer can always beat a C programmer;
assuming a handy club is laying around :-)


Vesa Karvonen

unread,
Mar 21, 1997, 3:00:00 AM3/21/97
to

Randy Hyde wrote:
>
> >>>>>>
> Hmmn... I'm so used to the "trick" that I find TEST reg,reg
> more readable. This is probably because it implies which
> conditions can be tested. I.e. after seeing an TEST reg,reg
> I expect to see E/NE, Z/NZ or S/NS. After CMP reg,constant
> there are much more "legal" branches: E/NE, S/NS, LE/G, L/GE,
> JB/JAE,... IMHO the use of TEST in many situation makes it
> easier to verify the correctness of the branch.
> <<<<<<<
>
> Please don't take offense at what I'm about to say, because
> you're suffering from a common assembly language programmer
> ailment -- you've grown so accustomed to using tricks that
> it doesn't occur to you that this is tricky code.

I couldn't find anything offensive on your post. You'll have
to do much worse than that to offend me. ;-)

The only reason why I still program in assembly language is
that I can beat a(ny) compiler given that the compiler doesn't
generate optimal code in the particular case (which can be
quickly estimated by analyzing the compiler output). In order
to do this, that is to beat the compiler and analyze the
compiler's output, I have to know every trick in the book
(certainly not any book that has been written ;-).

> This is fine, as long as you're the only person reading your
> code. In the real world, however, most programs wind up
> being read by someone other than the original program. And
> their bag of "standard tricks" may not exactly coincide with
> yours.

This is basically true, however there are ways to get around
the "standard tricks" problem. The easiest way is to comment
the code in a way which leaves no room for such questions.
Unfortunately one rarely writes such comments... and that is
the real problem.

> It is no wonder "normal" (non-assembly language) programmers
> feel that assembly language programs are so hard to read
> when a typical assembly language programmer feels that the
> obvious way to write something is the "unobvious" way to
> do something.

There was a (very short period) time when I felt that C was
difficult to read. After some experience it all started
to seem natural. These "normal" programmers you are talking
about are usually nearly ignorant assembler wise. They have
not yet really learned the "unobvious" obvious ways to do
something and can not really have a word in the matter.

Imagine learning C after learning Basic. The change can
be drastic. Suddenly you have to place a semicolon to
separate staments... Why? It was so natural to write
each stament on a separete line... Consider "int i = 1/2;"
Why is 'i' set to 0? It was so natural when integers
were automatically promoted to reals...

I guess that I trying to say that you can learn things
only once and this makes your view of the world biased.
In many cases the real problem is the attitude towards
the language rather then language itself, which makes
it so hard to read. Certainly assembly language is one
of the most difficult languages to read, but certainly
not as difficult as the "general public" thinks.

> I used to be this way. Gee, I remember hiding instructions
> inside the immediate operand field of other instructions, jumping
> into the middle of that instruction, and thinking that this was
> perfectly readable code (at least I never thought that writing
> self-modifying code was a good idea :-).

It can be a good idea... It's no more than about 3 months since
I last tested self-modifying code. It didn't improve performance
so I dropped it. The penalty of fetching code from the L2 cache
or DRAM really takes it's toll on modern hardware. Anyway, I think
that such code is perfectly readable as long as it is documented
well enough.

If the optimal solution requires the use of self-modifying code,
then I will not dispute it because "it is bad" or "it is difficult
(to read/write)".

The initial programmer usually wants to write the code to be
as efficient as possible, where the maintainer would really
like it to be as readable as possible. These two goals can
probably statistically be shown to be mutually exclusive.
The optimal code tends to be the least readable code (of the
two).

> Then I started teaching assembly
> language to (disinterested) students and quickly realized
> the error of my ways.

BTW do you show your students self-modifying code? It could
really give the shivers to some students, who tought they
were starting to understand assembly language code ;)

> BTW, you leave me unconvinced that
>
> test ax, ax
> je ItsZero
>
> is really better or more verifiable than
>
> cmp ax, 0
> je ItsZero

This isn't really the case I was picturing. The label
you are using is the first thing I read when I looked
at the snippets. It explains everything and can actually
make debugging the code more difficult, because immediately
after reading the label, you think that it is obviously
correct code and never bother to check the code itself.

Try debugging these snippets instead:

call something ; Returns value in eax
test eax,eax
jz do_anything
...
call something ; Returns value in eax
cmp eax,0
ja do_anything
...
call something ; Returns value in eax
cmp eax,0
jz do_anything
...
call something ; Returns value in eax
test eax,eax
ja do_anything
...
call something ; Returns value in eax
cmp eax,0
je do_anything

How long did it take for you to verify the correctness
of the above snippets assuming that the first snippet is
considered correct (among with other correct snippets).
(Well, it shouldn't take too long from an expert anyway...)

> TEST sets all the same flags as CMP (if I recall, it clears
> carry and overflow and sets the sign flag to the result
> of the logical and of the H.O. bits). Sure, it sets the
> flags differently than CMP, but I don't see how this makes
> the code any more verifiable. The (stated) purpose of
> the TEST instruction is to see if one or more bits are
> set. A side-effect of its operation is that you can
> use it in some special cases to test for zero. Elevating
> that special case to the main purpose (over a straight
> comparison against zero) doesn't seem entirely reasonable
> to me.

I propose a new syntax for
TEST REG,REG
as
TEST REG

This is the implied meaning I am referring to. TEST REG
implies that you are "testing" the register just like
using the FTST instruction for testing floating point
numbers, which, I am sure, you find perfectly readable.

Note that most architectures have special means for
"testing" a register (comparing with 0) and an assembly
language programmer that does not know these tricks is
definately a Newbie with a capital N. For example the x86
has TEST, MC68k has TST, the ARM has TST,... and these
are just the machines that have a relatively intuitive
form of "testing" a register.

Also this is exactly analogous to debating whether

if ( expression ) { ... }

is more readable than

if ( expression == 0) { ... }.

It is simply a matter of taste and there never will be
any concencus over which way is more readable. In fact,
there is a thread going on right now debating about proper
numeric definitions of TRUE and FALSE...

However the issue that can be analyzed rather than debated
is that the TEST REG instruction is often (slightly) more
efficient than CMP REG,0 and it is therefore recommended
to know if any serious work is to be done.

> Don't get me wrong, I'm not suggesting that there isn't
> ever a good reason for using TEST in this manner, it's
> just that saving a few bytes when the average machine contains
> 16 million of them doesn't make a whole lot of sense.

But this is exactly why it is important. Assume that a
compiler would generate CMP REG,0 instead of TEST REG for
the same reason. Surely you would think that the compiler
writer is a complete fool. You can never save too many
bytes. Byte here and byte there counts as many bytes. In
fact, typical application programs and operating systems
could be made considerably smaller and faster if it was
considered worth it. I personally find it somewhat offending
that the average (C) programmer (pun intented) doesn't really
know a squat about code optimization, yet thinks that his
compiler generates better code than an assembly language
programmer could.

> BTW, if saving space is a big concern (and it sometimes
> is a concern), then I'd suggest a macro like the following:
>
> JAXZ macro target
> test ax, ax
> jz target
> endm
>
> Granted, now someone has to read the macro to figure out
> what this does, but it does hide the trickiness and
> replaces with with something more meaningful
> (hopefully, they could relate JAXZ with JCXZ and figure
> it out, also, hopefully, you use meaningful names).

This is also a matter of taste. I personally find macros
expanding to 2-4 instructions (note that the range is not
carved into stone, but 2-4 is not just a random number!)
much more difficult to read than straight code, using
standard mnemonics, for the above mentioned reason - in
order to read such code, you must learn the macros, whereas
with straight code, you only need to be fluent in the
standard instruction set.

> I used to operate in this mode ("a trick used three times
> is standard procedure."). After teaching assembly language
> to beginners for about a year I realized the problems.
> Write your code readable first. If it needs to be shortened
> or sped up (inevitably producing harder to read code), that
> can always be done later, when it's more appropriate to do so.

It sounds like avoiding a problem by introducing another
problem. If the readability is really the issue, then
clearly some HLL is a better choice. You know that even
the choice of register allocation and parameter passing
conventions can have a dramatic effect on performance. If
you start by writing the most readable code and intent
to optimize it later, then you will effectively have to
write the code at least twice. You may considerably reduce
the development cycle by starting with HLL code and then
resorting to assembly language only if it is necessary.
This way you can easily test different parameter passing
conventions, algorithms, etc... usually much more quickly
than using assembly language.

BTW do you teach you students how to write inline assembly
code, call assembly language functions from a HLL or how
to call HLL functions from assembly language?

> >>>>>>
> [snip]
> > As a general rule, I've stopped telling students about
> > tricks like xor AX, AX and TEST AX, AX. I much
> > prefer readable and *CORRECT* code, something they
> > rarely produce when they resort to tricks.
>
> Why not tell them about SUB reg,reg? For beginner
> programmers it might be somewhat more readable than
> XOR reg,reg, because most people learn how to
> subtract much earlier than how to xor.
> <<<<<<
>
> SUB is definitely more readable than XOR, but MOV AX, 0
> is more readable still. Why not leave it at that?

Because I am obviously not as concerned about
the readability as you are. Just how difficult
it is for the beginners? Can you give some
statistical data on this?

I think that knowing these "tricks" is essential
for any assembly language programmer. In fact,
I think that most of these "tricks" are really
machine idioms rather than just clever "tricks".
It may certainly be difficult to learn these
idioms initially, but they come very naturally
afterwards.

> I should rephrase what I said in the previous post.
> Of course I teach my assembly language students about
> XOR and SUB to zero out registers -- they will need to
> be able to read other's code after all. What I don't
> do is tell them that's the way to write code.

This problem is not limited to the x86 line of CPU's.
The MC68k has special instructions that relate to this
matter very closely:

moveq #0,data_reg
clr.l data_reg

The former is the "portable" optimal way to clear a
[data] register. The latter is the intuitive way to
clear a register. In addition to the above instructions
one could also use:

eor.l data_reg,data_reg
sub.l reg,reg

I have also used

move.l #0,reg
movea.w #0,address_reg
lea $0,address_reg
lea $0.w,address_reg

(And more...)

I find these all forms (nearly) equally readable and
I have used every single form. If someone would claim
having programmed the MC68k and would have difficulty
reading/writing code using any or all of above forms,
then I would definately have some doubts about his/her
alleged experience with the processor.

> There
> is very little efficiency to be gained by writing
> XOR AX, AX or SUB AX, AX rather than MOV AX, 0.

Consider

mov eax,0
mov al,bl
add eax,ecx

compared to

sub/xor eax,eax
mov al,bl
add eax,ecx

on a PPro.

Perhaps what you really need is to define a
special macro for clearing a register:

; clr - clear a register
;
; Description:
; - clears the specified register.
;
; Condition codes:
; - all undefined.

clr MACRO x
xor x,x
ENDM

Such a macro could then be thought as a standard
instruction mnemonic for clearing a register. It
could even be reimplemented to use any old method
for clearing the register as long as everyone
understands what undefined means.

> Furthermore, I have been bitten by the fact that
> XOR clears the flags whereas MOV does not. For most
> programs, the trick just isn't worth it so I strongly
> encourage my students not to use it.

Why do the students take an assembly language course
anyway? Do they just want to learn assembly language
or do they have special applications in mind? Do they
take it just for the credit?

I learned assembly language because it was (and
still is) a way to write the fastest code around.

> Chapter Nine of "The Art of Assembly Language Programming"
> used to contain a *ton* of these types of tricks. A couple
> of years ago I went in and removed a good number of them.
> Architectural advances have rendered many of these tricks
> ineffective (deoptimizations rather than optimizations).
> Future advances may very well eliminate many of the tricks
> that are currently in AoA (e.g., multiplying by shifts, adds,
> and subtracts).

Perhaps you are taking optimization too seriously - as
some kind of absolute. Surely any optimization expert
knows that an architecture does not fix the execution
times of instructions. In fact, the relative "speed" of
instructions is prone to change from implementation to
another.

I think that it is important to document the most common
optimization tricks. Paired with the proper warnings of
reduced readability and non-guaranteed speed improvement,
everyone could then make the call him/herself. Surely the
alternative, hiding the "forbidden" knowledge, is much
worse for all intents and purposes.

[snip]


> An optimizing programmer can always beat a C programmer;
> assuming a handy club is laying around :-)

heh heh ;-)

--
==> Vesa Karvonen

Never take code optimization advice from an ANSI C programmer.

Jim Neil

unread,
Mar 21, 1997, 3:00:00 AM3/21/97
to

In article <33322A...@raita.oulu.fi>, Vesa Karvonen <vkar...@raita.oulu.fi> says:

>I propose a new syntax for
> TEST REG,REG
>as
> TEST REG
>
>This is the implied meaning I am referring to. TEST REG
>implies that you are "testing" the register just like
>using the FTST instruction for testing floating point
>numbers, which, I am sure, you find perfectly readable.

TERSE already supports this convention with the syntax:

reg ?

which generates a:

TEST REG,REG

[snip]

>Also this is exactly analogous to debating whether
>
> if ( expression ) { ... }
>
>is more readable than
>
> if ( expression == 0) { ... }.
>
>It is simply a matter of taste and there never will be
>any concencus over which way is more readable. In fact,
>there is a thread going on right now debating about proper
>numeric definitions of TRUE and FALSE...

This is NOT the same thing. I believe you ment to say:

if ( expression != 0) { ... }.

And could it be for this EAXCT resaon that people avoid
leaving the relational operator off?

[snip]

Randy Hyde wrote:

>> BTW, if saving space is a big concern (and it sometimes
>> is a concern), then I'd suggest a macro like the following:
>>
>> JAXZ macro target
>> test ax, ax
>> jz target
>> endm
>>
>> Granted, now someone has to read the macro to figure out
>> what this does, but it does hide the trickiness and
>> replaces with with something more meaningful
>> (hopefully, they could relate JAXZ with JCXZ and figure
>> it out, also, hopefully, you use meaningful names).

Well, a problem here is that JCXZ doesn't effect the flags
and your JAXZ macro *does*.

[snip]

>Perhaps what you really need is to define a
>special macro for clearing a register:
>
>; clr - clear a register
>;
>; Description:
>; - clears the specified register.
>;
>; Condition codes:
>; - all undefined.
>
>clr MACRO x
> xor x,x
> ENDM
>
>Such a macro could then be thought as a standard
>instruction mnemonic for clearing a register. It
>could even be reimplemented to use any old method
>for clearing the register as long as everyone
>understands what undefined means.

TERSE also supports this already with the following syntax.

&REG;

Which clears the specufued register by doing a:

SUB REG,REG


Jim Neil ___ ___/ ____/ ___ / ____/ ____/
Creator of The / / / / / /
TERSE Programming Language / ___/ ___/ ____ / ___/
http://www.terse.com / / / \ / /
jim-...@digital.net __/ ______/ __/ __\ ______/ ______/ TM
ISBN: 0-9652660-0-1

Rob Nicholson

unread,
Mar 22, 1997, 3:00:00 AM3/22/97
to

As well as unsigned and signed.

Regards, Rob.


Adrian Gothard

unread,
Mar 23, 1997, 3:00:00 AM3/23/97
to

In message <333099...@raita.oulu.fi>
Vesa Karvonen <vkar...@raita.oulu.fi> writes:

> Randy Hyde wrote:
> [snip]
> > Actually, CMP AL, 0 is always better than TEST AL,AL
> > because
> > (1) they are both the same length (2 bytes).
> > (2) CMP is more readable.

It all depends upon which cpu you're using,
8088/86, 80186/88, 80286/88, 80386, 80486, Pentium etc.

> Hmmn... I'm so used to the "trick" that I find TEST reg,reg
> more readable. This is probably because it implies which

> Why not tell them about SUB reg,reg? For beginner


> programmers it might be somewhat more readable than
> XOR reg,reg, because most people learn how to
> subtract much earlier than how to xor.

Sub eax,eax is faster than Xor on a 486 than on a 386.
Mov xx,0 is appropriate sometimes, depending upon the preceeding instructions.

What we are talking about here is optimisations.

This is black art whatever processor you use (and I'm including
microcontrollers, Motorola etc). Generally I agree that the easier it
is to understand the better, but optimisations have their place for
fast code. Often writing the time critical bit in assembler is an
adequate performance gain.

Adrian.


Adrian Gothard <White Horse Design>

unread,
Mar 23, 1997, 3:00:00 AM3/23/97
to

In message <5gsr24$q...@james.freenet.hamilton.on.ca>
af...@james.freenet.hamilton.on.ca (Scott Nudds) writes:

Think of the CMP instruction as a subtraction operation with all the
flags set as if the subtraction had occurred (which it does not).

The TEST instruction performs a bit-wise AND operation.

So, use CMP to compare data on a value basis and TEST for bit
testing. Of course for some data values you could use either, but it
provides a strong hint that the programmer is manipulating bit
quantities most of the time.

An exception: I often use TEST ax,ax just to set the flags before
returning from a subroutine, where this is NOT a bit test at all, but
it does imply that I am "testing" the value in ax.

Assembler can be just as idiomatic as 'C'!

--
Adrian

---
WWW WWW
WWW WWW Adrian Gothard
WWW WWW White Horse Design.
WWW WW WWW
WWWWWWWWWW agot...@zetnet.co.uk
WWWW WWWW adrian....@rdl.co.uk
WWW WWW


If A equals success, then the formula is A = X + Y + Z, where
X is "work", Y is "play", Z is "Keep your mouth shut" -- Albert Einstein

Randy Hyde

unread,
Mar 24, 1997, 3:00:00 AM3/24/97
to

>>>>
> Randy Hyde wrote:
> [snip]
> > Actually, CMP AL, 0 is always better than TEST AL,AL
> > because
> > (1) they are both the same length (2 bytes).
> > (2) CMP is more readable.

It all depends upon which cpu you're using,
8088/86, 80186/88, 80286/88, 80386, 80486, Pentium etc.
<<<<<

The size is the same on all CPUs.
There is a one cycle difference on the 8088-80286. But
if performance is a problem, you might want to consider
a better processor :-) Okay, I do realize there are
some embedded system out there that still use these
earlier processors. You have my full permission to use
TEST on such systems if you can show me that you really
do need that extra cycle *and* you've tested your code
to ensure it really does run faster (Remember the
Zen mantra: always time your code).

>>>
Sub eax,eax is faster than Xor on a 486 than on a 386.
<<<

Now I haven't actually tried this myself, but every
published manual claims that these instrs run the
same speed on a given processor. If you've run
experiments to the contrary, or found a (correct)
source of information for this, I'd appreciate the
reference. My numbers, btw, come from a combination
of MASM's reference guide, Hummel's text, and Intel
documentation. I am not claiming these are all correct,
(indeed, there are inconsistencies among them) but I
would be surprised to find your claim is true.
Of course, I may not have completely understood what
you said up there. I assume you're saying that
on certain processors sub is faster than xor.

>>>>>
What we are talking about here is optimisations.

This is black art whatever processor you use (and I'm including
microcontrollers, Motorola etc). Generally I agree that the easier it
is to understand the better, but optimisations have their place for
fast code. Often writing the time critical bit in assembler is an
adequate performance gain.

Adrian.
<<<<<<

What we are talking about here is the fact that some people
have grown so accustomed to their tricks, that they apply
them in inappropriate situations. I will never argue that
one should choose readable code over faster (or shorter)
code if the situation demands speed or size. However,
all other things being equal (e.g., sub/xor vs. mov) I feel
that readable code should win out. Readable code should
also win out if space or speed is *not* of paramount
importance for that instruction.
Randy Hyde


Rob Nicholson

unread,
Mar 25, 1997, 3:00:00 AM3/25/97
to

They would case a stall if they happened to use a result that wasn't yet
ready, e.g.

mov ax,bx
cmp ax,100

Regards, Rob.


0 new messages