flat assembler
Message board for the users of flat assembler.

Index > Main > Converting arithmetic expressions to Assembly

Goto page Previous  1, 2
Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16901
Location: In your JS exploiting you and your system
revolution
Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware.

BTW: xor changes the sign, it is not equivalent to FABS.
Post 11 Nov 2018, 10:45
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 1435
Furs
revolution wrote:
Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware.

BTW: xor changes the sign, it is not equivalent to FABS.
Oh, I thought you wanted to flip the sign in case the power was odd/even. My bad.

Then of course you have to use and instead, with 0x7F, but yeah.
Post 11 Nov 2018, 11:06
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
Furs wrote:
I mean MSB = most significant byte. In your case it should be "most significant DWORD".


When people refer to MSB, people talk about byte position, NOT a byte quantity. In any operand size larger than a byte, there always exists 2 important properties of that operand: its LSB and MSB. MSB always assumes the highest byte position of any given operand. This is pretty basic.
I don't think you understand how floating format is laid out in memory or in a GPR. I also doubt your understanding on how addressing modes work. Here's the real layout of how floating point is parsed in memory;
Code:
x dq -45.345

mov al,byte[x+7]   ;this approaches the MSB if you want to extract the highest byte
and al,0x7f           ;flip it
mov byte[x+7],al  ;copy it back to MSB

or,

btr dword[x+4],31 ;flips the bit 31 of the upper half of the REAL8.    


While XOR and AND also work, sometimes it is better being more explicit of what you instruction trying to do. For example in this case, BTR stands for Bit Test and Reset. It's much more clearer and descriptive.

If you have access to my BASELIB routines, you get to see what you're talking about on-the-fly. You don't need "geometry" of some sort to see how a REAL8 data are parsed into memory.

Code:
;This is "sbase32w.asm"
        format PE console
        include 'win32axp.inc'
        entry main

        section '.data' data readable writeable
x       dq -45.345

        section '.text' code readable executable
main:
        push    x
        call    fpdinfo
        call    prnline

        btr     dword[x+4],31  ;reset bit 31 of the upper portion of x

        push    x
        call    fpdinfo
        call    prnline

        push    x
        call    prndbl
        call    prnline

        push    x
        push    64
        call    memview

        call    halt
        call    exitx     


With this output
Code:
C046AC28F5C28F5C
1.10000000100.01101010110000101000-11110101110000101000111101011100
Sign: 1
Exp : +5
Mant: 1.41703125

4046AC28F5C28F5C
0.10000000100.01101010110000101000-11110101110000101000111101011100
Sign: 0
Exp : +5
Mant: 1.41703125

45.345
00401000| 5C 8F C2 F5 28 AC 46 40 |+7|+7
00401008| 00 00 00 00 00 00 00 00 |+F|+15
00401010| 00 00 00 00 00 00 00 00 |+17|+23
00401018| 00 00 00 00 00 00 00 00 |+1F|+31
00401020| 00 00 00 00 00 00 00 00 |+27|+39
00401028| 00 00 00 00 00 00 00 00 |+2F|+47
00401030| 00 00 00 00 00 00 00 00 |+37|+55
00401038| 00 00 00 00 00 00 00 00 |+3F|+63    


See how the value changes in memory via memview output using the correct addressing mode.
Post 11 Nov 2018, 11:33
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
revolution wrote:
Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware.

BTW: xor changes the sign, it is not equivalent to FABS.


FCHS involves branching. While it sounds convenient it's probably not the best option here.
Post 11 Nov 2018, 11:44
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
Furs wrote:
revolution wrote:
Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware.

BTW: xor changes the sign, it is not equivalent to FABS.
Oh, I thought you wanted to flip the sign in case the power was odd/even. My bad.

Then of course you have to use and instead, with 0x7F, but yeah.


Don't let yourself down Smile
XOR does work if you pit it against the entire DWORD. It just doesnt work against the MSB that way.

Here's another example, showcasing the AND and XOR to flip the sign bit of a REAL8. Still using "sbase32w.asm" source;
Code:
x dq -0.02345

;and     dword[x+4],0x7fffffff
xor     dword[x+4],0x80000000
push    x
call    prndbl     ;Sign bit is reset, using either one of the above    
Post 11 Nov 2018, 12:09
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16901
Location: In your JS exploiting you and your system
revolution
fasmnewbie wrote:
FCHS involves branching. While it sounds convenient it's probably not the best option here.
The behaviour will be implementation dependant. The instruction byte length is probably shorter than using the CPU instructions, so if performance is a concern then it could be more cache friendly, that would depend upon the application it is used in.
Post 11 Nov 2018, 12:18
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 1435
Furs
fasmnewbie wrote:
When people refer to MSB, people talk about byte position, NOT a byte quantity. In any operand size larger than a byte, there always exists 2 important properties of that operand: its LSB and MSB. MSB always assumes the highest byte position of any given operand. This is pretty basic.
I don't think you understand how floating format is laid out in memory or in a GPR. I also doubt your understanding on how addressing modes work. Here's the real layout of how floating point is parsed in memory;
Code:
x dq -45.345

