0

I am trying to make a compiler for my own simple programming language. It should output Intel-syntax x86 assembly. However, I am struggling to make it produce the correct code for the decimal numbers. Specifically, I am trying to implement the "exp" function to calculate "pow(e,x)", where 'e' is the base of the natural logarithm. Here is an example:

/*Preiously declared the variables 'result' and 'x' as global 32-bit floating-point numbers*/
result=exp(x)

Here is the code the compiler outputs for that example:

finit
fld dword [x]
fldl2e
fmulp st1,st0
fst dword [result]
fld1
fscale
fld1
fld dword [result]
fprem
fxch
f2xm1
fld1
faddp st1,st0
fmulp st1,st0
fstp dword [result]

To my best knowledge of x86 assembly, the code appears correct. However, it appears as though the "result" is, after that code, zero, no matter what 'x' is. Can you find the error in the code? Thanks!

FlatAssembler
  • 667
  • 7
  • 30
  • So what values do you have on the stack during calculation? Did you debug it? – Ped7g Feb 09 '18 at 21:01
  • How exactly would you recommend me to debug it? – FlatAssembler Feb 09 '18 at 21:20
  • 2
    with debugger. What is your platform? I have commercial turbo debugger for 16b DOS, in linux I'm using edb-debugger, but gdb is available almost everywhere. Not sure about windows, I think visual studio is still reasonable, but haven't seen it for years. – Ped7g Feb 09 '18 at 21:27
  • Of developer tools, I only have the Flat Assembler installed on my Windows computer. I am writing the compiler in JavaScript and running it in a browser. Which debugger would you recommend me to learn? – FlatAssembler Feb 09 '18 at 21:35
  • probably simplest thing is one for your target platform. You managed to avoid to specify that. I already gave you hints above for all common variants. It doesn't matter what you use to produce the machine code, as long as you have machine code, you can load it in any decent debugger and execute it. Of course it makes things simpler, if the machine code is stored in some kind of executable native to your platform, so you don't have to inject it into running process in some weird way, but for a short piece of code like yours, even entering it in debugger manually is feasible. – Ped7g Feb 09 '18 at 21:39
  • I meant, I was targetting 32-bit Windows. – FlatAssembler Feb 09 '18 at 21:47

1 Answers1

2

try:

finit
fld dword [_x]
fldl2e
fmulp st1,st0       ;st0 = x*log2(e) = tmp1
fld1
fscale              ;st0 = 2^int(tmp1), st1=tmp1
fxch
fld1
fxch                ;st0 = tmp1, st1=1, st2=2^int(tmp1)

fprem               ;st0 = fract(tmp1) = tmp2
f2xm1               ;st0 = 2^(tmp2) - 1 = tmp3
faddp st1,st0       ;st0 = tmp3+1, st1 = 2^int(tmp1)
fmulp st1,st0       ;st0 = 2^int(tmp1) + 2^fract(tmp1) = 2^(x*log2(e))
fstp dword [_result]        
ret

My apologies for not explaining what I changed, but this was really difficult for me to figure out.

C_Elegans
  • 1,113
  • 8
  • 15
  • I think `fsub( x, frndint(x))` also works to get the fractional part, and is *much* more efficient than `fprem`. Or is that numerically not as good? There's also `fxtract` to split into exponent and significand, if that helps. – Peter Cordes Feb 10 '18 at 02:09
  • 1
    I really don't know. Though if OP is worried about performance then they really should be using sse instead of x87. – C_Elegans Feb 10 '18 at 02:34