<p>Rosetta 2 is a program that enables the new ARM-based Macs to run programs for old x86-based Macs by translating x86 machine code to ARM machine code. But how does it do that? What seems especially problematic is translating x87 (the legacy FPU) instructions to ARM machine code. x87 instructions are stack-based, and there is no stack-based FPU on ARM processors.</p>
<p>I am thinking about extending my <a href="https://flatassembler.github.io/compiler" rel="noreferrer">Arithmetic Expression Compiler</a> to be able to output not just x86 assembly code, but also ARM assembly code, so that knowledge will come useful to me.</p>

<stack><assembly><stack-based-languages>
How is Rosetta 2 capable of translating x87 instructions (which are stack-based) to ARM machine code (where the FPU is register-based)?
CC BY-SA 4.0
2024-04-09T11:22:51.727Z
are you sure they handle x87 instructions? most FPU math in x84-64 land is done using the simd execution units
ratchet freak
CC BY-SA 4.0
2024-04-09T11:23:34.163Z
the larger challenge by far for rosetta is implementing 80-bit floats, which are not supported in hardware on aarch64; they are likely implemented in software.  and the fact that precision is runtime-configurable.  fast emulation of x87 is unlikely to be a priority for rosetta, since it is somewhat slow even on intel/amd cpus (where it is natively supported in hardware), and is no longer commonly used by software
Moonchild
CC BY-SA 4.0
2024-04-09T11:25:06.350Z
what you are looking for is a _register allocation_ algorithm.  there are some straightforward algorithms that can be used for simple tree-based recursive expression languages and give acceptable results.  alternately, if you don't care about performance much (likely if you are targeting x87), then you could just generate aarch64 code that uses a stack manually
Moonchild
CC BY-SA 4.0
2024-04-09T13:09:49.567Z
There is a trivial way to translate stack machine code to register machine code, which is to use the register machine's stack as the stack. Then each operation is preceded by popping the operands to the appropriate registers, and followed by pushing the result to the stack. The trivial way can be optimised by remembering what's in each register, and cancelling "push, pop" instructions to the same register, or replacing them with "mov" if the value you want is still in a different register.
kaya3
CC BY-SA 4.0
2024-04-09T18:49:58.157Z
There's an article at https://ffri.github.io/ProjectChampollion/part1/ explaining how to access and disassemble the converted binaries, so you could see for yourself. I'd agree with the guess that x87 is probably just emulated in software, not necessarily very efficiently.  Modern code rarely uses x87 and prefers to do floating point with SSE (guaranteed supported on all x86-64). Your compiler should probably be doing that too.
Nate Eldredge
CC BY-SA 4.0
2024-04-09T18:55:47.853Z
Indeed, most compilers find it painful to target x87 because of the register stack. A flat register file, as with ARM and x86 SSE, is much more convenient. Your question suggests that your compiler is based on the stack model and you want to port that to ARM; but you're probably better off dropping the stack model altogether and assuming a flat register file from the outset. In that case, knowing how Rosetta2 handles x87 would not be relevant.
Nate Eldredge
CC BY-SA 4.0
2024-04-28T06:20:17.070Z
I took a look at some translated x87 code, and indeed it's mostly just a bunch of `bl` instructions that presumably call functions in the runtime to emulate the x87 instructions.  I found it tedious to trace into it (for some reason the program dies in lldb if you try to single-step or continue after a breakpoint) but I strongly suspect the virtual x87 registers are just kept in memory, so that the x87 stack pointer is just a pointer and can be moved with regular arithmetic.
Nate Eldredge
<p>Stack based languages can be converted into register based languages with register allocation. Register allocation can be solved with graph coloring, which is fairly advanced. However, if performance is not critical, then it can be done with a simpler algorithm. I think based on comments that others have left that in the case of Rosetta 2, it merely simulates a stack with registers. However, I think that what you are actually wondering is about how this can be done in the more general case. In a stack based language, the program is almost a linear substructure, excluding loads and stores. Thus a temporary should be dead once it is used, unless it is loaded or stored. When a substructure is linear and the number of pushs and pops of each instruction is known ahead of time, then one can simply keep a list (or set and stack) of live numbered temporaries and create a new temporary for each result and use the most recent temporaries to pass into instructions. Unfortunately, real world programs contain control flow, which means the number of pushs and pops may not be known at compile time. To handle control flow, one might want to consider simulating a stack.</p>
<p>I don't know much about stack based assembly instructions; however, I have tried working with converting an intermediate representation both to 3 address code and back to 4 address code, when working on a hobby compiler, where performance is not critical. I hope everything I have said is accurate and clear.</p>