mov al,byte[x+7]   ;this approaches the MSB if you want to extract the highest byte
and al,0x7f           ;flip it
mov byte[x+7],al  ;copy it back to MSB

or,

btr dword[x+4],31 ;flips the bit 31 of the upper half of the REAL8.    
But why +4 and not +7? The position of the MSB byte is x+7. Literally. Doesn't matter the access mode.

You are truncating it to a 4-byte alignment (dword), but in fact:
Code:
btr dword[x+7],31    
is a perfectly valid instruction and works (and it's what MSB means btw).

There's no reason to truncate a byte's position based on what you are accessing with, because x86 doesn't require aligned memory access (except for rare cases).

So saying "MSB" in this context is very confusing, IMO. Should be "most significant DWORD" as I said. Wink


EDIT: BTW I am aware that it SHOULD be x+4, I'm not disagreeing with you. Just saying that you used the "your base's MSB" as the address which is confusing cause it means [x+7] in this case, which is wrong. i.e. just a matter of what you said, not what you meant Razz


Last edited by Furs on 11 Nov 2018, 18:42; edited 2 times in total
Post 11 Nov 2018, 15:40
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16901
Location: In your JS exploiting you and your system
revolution
Furs wrote:
But why +4 and not +7? The position of the MSB byte is x+7. Literally. Doesn't matter the access mode.
"btr dword[x+7],31" will alter bit 7 of the byte at x+10.
Post 11 Nov 2018, 15:44
View user's profile Send private message Visit poster's website Reply with quote
UniverseIsASimulation



Joined: 23 Sep 2016
Posts: 26
UniverseIsASimulation
It seems like there are more than one bug in the web-app. If I enter the arithmetic expression:
Code:
pow(abs(x),y)*((x<0&mod(y,2)=1)*(-1)+(x>0|mod(y,2)=0)*1+((x<0&not(mod(y,1)=0)&(0/0))))    

Transpiled into JavaScript and then executed (which is what the "Interpret" button does), it behaves like the "pow" function for all inputs. However, the compiler output is this:
Code:
finit 
fld dword [y] 
mov [result],2f 
fld dword [result] 
fxch 
fprem 
fxch 
fstp dword [result] 
mov [result],1f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jne l640924 
fld1 
jmp l564953 
l640924: 
fldz 
l564953: 
fld dword [x] 
mov [result],0f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jna l337650 
fld1 
jmp l814480 
l337650: 
fldz 
l814480: 
fxch 
fistp dword [result] 
mov eax,[result] 
fistp dword [result] 
and [result],eax 
fild dword [result] 
mov [result],0f 
fld dword [result] 
mov [result],1f 
fld dword [result] 
fsubp st1,st0 
fmulp st1,st0 
fld dword [y] 
mov [result],2f 
fld dword [result] 
fxch 
fprem 
fxch 
fstp dword [result] 
mov [result],0f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jne l730422 
fld1 
jmp l471695 
l730422: 
fldz 
l471695: 
fld dword [x] 
mov [result],0f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jnb l46226 
fld1 
jmp l580080 
l46226: 
fldz 
l580080: 
fxch 
fistp dword [result] 
mov eax,[result] 
fistp dword [result] 
or [result],eax 
fild dword [result] 
mov [result],1f 
fld dword [result] 
fmulp st1,st0 
faddp st1,st0 
fld dword [y] 
mov [result],1f 
fld dword [result] 
fxch 
fprem 
fxch 
fstp dword [result] 
mov [result],0f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jne l920163 
fld1 
jmp l751054 
l920163: 
fldz 
l751054: 
fld1 
fxch 
fsubp st1,st0 
fld dword [x] 
mov [result],0f 
fld dword [result] 
fcomip st1 
fstp dword [result] 
jna l399314 
fld1 
jmp l871526 
l399314: 
fldz 
l871526: 
fxch 
fistp dword [result] 
mov eax,[result] 
fistp dword [result] 
and [result],eax 
fild dword [result] 
mov [result],0f 
fld dword [result] 
mov [result],0f 
fld dword [result] 
fdivp st1,st0 
fistp dword [result] 
mov eax,[result] 
fistp dword [result] 
and [result],eax 
fild dword [result] 
faddp st1,st0 
fld dword [x] 
fabs 
fld dword [y] 
fxch 
fld1 
fxch 
fyl2x 
fldl2e 
fdivp st1,st0 
fmulp st1,st0 
fldl2e 
fmulp st1,st0 
fld1 
fscale 
fxch 
fld1 
fxch 
fprem 
f2xm1 
faddp st1,st0 
fmulp st1,st0 
fxch 
fmulp st1,st0 
fstp dword [result]
    

That, if compiled with FASM and run, doesn't give the correct results. Any idea what's going on?
Post 11 Nov 2018, 16:12
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 1435
Furs
revolution wrote:
Furs wrote:
But why +4 and not +7? The position of the MSB byte is x+7. Literally. Doesn't matter the access mode.
"btr dword[x+7],31" will alter bit 7 of the byte at x+10.
I know, that's exactly what I mean.

He said [your base's MSB] to use in place of dword [x+4] which is confusing since x+4 is not the MSB.
Post 11 Nov 2018, 18:27
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16901
Location: In your JS exploiting you and your system
revolution
So x+4 is the MSD?

Anyhow, just use FCHS or FABS, they'll get the job done without this kind of confusion.
Post 11 Nov 2018, 18:31
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
Quote:
EDIT: BTW I am aware that it SHOULD be x+4, I'm not disagreeing with you. Just saying that you used the "your base's MSB" as the address which is confusing cause it means [x+7] in this case, which is wrong. i.e. just a matter of what you said, not what you meant Razz


Yeah, I can see where your confusion came from. It's about trying to match the idea of a "byte quantity" to a "dword" memory operand. I understand that problem. I was once there when I was completely as clueless to separate the idea of addressing modes from operand sizes. Thank god for the AMD manuals! Very Happy
Post 12 Nov 2018, 11:19
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
universe

your code is too long for us to even begin with. Give a smaller test case so we can at least enjoy it in smaller pieces. Perhaps start with label names?
Post 12 Nov 2018, 11:28
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
Universe, here, I embedded the output above into the "sbase32w.asm" source file. You can run the program as it is and get to use the FPU-specific routines in there. For example, I inserted multiple calls to "fpu_stack" at certain jump points to confirm the transitions from 1 "label" to another. In the end I call "prnflt" routine to print the final result. I didn't make any modifications to the above output.

You can also insert calls to "fpu_stack" at suspected faulty lines to see the content of the FPU any time.

For x = 5.4, y=3.4 the final answer is 309.1284.

Is this expected?

P/s Attachment will be deleted soon, because my quota doesn't look good, I think.


Last edited by fasmnewbie on 13 Nov 2018, 14:27; edited 1 time in total
Post 12 Nov 2018, 11:49
View user's profile Send private message Visit poster's website Reply with quote
UniverseIsASimulation



Joined: 23 Sep 2016
Posts: 26
UniverseIsASimulation
Yes, but for x=-2 and y=1.5, it returns 0. I expected it to return NaN.
Post 12 Nov 2018, 16:07
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
fasmnewbie
Universe, it shouldn't return NaN because you already set it to FABS. Returning 0.0 is expected. It is now come down to your own set of rules against user input, at least for POW function taking negative base. I don't see anything wrong there.

For my own fpow function, I immediately set it to #err for negative base because I knew something confusing like this could happen.
Post 12 Nov 2018, 18:12
View user's profile Send private message Visit poster's website Reply with quote
UniverseIsASimulation



Joined: 23 Sep 2016
Posts: 26
UniverseIsASimulation
Anyway, I've improved my compiler using the Duktape framework to be able not only to translate single directives from my own programming language into Assembly, but to also be able to translate entire simple programs stored in files. Here is one of the first programs I've written in the first programming language I've made myself:
Code:
;Advanced example: implementing the permutation algorithm.
AsmStart
    debug=0
        macro pushIntToStack x
        {
                sub esp,4
                fld dword [x]
                fistp dword [esp]
        }
        macro pushPointerToStack x
        {
                sub esp,4
                lea ebx,[x]
                mov [esp],ebx
        }
        macro pushStringToStack x
        {
                sub esp,4
                mov dword [esp],x
        }
        format PE console
        entry start

        include 'win32a.inc'

        section '.text' code executable
        start:
        jmp enterNumber$
                enterNumber db "Enter a whole number (1 - 1'000'000).",10,0
        enterNumber$:
        pushStringToStack enterNumber
        call [printf]
        pushPointerToStack original
        jmp floatSign$
                floatSign db "%f",0
        floatSign$:
        pushStringToStack floatSign
        call [scanf]
        jmp permutationString$
                permutationString db "The permutations of its digits are:",10,0
        permutationString$:
        pushStringToStack permutationString
        call [printf]
AsmEnd
numberOfDigits:=0
i:=0
While i<10
        countDigits[i]:=0
        i:=i+1
EndWhile
While original>0
        numberOfDigits:= numberOfDigits + 1
        lastDigit:= mod( original , 10 )
        countDigits[ lastDigit ]:=countDigits( lastDigit ) + 1
        original:= (original - lastDigit) / 10
EndWhile
AsmStart
        if debug=1
AsmEnd
                i:=0
                While i<10
                        subscript:=4*i
                        AsmStart
                                fld dword [subscript]
                                fistp dword [subscript]
                                mov ebx,[subscript]
                                pushIntToStack (countDigits+ebx)
                                pushStringToStack integerSign
                                call [printf]
                        AsmEnd
                        i:=i+1
                EndWhile
                AsmStart
                        pushStringToStack newLineString
                        call [printf]
                AsmEnd
AsmStart
end if
AsmEnd
topOfMyStack:=1
myStack[(numberOfDigits+1)]:=0
While topOfMyStack>0
        currentNumberOfDigits:=myStack ( topOfMyStack * ( numberOfDigits + 1 ) )
        i:=0
        While i<currentNumberOfDigits
                currentNumber(i):=myStack ( topOfMyStack * ( numberOfDigits + 1 ) + ( i + 1 ) )
                i:=i+1
        EndWhile
        AsmStart
                if debug=1
        AsmEnd
                        i:=0
                        While i<currentNumberOfDigits
                                subscript:=i*4
                                AsmStart
                                        fld dword [subscript]
                                        fistp dword [subscript]
                                        mov ebx,[subscript]
                                        pushIntToStack (currentNumber+ebx)
                                        pushStringToStack integerSign
                                        call [printf]
                                AsmEnd
                                i:=i+1
                        EndWhile
                        AsmStart
                                pushStringToStack newLineString
                                call [printf]
                        AsmEnd
        AsmStart
                end if
        AsmEnd
        topOfMyStack:=topOfMyStack-1
        If currentNumberOfDigits=numberOfDigits
                i:=0
                While i<numberOfDigits
                        subscript:=i*4
                        AsmStart
                                fld dword [subscript]
                                fistp dword [subscript]
                                mov ebx,[subscript]
                                pushIntToStack (currentNumber+ebx)
                                pushStringToStack integerSign
                                call [printf]
                        AsmEnd
                        i:=i+1
                EndWhile
                AsmStart
                        pushStringToStack newLineString
                        call [printf]
                AsmEnd
        Else
                i:=0
                While i<10
                        counter:=0
                        j:=0
                        While j<currentNumberOfDigits
                                If currentNumber(j)=i
                                        counter:=counter+1
                                EndIf
                                j:=j+1
                        EndWhile
                        If counter<countDigits(i)
                                topOfMyStack:=topOfMyStack+1
                                myStack(topOfMyStack*(numberOfDigits+1)):=currentNumberOfDigits+1
                                j:=0
                                While j<currentNumberOfDigits
                                        myStack(topOfMyStack*(numberOfDigits+1)+(j+1)):=currentNumber(j)
                                        j:=j+1
                                EndWhile
                                myStack (topOfMyStack * (numberOfDigits + 1) + (j + 1) ) := i
                        EndIf
                        i:=i+1
                EndWhile
        EndIf
EndWhile
AsmStart
invoke system,_pause
invoke exit,0

_pause db "PAUSE",0
integerSign db "%d",0
newLineString db 10,0

section '.rdata' readable writable
original dd ?
result dd ?
lastDigit dd ?
numberOfDigits dd ?
countDigits dd 11 dup(?)
subscript dd ?
myStack dd 1000 dup(?)
topOfMyStack dd ?
counter dd ?
i dd ?
currentNumber dd 11 dup(?)
currentNumberOfDigits dd ?
j dd ?


section '.idata' data readable import
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'
AsmEnd    

The source code of the compiler, as well as the instructions on how to compile it and use it, can be downloaded here.
So, what do you think about it? Is it worth continuing developing it?
I am also dreaming about making my own LISP-like language, in which you will able to use both S-expressions and infix-expressions (since S-expressions come handy in array and string-manipulation, and infix-expressions come handy in arithmetic expressions), but I am unlikely to have time to develop it in foreseeable future.
Post 05 Jan 2019, 17:48
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.