Skip to content
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

Merged
merged 11 commits into from
Jan 26, 2017
Merged

Conversation

kernigh
Copy link
Contributor

@kernigh kernigh commented Jan 26, 2017

I add extended mnemonics (or simplified mnemonics) like beq and extrwi 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.

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.
r0 is a special case and can't be used when adding a register to a
constant.  The few remaining users of the scratch register don't do
that.  I removed other usages of the scratch register in 7c64dab,
5b5f774, 19f0eb8, f64b7d8.
@kernigh
Copy link
Contributor Author

kernigh commented Jan 26, 2017

The failure from Travis is

**** /tmp/ack-build/obj/plat/linuxppc/tests/tests/linuxppc-bug-22-inn_mod-testlog.txt
@@FAIL

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.

@davidgiven davidgiven merged commit 559233e into davidgiven:default Jan 26, 2017
@davidgiven
Copy link
Owner

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.

@davidgiven
Copy link
Owner

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 addi rX, r0, 0. Oops.

@kernigh kernigh deleted the kernigh-pr-xm branch January 27, 2017 02:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants