Qemuonarm


Ari64 said:
In case it's not clear what I meant, here's a theoretical example:

Code:
 mul %ebx
 mov %eax,(%esi)
 mov (%edi),%edx

edx is written by the first instruction but never used. It gets overwritten by the third instruction. So it's unneeded, and on ARM it's possible to use mul instead of umull for this.
Funny example: it almost 100% the one I was discussing with a QEMU maintainer yesterday. The internal QEMU op for widening mul could be in that case changed to a non-widening one. Do you wander on QEMU IRC channel? :p

The only problem is what happens when the second instruction causes a pagefault. To enter the interrupt handler with the correct values, you'd have to recalculate edx.
I hacked QEMU to remove the flush of x86 registers cached in ARM registers around memory accesses. At the moment I don't care, but I have a solution to catch problems: regenerate the code for the block until the faulting PC, at which point I'll know in which ARM reg, x86 registers were allocated. One can then use the context passed to the signal handler to retrieve ARM reg contents. It would be costly, but it should not happen that often.

BTW, about the Beagle, I really am unlucky: the USB-serial cable I bought refuses to work correctly; I checked on another PC with a HW serial port and it works.
 
Last edited by a moderator:
Laurent said:
Ari64 said:
Code:
 mul %ebx
 mov %eax,(%esi)
 mov (%edi),%edx

edx is written by the first instruction but never used. It gets overwritten by the third instruction. So it's unneeded, and on ARM it's possible to use mul instead of umull for this.
Funny example: it almost 100% the one I was discussing with a QEMU maintainer yesterday. The internal QEMU op for widening mul could be in that case changed to a non-widening one. Do you wander on QEMU IRC channel? :p
No, I remembered that example because it turns out it's fairly difficult to make this optimization when recompiling MIPS code. I suspect it will work better when emulating x86. (Since the HI/LO registers are written infrequently it's often difficult to identify cases where one of the registers is unnecessary. I ended up optimizing a lot more trivial cases.)

Laurent said:
I hacked QEMU to remove the flush of x86 registers cached in ARM registers around memory accesses. At the moment I don't care, but I have a solution to catch problems: regenerate the code for the block until the faulting PC, at which point I'll know in which ARM reg, x86 registers were allocated. One can then use the context passed to the signal handler to retrieve ARM reg contents. It would be costly, but it should not happen that often.
Then you have to save the initial values. This can get complicated. It will probably work for many cases of flag elimination though.

Laurent said:
BTW, about the Beagle, I really am unlucky: the USB-serial cable I bought refuses to work correctly; I checked on another PC with a HW serial port and it works.
I use a USB-serial cable, I just needed a crossover (null modem) adapter.
 
Last edited by a moderator:
Ari64 said:
Laurent said:
I hacked QEMU to remove the flush of x86 registers cached in ARM registers around memory accesses. At the moment I don't care, but I have a solution to catch problems: regenerate the code for the block until the faulting PC, at which point I'll know in which ARM reg, x86 registers were allocated. One can then use the context passed to the signal handler to retrieve ARM reg contents. It would be costly, but it should not happen that often.
Then you have to save the initial values. This can get complicated. It will probably work for many cases of flag elimination though.
You're right, I didn't think about the cases where an ARM register represents a part of a computation and not exactly an x86 register. I think QEMU i386 front-end tries to make sure simulated x86 register contents should be OK (i.e. match what they would be on an x86) before issuing the ld/st. Which also makes me think code scheduling will be a real problem.

I use a USB-serial cable, I just needed a crossover (null modem) adapter.
I have that, I could log into the BB from an older computer. My USB serial definitely is the problem... I have set up everything.
And still I'm blocked: I can't ssh into the BB (I created an account, verified I could locally ssh), but no way to ssh from my PC. I wonder if using a test image was wise :unsure:
 
Last edited by a moderator:
Laurent said:
You're right, I didn't think about the cases where an ARM register represents a part of a computation and not exactly an x86 register. I think QEMU i386 front-end tries to make sure simulated x86 register contents should be OK (i.e. match what they would be on an x86) before issuing the ld/st. Which also makes me think code scheduling will be a real problem.
If you require that the registers exactly match the simulated x86 registers before the ld/st, then you will have to calculate edx for the mul instruction in the example above, and you can not make this optimization.

Laurent said:
I use a USB-serial cable, I just needed a crossover (null modem) adapter.
I have that, I could log into the BB from an older computer. My USB serial definitely is the problem... I have set up everything.
And still I'm blocked: I can't ssh into the BB (I created an account, verified I could locally ssh), but no way to ssh from my PC. I wonder if using a test image was wise :unsure:
No USB ethernet?
 
Last edited by a moderator:
Ari64 said:
If you require that the registers exactly match the simulated x86 registers before the ld/st, then you will have to calculate edx for the mul instruction in the example above, and you can not make this optimization.
Right, and this also means I have to review all the TCG level optimizations I had in mind.

No USB ethernet?
Ethernet over USB (g_ether) works since I can ping the board, but strangely ssh refuses connections. Perhaps some problem in dropbear configuration.
 
