I have the following code
I'm trying to set all the bits in eax to 0 except the first 3. Sort of error checking, all values have to result in a valid jump into the table.
your help is most appriciated.
tbl dd yes,no,maybe,Error ; these are addresses of labels
mov ebx,tbl
xor eax,eax
mov eax,4
AND EAX,3
baba:
shl eax,2
jmp
I'm trying to set all the bits in eax to 0 except the first 3. Sort of error checking, all values have to result in a valid jump into the table.
your help is most appriciated.
Try this
Biterider
and eax, 3 ;lowest 2 bits set => 2^2 = 4 (yes,no,maybe,Error)
jmp
Biterider
Posted on 2013-04-23 18:59:49 by mich
I doubt if "and" is what you want... but maybe I don't understand what you want.
So the question is whatever number is in eax needs to be reduce to be a value from 1-4. All values > 4 need a jump to error and also all values < 0.
Do you want a value between 1 and 4 or between 0 and 3? Is <0 supposed to be an error, or <=0? Is 5 supposed to be an error, or cycle back to no?
ASSuming that you want 0 - yes, 1 - no, 2 - maybe, 3 or more - error, less than 0 - error... you probably want "ja", not "jg".
I'm not in love with that, but it may do what you want... or what I think you should want... :)
Best,
Frank
So the question is whatever number is in eax needs to be reduce to be a value from 1-4. All values > 4 need a jump to error and also all values < 0.
Do you want a value between 1 and 4 or between 0 and 3? Is <0 supposed to be an error, or <=0? Is 5 supposed to be an error, or cycle back to no?
ASSuming that you want 0 - yes, 1 - no, 2 - maybe, 3 or more - error, less than 0 - error... you probably want "ja", not "jg".
mov ebx, 3
cmp eax, ebx
cmova eax, ebx
jmp
I'm not in love with that, but it may do what you want... or what I think you should want... :)
Best,
Frank
Hi Frank, thanks for your reply.
Yes you are right. In this particular example, there are 4 valid jump addresses in the table. To avoid disasters, each evaluation has to resolve in one of them. So 0 for yes, 1 for no, 2 for all others and anything else HAS to evaluate to 3 ERROR.
mov ebx, 3
cmp eax, ebx
cmova eax, ebx
jmp
In the context of an FSA this is not quite the solution I have been looking for. The program listed above does not use a single logic comparison, so the cmp eax, ebx is a bit of a damper on my ego but hey it works and works very well. Technically the evaluation is not needed as long as the caller assures the correct jump.
By the way, the program above is modeled after my life, no comp's if's and butts, all jumps!
Regards,
Klod
Yes you are right. In this particular example, there are 4 valid jump addresses in the table. To avoid disasters, each evaluation has to resolve in one of them. So 0 for yes, 1 for no, 2 for all others and anything else HAS to evaluate to 3 ERROR.
mov ebx, 3
cmp eax, ebx
cmova eax, ebx
jmp
In the context of an FSA this is not quite the solution I have been looking for. The program listed above does not use a single logic comparison, so the cmp eax, ebx is a bit of a damper on my ego but hey it works and works very well. Technically the evaluation is not needed as long as the caller assures the correct jump.
By the way, the program above is modeled after my life, no comp's if's and butts, all jumps!
Regards,
Klod
Hi
In the System.inc file of the OA32 proj. there is a macro called JumpOn what does what you want and automated the task
Only if you are in range it will jump, otherwise it continues with the regular execution.
Regards, Biterider
In the System.inc file of the OA32 proj. there is a macro called JumpOn what does what you want and automated the task
; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧
; Macro: JumpOn
; Purpose: Create a jump table and executes a jump to a label according the content of a
; register.
; Arguments: Arg1: Case register.
; Arg2: Jump labels.
; Returns: Nothing.
; Example: JumpOn eax, @@10, @@20, @@30
JumpOn macro RegName:req, Labels:vararg
local JumpTable
.const
??Count = 0
for ??Arg, <Labels>
ife ??Count
JumpTable dd offset ??Arg
else
dd offset ??Arg
endif
??Count = ??Count + 1
endm
.code
cmp RegName, ??Count
jae @F
jmp
@@:
endm
Only if you are in range it will jump, otherwise it continues with the regular execution.
Regards, Biterider
In the context of an FSA this is not quite the solution I have been looking for. The program listed above does not use a single logic comparison, so the cmp eax, ebx is a bit of a damper on my ego but hey it works and works very well.
What do you mean by that exactly?
A compare is basically just a subtraction where the result is discarded. On modern CPUs it is a single-cycle operation just like and, for example, and no stalls.
It is only the conditional jumps that may come after a compare (or any other instruction that updates the condition flags) that may cause a stall and hamper performance. A cmovcc does not (the problem with conditional jumps is that they may or may not modify the instruction pointer, which may invalidate the pipeline).
Hi Biterider
Thanks for your reply. I haven't even thought that far yet. I had an idea and I had a go at it just to see what it looks like in source code and disassembled. What I got is enough to add another round of experiments to find out if this a worthwhile subject.
Hi Scali,
Thanks for your insight. The damper on my ego was meant as a diminutive comment about my own abilities to find a solution. ;)I had interpreted FSA as a piece of code that does avoid compare's all together and uses calculations and tables to implement the desired logic.
I had replied a little bit to hastily. I had missed to note in the debugger that in fact there was no conditional jump.
Thanks for all your contributions
Klod
Thanks for your reply. I haven't even thought that far yet. I had an idea and I had a go at it just to see what it looks like in source code and disassembled. What I got is enough to add another round of experiments to find out if this a worthwhile subject.
Hi Scali,
Thanks for your insight. The damper on my ego was meant as a diminutive comment about my own abilities to find a solution. ;)I had interpreted FSA as a piece of code that does avoid compare's all together and uses calculations and tables to implement the desired logic.
It is only the conditional jumps that may come after a compare (or any other instruction that updates the condition flags) that may cause a stall and hamper performance. A cmovcc does not (the problem with conditional jumps is that they may or may not modify the instruction pointer, which may invalidate the pipeline).
I had replied a little bit to hastily. I had missed to note in the debugger that in fact there was no conditional jump.
Thanks for all your contributions
Klod
Well if you don't want any 'cmp', here's a variation:
How it works is like this:
sub eax, 3 will result in a value < 0 only if eax < 3. In other words, we set carry if eax < 3.
sbb edx, edx will transfer -carry to edx. So if carry then edx = -1 else edx = 0.
Then we and eax with edx, so that if eax was < 3, its value is preserved (and with -1 does not do anything), else eax = 0 (and with 0 will reset all bits).
Now we add 3 back to eax. The result is: if eax was < 3, then its original value is restored (counter-act the sub 3 we did earlier), else eax was 0, so now we get 3, which is our 'Error' value.
The life of real programmers before Pentium Pro :)
sub eax, 3
sbb edx, edx
and eax, edx
add eax, 3
jmp
How it works is like this:
sub eax, 3 will result in a value < 0 only if eax < 3. In other words, we set carry if eax < 3.
sbb edx, edx will transfer -carry to edx. So if carry then edx = -1 else edx = 0.
Then we and eax with edx, so that if eax was < 3, its value is preserved (and with -1 does not do anything), else eax = 0 (and with 0 will reset all bits).
Now we add 3 back to eax. The result is: if eax was < 3, then its original value is restored (counter-act the sub 3 we did earlier), else eax was 0, so now we get 3, which is our 'Error' value.
The life of real programmers before Pentium Pro :)
In fact, the add isn't really necessary, since you can just add an offset to the table as well:
So you ask yourself, why do you really need cmovcc anyway? This solution goes in 4 instructions, just like the cmov one.
sub eax, 3
sbb edx, edx
and eax, edx
jmp
So you ask yourself, why do you really need cmovcc anyway? This solution goes in 4 instructions, just like the cmov one.
Nice! I figured cmovcc would be better than the conditional jump (which may not be true), but only because I couldn't think of a "sbb trick" that would do it. I like this. Of course the jump table is not well predicted anyway, so it may be "racing stripes on a Yugo". :)
Best,
Frank
Best,
Frank
Oh well, it's just this thing I have... The Pentium was the last great CPU as far as assembly programming goes.
The Pentium Pro took a lot of the 'magic' away from assembly programming. Partly because it did the instruction scheduling for you, and the old rule of "fecal matter in == fecal matter out" no longer applied as much (you no longer really had to count cycles and try to make use of the U and V pipelines manually, by carefully crafting your routines). Partly because from then on, clockspeeds reached insane heights (and later the number of cores/threads), and the execution speed of code just wasn't an issue anymore. And partly because the Pentium Pro's new execution engine meant that a lot of clever optimizing tricks no longer worked very well, while a lot of 'dumb' code that even a compiler could come up with, would be quite optimal.
The cmovcc instruction symbolizes this to a certain extent. In many cases, you can come up with some nice solutions that work equally well, using just regular 386-instructions, of which I have given one example. But the challenge has always been to find such solutions. That was part of the charm of programming assembly.
So to me it's the end of an era. If you also check out some of the stuff I've written elsewhere on C64/6502 programming... You'll see all these clever tricks that people have come up with over the years. The true art of assembly. But on modern x86 CPUs, most of these tricks don't apply.
The Pentium Pro took a lot of the 'magic' away from assembly programming. Partly because it did the instruction scheduling for you, and the old rule of "fecal matter in == fecal matter out" no longer applied as much (you no longer really had to count cycles and try to make use of the U and V pipelines manually, by carefully crafting your routines). Partly because from then on, clockspeeds reached insane heights (and later the number of cores/threads), and the execution speed of code just wasn't an issue anymore. And partly because the Pentium Pro's new execution engine meant that a lot of clever optimizing tricks no longer worked very well, while a lot of 'dumb' code that even a compiler could come up with, would be quite optimal.
The cmovcc instruction symbolizes this to a certain extent. In many cases, you can come up with some nice solutions that work equally well, using just regular 386-instructions, of which I have given one example. But the challenge has always been to find such solutions. That was part of the charm of programming assembly.
So to me it's the end of an era. If you also check out some of the stuff I've written elsewhere on C64/6502 programming... You'll see all these clever tricks that people have come up with over the years. The true art of assembly. But on modern x86 CPUs, most of these tricks don't apply.
Hi Scali
Thank you very much for sharing this piece of code. Needless to say it went right away in my collection of ASMGEMS.
It's this that separates the artist from the professional.
elegance!
Regards,
Klod
Thank you very much for sharing this piece of code. Needless to say it went right away in my collection of ASMGEMS.
But the challenge has always been to find such solutions. That was part of the charm of programming assembly.
It's this that separates the artist from the professional.
elegance!
Regards,
Klod