CC BY-SA 4.0
2024-04-29T04:29:15.947Z
2024-04-29T04:29:15.947Z
ggZQX6YPvD
# How is Rosetta 2 capable of translating x87 instructions (which are stack-based) to ARM machine code (where the FPU is register-based)?
Posted by: username_0 on 2024-04-09
Rosetta 2 is a program that enables the new ARM-based Macs to run programs for old x86-based Macs by translating x86 machine code to ARM machine code. But how does it do that? What seems especially problematic is translating x87 (the legacy FPU) instructions to ARM machine code. x87 instructions are stack-based, and there is no stack-based FPU on ARM processors.

I am thinking about extending my [Arithmetic Expression Compiler](https://flatassembler.github.io/compiler) to be able to output not just x86 assembly code, but also ARM assembly code, so that knowledge will come useful to me.
**Tags:** stack assembly stack-based-languages
> **Comments:**
> **username_1**: are you sure they handle x87 instructions? most FPU math in x84-64 land is done using the simd execution units  
> **username_2**: the larger challenge by far for rosetta is implementing 80-bit floats, which are not supported in hardware on aarch64; they are likely implemented in software.  and the fact that precision is runtime-configurable.  fast emulation of x87 is unlikely to be a priority for rosetta, since it is somewhat slow even on intel/amd cpus (where it is natively supported in hardware), and is no longer commonly used by software  
> **username_2**: what you are looking for is a _register allocation_ algorithm.  there are some straightforward algorithms that can be used for simple tree-based recursive expression languages and give acceptable results.  alternately, if you don't care about performance much (likely if you are targeting x87), then you could just generate aarch64 code that uses a stack manually  
> **username_3**: There is a trivial way to translate stack machine code to register machine code, which is to use the register machine's stack as the stack. Then each operation is preceded by popping the operands to the appropriate registers, and followed by pushing the result to the stack. The trivial way can be optimised by remembering what's in each register, and cancelling "push, pop" instructions to the same register, or replacing them with "mov" if the value you want is still in a different register.  
> **username_4**: There's an article at https://ffri.github.io/ProjectChampollion/part1/ explaining how to access and disassemble the converted binaries, so you could see for yourself. I'd agree with the guess that x87 is probably just emulated in software, not necessarily very efficiently.  Modern code rarely uses x87 and prefers to do floating point with SSE (guaranteed supported on all x86-64). Your compiler should probably be doing that too.  
> **username_4**: Indeed, most compilers find it painful to target x87 because of the register stack. A flat register file, as with ARM and x86 SSE, is much more convenient. Your question suggests that your compiler is based on the stack model and you want to port that to ARM; but you're probably better off dropping the stack model altogether and assuming a flat register file from the outset. In that case, knowing how Rosetta2 handles x87 would not be relevant.  
> **username_4**: I took a look at some translated x87 code, and indeed it's mostly just a bunch of `bl` instructions that presumably call functions in the runtime to emulate the x87 instructions.  I found it tedious to trace into it (for some reason the program dies in lldb if you try to single-step or continue after a breakpoint) but I strongly suspect the virtual x87 registers are just kept in memory, so that the x87 stack pointer is just a pointer and can be moved with regular arithmetic.  
---
## 1 answers
### Answer by username_5 on 2024-04-29. Score: 2
Stack based languages can be converted into register based languages with register allocation. Register allocation can be solved with graph coloring, which is fairly advanced. However, if performance is not critical, then it can be done with a simpler algorithm. I think based on comments that others have left that in the case of Rosetta 2, it merely simulates a stack with registers. However, I think that what you are actually wondering is about how this can be done in the more general case. In a stack based language, the program is almost a linear substructure, excluding loads and stores. Thus a temporary should be dead once it is used, unless it is loaded or stored. When a substructure is linear and the number of pushs and pops of each instruction is known ahead of time, then one can simply keep a list (or set and stack) of live numbered temporaries and create a new temporary for each result and use the most recent temporaries to pass into instructions. Unfortunately, real world programs contain control flow, which means the number of pushs and pops may not be known at compile time. To handle control flow, one might want to consider simulating a stack.

I don't know much about stack based assembly instructions; however, I have tried working with converting an intermediate representation both to 3 address code and back to 4 address code, when working on a hobby compiler, where performance is not critical. I hope everything I have said is accurate and clear.
---