Last edited by a moderator:
The BB problem is in fact in the ethernet over USB. I properly configured it on my PC so that it recognizes the BB and configures usb0 correctly. The problem is that it seems that on BB side it's already too late and so its usb0 isn't corretly setup (no IP address).

Anyway using a PC with serial interface, I could at least give QEMU a try.
The BB is running at 500 MHz (at least I guess based on BogoMIPS being at 477).

Code:
nbench gcc 4.1.2
==========================ORIGINAL BYTEMARK RESULTS==========================
INTEGER INDEX       : 2.426
FLOATING-POINT INDEX: 0.494
Baseline (MSDOS*)   : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0
==============================LINUX DATA BELOW===============================
MEMORY INDEX        : 0.467
INTEGER INDEX       : 0.735
FLOATING-POINT INDEX: 0.274
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38

nbench gcc 2.96
==========================ORIGINAL BYTEMARK RESULTS==========================
INTEGER INDEX       : 1.578
FLOATING-POINT INDEX: 0.465
Baseline (MSDOS*)   : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0
==============================LINUX DATA BELOW===============================
MEMORY INDEX        : 0.327
INTEGER INDEX       : 0.452
FLOATING-POINT INDEX: 0.258
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38
 
Laurent said:
Ari64 said:
If you require that the registers exactly match the simulated x86 registers before the ld/st, then you will have to calculate edx for the mul instruction in the example above, and you can not make this optimization.
Right, and this also means I have to review all the TCG level optimizations I had in mind.
There are a few ways this can be done. In many cases you can just drop the values, leaving old values in the registers. This will work for userspace emulation as long as the process doesn't catch SIGSEGV (and probably still work even if it does).

If you know the initial state, you can re-execute the instructions. For an x86 mul instruction, this might not be possible since eax gets overwritten, so you might not know the initial values. But if you have something like this:
Code:
 mov memory,%eax
 mul %ebx
 mov %eax,(%esi)
then you can replay the instruction sequence and calculate edx, as long as you know that the store did not overwrite the intital value.

If you have some free registers, then you can copy into a temporary register and keep it until you know you won't have to back out due to an exception. If I were going to do this for flag generation, I'd keep track something like this:
Code:
 xor %eax,%eax        flags=zero
 and %edx,$0xff       flags=edx
 mov mem, %ecx        flags=edx
 lea (%ecx,%edx),%edx temp=edx; flags=temp
 mov %edx, mem        flags=temp
Then you can regenerate the missing values when an exception happens. You just have to move values into a temporary register when something is about to overwrite a register that you're tracking.


Laurent said:
The BB problem is in fact in the ethernet over USB. I properly configured it on my PC so that it recognizes the BB and configures usb0 correctly. The problem is that it seems that on BB side it's already too late and so its usb0 isn't corretly setup (no IP address).

Anyway using a PC with serial interface, I could at least give QEMU a try.
The BB is running at 500 MHz (at least I guess based on BogoMIPS being at 477).
Run ifconfig and set an IP address. Just make sure udev didn't rename eth0 to something else.

Integer doesn't look too bad considering the current level of optimization. Optimizing those 80-bit floats is going to be hard. :(
 
Last edited by a moderator:
Ari64 said:
If you know the initial state, you can re-execute the instructions. For an x86 mul instruction, this might not be possible since eax gets overwritten, so you might not know the initial values. But if you have something like this:
Code:
 mov memory,%eax
 mul %ebx
 mov %eax,(%esi)
then you can replay the instruction sequence and calculate edx, as long as you know that the store did not overwrite the intital value.
I don't think you could replay if there are multiple ld/st and the faulting one is not the first, unless you keep so much state that it defeats your optimizations :(

Optimizing those 80-bit floats is going to be hard. :(
Especially given that the results are for 64-bit floats... I don't handle 80-bit FP with native instructions (this should rely on the softfloat library, but QEMU is severely broken and doesn't even cross-compile with it enabled; given I don't care about 80-bit FP, I didn't take the time to fix that yet).
 
Last edited by a moderator:
Laurent said:
Ari64 said:
If you know the initial state, you can re-execute the instructions. For an x86 mul instruction, this might not be possible since eax gets overwritten, so you might not know the initial values. But if you have something like this:
Code:
 mov memory,%eax
 mul %ebx
 mov %eax,(%esi)
then you can replay the instruction sequence and calculate edx, as long as you know that the store did not overwrite the intital value.
I don't think you could replay if there are multiple ld/st and the faulting one is not the first, unless you keep so much state that it defeats your optimizations :(
If there are loads and stores then it's pretty much impossible. If it's just loads then it will work.

It's probably easier to copy into temporary registers. You'd need to:

- Save multiplicands when discarding eax or edx
- Save dividend when discarding remainder or quotient
- Save result when it is overwritten, but SF, ZF, PF are not
- Save addends if you can't keep the overflow or carry flag
- Save addends in the extremely rare case that you need the adjust flag

Most of these cases are pretty uncommon, so I don't think you'd have to keep that much state.
 
Last edited by a moderator:
Back
Top