Hello, i'm having issues checking overflow while adding.
We are making a really basic compiler, my code is:
Array b[2.];
b[1.]:=1.;
b[1.]:=b[1.]+1.2;
And this is what we are generating on masm32
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
.data
nombre db "Compilador",0
EDIV0 db "Error: Division por 0",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 0
cte6 dq 1.2
cte5 dq 1.
cte4 dq 1.
cte3 dq 1.
cte2 dq 1.
cte1 dq 2.
_@7 dq 0
_@6 dq 0000h
_@5 dq 0
_@1 dq 0
_b dq 2 dup (0000h)
.code
start:
FLD _b
FADD _@1
FSTP _@1
FLD cte3
FSTP qword ptr[_@1]
FWAIT
FLD cte3
FLD cte3
FCOMP
fstsw ax
sahf
JBE ET10
JMP ABORT
ET10:
FLD cte1
FLD cte3
FCOMP
fstsw ax
sahf
JBE ET16
JMP ABORT
ET16:
FLD _b
FADD _@5
FSTP _@5
FLD qword ptr [_@5]
FWAIT
FSTP _@5
FLD _@5
FLD cte6
FADD
FSTP _@6
JC OVER
FLD _b
FADD _@7
FSTP _@7
FLD _@6
FSTP qword ptr[_@7]
FWAIT
invoke ExitProcess,0
DIV0:
invoke MessageBox, NULL, addr EDIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start
My questions are:
1. Is correct to use
fstsw ax
sahf
while checking for flags on the coprocessor? or is there another way to do this?
2. Why does this code generate an add overflow while it shouldn't ?
Thanks in advance.
you should define those as REAL8, not QWORD
1.7976931348623158^308 is the max :P
fstsw ax
sahf
is ok, i guess - but, you will get an exception when it overflows (next century), not a math flag
FLD _@5
FLD cte6
FADD ; <<<<<< FPU instruction does not set CPU flags
FSTP _@6
JC OVER
Quote from: dedndave on November 27, 2012, 04:27:30 AM
you should define those as REAL8, not QWORD
that syntax is strange, but OK as long as using a dot in the declaration.
Quote from: Joao Batista on November 27, 2012, 03:17:26 AM
My questions are:
fstsw ax
sahf
is there another way to do this?
this method is obsolete - use FCOMI[P]/FUCOMI[P] instead.
mm ok.. so..
FLD _@5
FLD cte6
FADD
FSTP _@6
JC OVER
here the FADD doesn't set the cpu flags.. how do i do that then?
and.. how do i use FCOM? FCOMI.. etc?
i tried something like
FLD _@5
FLD cte6
FCOM
JC OVER
FADD
FSTP _@6
but this doesnt work..
yeah.. im kinda lost here hehe
f[i]ld a
f[i]ld b
fcomip
fstp st
ja @A_GE_B
jb @A_LT_B
jz @A_EQ_B
jae ...
jp @error
AMD64 Architecture Programmer's Manual Volume 5: 64-Bit Media and x87 Floating-Point Instructions (http://support.amd.com/us/Processor_TechDocs/26569_APM_v5.pdf)
Ray's FPU tutorial is probably a little easier to understand...
http://www.ray.masmcode.com/fpu.html (http://www.ray.masmcode.com/fpu.html)
ok ill start reading, ty, but just one problem.
I keep geting "Instruction or register not accepted in current CPU mode" error
how do i set the cpu mode to work with that?
Hi Joao,
Quote from: Joao Batista on November 27, 2012, 05:28:20 AM
ok ill start reading, ty, but just one problem.
I keep geting "Instruction or register not accepted in current CPU mode" error
how do i set the cpu mode to work with that?
did you try .387 after .386?
Gunther
The fcomip needs probably .586 or .686 - just try...
i think .686 is required :t
Ok thank you all for the help.. i have to wait until tomorrow to try all this so.. see you tomorrow!
Thanks again!
One possibility is to store the status word and test the exception status bits.
;==============================================================================
include \masm32\include\masm32rt.inc
;.686
;==============================================================================
;--------------------------------------------------
; Equates for the FPU status word exception flags.
;--------------------------------------------------
FEX_INVALID equ 1
FEX_DENORMALIZED equ 2
FEX_ZERODIVIDE equ 4
FEX_OVERFLOW equ 8
FEX_UNDERFLOW equ 16
FEX_PRECISION equ 32
FEX_STACKFAULT equ 64
FEX_ANY equ 127
;==============================================================================
.data
r10max REAL10 1.18E4932 ; approximate
r8 REAL8 0.0
fpu_status dd 0
.code
;==============================================================================
start:
;==============================================================================
fstsw WORD PTR fpu_status
test fpu_status, FEX_OVERFLOW
jz @F
printf("OF 0\n")
@@:
fld r10max
fld r10max
fadd
fstsw WORD PTR fpu_status
test fpu_status, FEX_OVERFLOW
jz @F
printf("OF 1\n")
@@:
fstp st
fclex
fld r10max
fstp r8
fstsw WORD PTR fpu_status
test fpu_status, FEX_OVERFLOW
jz @F
printf("OF 2\n")
@@:
fclex
fld1
fstp r8
fstsw WORD PTR fpu_status
test fpu_status, FEX_OVERFLOW
jz @F
printf("OF 3\n")
@@:
fclex
inkey
exit
;==============================================================================
using real8's, and starting at 1.0...
adding 1.2 with each pass...
i don't think you will live long enough to see it overflow :biggrin:
refer to reply #1 - lol
http://masm32.com/board/index.php?topic=959.msg8657#msg8657 (http://masm32.com/board/index.php?topic=959.msg8657#msg8657)
Hi, yeah the thing with the dq is that i must use them.. i know it sounds silly, but you will have to tell that to my professor -.-
So is a restriction i have to live with.
ok - but read the rest of that post :P
Hi, i still can't make this work :S
can you just give me a super simple example.. using dq, of how to check for add overflow on the fpu and jump to another tag?
i tried everything u told me to :S
i must be doing somehing wrong :S
tried this
FLD cte1
FLD cte2
FADD
fstsw WORD PTR fpu_status
test fpu_status, FEX_OVERFLOW
jz OVER
tried this
FLD cte0
FLD cte6
FCOMI ST,ST(0)
fwait
Jc OVER
and so on.. :S
in your program, you may want to do an FINIT and set the precision
under windows, when a program is loaded, i think it is initialized and set to double precision (8 byte)
FINIT sets it to extended real (10 byte)
that is just something to note - may not be your problem
once you have that set up.....
fld cte1
fld cte2
fadd
fstsw ax
test al,FEX_OVERFLOW
jnz OverFlow_Occured
use something like 1.78E308 for both cte1 and cte2 - that should cause an overflow
Quote from: dedndave on November 28, 2012, 11:25:49 AM
in your program, you may want to do an FINIT and set the precision
under windows, when a program is loaded, i think it is initialized and set to double precision (8 byte)
FINIT sets it to extended real (10 byte)
that is just something to note - may not be your problem
once you have that set up.....
fld cte1
fld cte2
fadd
fstsw ax
test al,FEX_OVERFLOW
jnz OverFlow_Occured
use 1.78E308 for both cte1 and cte2 - that should cause an overflow
just tried this and doesnt work :S
And just when you just told me that, i was trying to do what ray's tutorial says..
cte0 dq 1.39769e+308
cte6 dq 1.79769e+308
.code
start:
FLD cte0
FLD cte6
FADD
fstsw ax
fwait
sahf
JC OVER
this seems perfect.. but doesn't work :S
fld loads cte0 and 6 in st
then i add them
fstsw ax is supposed to store the flags on ax register
fwait .. wait while fpu is busy
sahf is supposed to "pass" fpu flags to cpu..
JC OVER is supposed to jump if the carry flag is up
:( what's wrong??
hmmmmm
the FPU is using REAL10 format, internally - which it always does except for integer and bcd values
perhaps you won't get an overflow until you try to store it into a REAL8 - lol
another way to try it would be to go ahead and do an FINIT
that sets it to REAL10 precision
then test to see if you can cause an overflow using REAL10's
the max value is about 1.19E4932
so, you can add 1.0E4932 to itself to get an overflow
as you can see, most of us have never tried to overflow the FPU :lol:
we generally have our hands full testing for equality or "near-equality"
Yeah is not that we are trying to make it overflow.. i have to test if our code works XD
like this!!
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
FEX_OVERFLOW equ 8
.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 1.78E308
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADD
fstsw ax
fwait
sahf
JC OVER
JMP EDIV0
invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start
This doesn't work! and we don't know why!! :P
Thing is, my profesor will test our code with a 1.78E308 + 1.78E308 value and our program should show a message saying hey.. fpu overflowed .. :(
As dave said, the OF exception occurs when you store the value. A simple approach would be to test the result for NaN after it has been stored in memory (requires that the input values are valid):
mov eax,DWORD ptr r8Var[4]
and eax,7FF00000h
xor eax,7FF00000h
jz @error
EDIT: code changed
O.o i didn't understand a single word of that code lol
where do i add it on my code? hahaha
Quote from: qWord on November 28, 2012, 11:45:52 AM
As dave said, the OF exception occurs when you store the value. A simple approach would be to test the result for NaN after it has been stored in memory (requires that the input values are valid):
and DWORD ptr r8Var[4],7FF00000h
xor DWORD ptr r8Var[4],7FF00000h
jz @error
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
FEX_OVERFLOW equ 8
.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 0
result dq ?
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADDp
fstp result
mov eax,DWORD ptr result[4]
and eax,7FF00000h
xor eax,7FF00000h
jz OVER
JMP EDIV0
invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start
As said, this method makes only sense if the input values are validated (and not NaN themself)
BTW, what you can also do is to unmask the wished exceptions and then enclose you calculation by corresponding exception handler (SEH).
Quote from: qWord on November 28, 2012, 11:54:26 AM
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
FEX_OVERFLOW equ 8
.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 0
result dq ?
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADDp
fstp result
mov eax,DWORD ptr result[4]
and eax,7FF00000h
xor eax,7FF00000h
jz OVER
JMP EDIV0
invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start
As said, this method makes only sense if the input values are validated (and not NaN themself)
so basically.. u have to store the value to make the overflow? O.o
btw.. that worked with a FADD instead of a FADDP .. :D
So. thank you very very much!!!
Quote from: Joao Batista on November 28, 2012, 12:01:40 PM
btw.. that worked with a FADD instead of a FADDP .. :D
Yes it does but it leaves a value in the FPU. Do that 8 times, e.g. in a loop, and the FPU chokes. And you have a bug that can be chased only with Olly...
Quote from: jj2007 on November 28, 2012, 05:20:41 PM
Quote from: Joao Batista on November 28, 2012, 12:01:40 PM
btw.. that worked with a FADD instead of a FADDP .. :D
Yes it does but it leaves a value in the FPU. Do that 8 times, e.g. in a loop, and the FPU chokes. And you have a bug that can be chased only with Olly...
Hi,
Yes, but using FADD with no operands is a special case.
It defaults to adding ST and ST(1) and then popping. ST
is ST(0) as well. It's a MASM (and other assemblers) thing.
0005 9B DC C1 FADD ST(1),ST
0008 9B DE C1 FADDP ST(1),ST
000B 9B DE C1 FADD
Regards,
Steve N.
Quote from: FORTRANS on November 30, 2012, 04:05:59 AM
using FADD with no operands .. defaults to adding ST and ST(1) and then popping.
Interesting, thanks Steve :t