-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PowerPC extended mnemonics #49
Conversation
Also make a few changes to basic mnemonics. Fix typo in name of the basic "creqv". Add the basic "addc" and relatives, because it would be odd to have the extended "subc" without "addc". Fix the basic "rldicl", "rldicr", "rldic", "rldimi" to correctly encode the 6-bit MB field. Fix "slw" and relatives to correctly swap their RA and RS operands. Add many, but not all, of the extended mnemonics from IBM's Power ISA Version 2.06 Book I Appendix E. (I used 2.06, published 2009, just because I already had the PDF of it.) This commit includes mnemonics for branching, subtraction, traps, bit rotation, and a few others, like "mflr" and "nop". The assembler now understands branches like `beq cr7, label` and bit shifts like `slwi r7, r7, 2`. These encode the same machine instructions as the basic "bc" and "rlwinm". Some operands to basic names become optional. The assembler no longer requires the level in "sc" or the branch hint in "bcctr" and "bclr"; they default to zero. Some extended names take an optional branch hint or condition register. Some extended names are still missing. I don't provide names with static branch prediction, like "beq+" or "bge-", because the assembler parses '+' and '-' as operators, not as part of an instruction name. I also don't provide some names that 2.06 has for moving to or from the condition register or some special purpose registers, names like "mtcr" or "mfuamr". This commit also deletes some unused tokens and one unused yacc rule.
Linux passes the arguments in registers, but our compiler expects arguments on the stack. Signal handlers got garbage instead of the signal number. Some handlers, like the one in lang/m2/libm2/sigtrp.c, need the correct signal number. I write a "bridge" in PowerPC assembly that moves the arguments to the stack. I put the bridge in sigaction(), so I provide a signal() that calls sigaction(). I remove the *.c glob or wildcard from build.lua, so linuxppc only compiles its own signal.c, not the other signal.c for linux386 and linux68k. My bridge uses sigprocmask(), so I also add sigprocmask(). Because linux386 and linux68k use globs, they also get sigprocmask(). I sync the header files so all three Linux platforms declare execve(), sigprocmask(), and unlink(), but not remove(), because we have remove() in <stdio.h>. I am using sigaction.s to test some features that we recently added to our PowerPC assembler. These are the "hi16[...]" and "lo16[...]" syntax, and also the extended names like "beq", "cmpwi", "li", "subi".
I need this for relocations in lis/lfd pairs. I add lfd along with addi, lfs, lha, stfs, stfd to the list.
The new features are the hi16/lo16 and ha16/lo16 syntax for relocations, and the extended mnemonics like "blr". Use ha16/lo16 to load some double floats with 2 instructions (lis/lfd) instead of 3 (lis/ori/lfd). Use the extended names for branches, comparisons, and bit rotations, so I can more easily read the code. The new names often encode the same machine instructions as the old names, except in a few places where I changed the instructions. Stop using andi. when we don't need to set cr0. In inn.s, I change andi. to extrwi to extract the same bits. In los.s and sts.s, I change "andi. r3, r3, ~3" to "clrrwi r3, r3, 2". This avoids setting cr0 and also stops clearing the high 16 bits of r3. In csa.s, los.s, sts.s, I change some comparisons and right shifts from signed to unsigned (cmplw, cmplwi, srwi), because the sizes are unsigned. In inn.s, the right shift can be signed (sraw) or unsigned (srw), but I use srw because we don't need the carry bit. In fef8.s, I save an instruction by using rlwinm instead of addis/andc to rlwinm to clear a field. The code no longer kills r7. In both fef8.s and fif8.s, I remove the list of killed registers. Also remove some whitespace from ends of lines.
This is for fef 8 and fif 8. I changed .fef8 so it no longer kills r7, but I don't want to update the list. We already use "kills ALL" for most other calls to libem.
Always use 'kills ALL' when reaching a label, because our registers and tokens have the wrong values if the program jumps to this label from somewhere else. When falling through a label, if the top element is in r3, then require that the rest of the stack is in the real STACK, not in registers or tokens. I'm doing this to be certain that the missing constraints are not causing bugs. I did not find any such bug, perhaps because the labels are usually near other instructions (like conditional branches and function calls) that stack or kill tokens.
This fixes the coercion from IND_ALL_D to FREG. The coercion had never happened, because IND_ALL_D had 8 bytes but FREG had 4 bytes. Instead, ncg always stacked the IND_ALL_D and unstacked a FREG. The stacking rule uses f0, so the code did load f0 with the indirect value, push f0 to stack, load f1 to stack, move stack pointer. Now that FREG has 8 bytes, ncg does the coercion, and the code just loads f1 with the indirect value.
The rewritten code rules bring 3 new features: 1. The new rules compare a small constant with a register by reversing the comparison and using `cmpwi` or `cmplwi`. The old rules put the constant in a register. 2. The new rules emit shorter code to yield the test results, without referencing the tables in mach/powerpc/ncg/tge.s. 3. The new rules use the extended `beq` and relatives, not the basic `bc`, in the assembly output. I delete the old tristate tokens and the old moves, because they confused me. Some of the old moves weren't really moves. For example, `move R3, C0` and then `move C0, R0` did not move r3 to r0. I rename C0 to CR0.
Nothing uses the tables in tge.s, after I changed the ncg table. There are no *.e files in libem, so don't try to build them.
Also don't delete addis r0, r0, 0. These instructions are special cases that set r0 to zero. If we delete them, then r0 keeps its old value. I caught this bug because osxppc protects the .text segment against writing. (linuxppc doesn't protect it.) A program tried to set r0 to the NULL pointer, but top deleted the instruction, so r0 kept an old return address pointing into .text. Later the program checked that r0 wasn't NULL, tried to write to address r0, and crashed.
The failure from Travis is
I don't see any failure when I do the build with my OpenBSD/amd64 machine, but my machine skips some tests and Travis skips some other tests. I did edit mach/powerpc/libem/inn.s, so perhaps I broke something there. |
Works fine on my machine (92 tests run, 92 tests pass). The Travis machine is using qemu-user 1.0.50, which according to the timestamp is from 2012. My machine is running 1:2.1. I'm inclined to put that down to a qemu bug. |
Building using Travis' experimental trusty image also fails, but differently --- after 24 minutes the build is killed because no output has been produced for the last 10 minutes. The last thing in the build log appears to be running the newdispose test for linux386. So... I think we just have to disable the tests on Travis? Which I really don't want to do, but if they're not going to actually usefully test anything, then there's no point having them... Anyway, thank you for doing this; I can really use the new mnemonics. Also, good catch with |
I add extended mnemonics (or simplified mnemonics) like
beq
andextrwi
to the PowerPC assembler (5aa2ac2), then I start using them (and ha16, hi16, lo16 from #45). Signal handlers for linuxppc now get arguments. libem and ncg use the extended names for bit rotations and conditional branches. Also, led allows lo16 with more instructions, ncg can now coerce 8-byte tokens to registers, and top no longer deletes addi r0, r0, 0.I did not test all the instructions in our assembler. There's some confusion about whether or not instructions swap the RS and RA operands. I changed this for some instructions, like
slw
, but I believe that some instructions still emit operands in the wrong order.