Add more page numbers from PowerPC version 2.01. Remove "xnop" not in
2.01, add "mtcr" from 2.01. Add "lwarx" and the other instructions
from Book II. I did not try all the newly added instructions, but
these seem to work: dcbt, dcbtst, icibi, isync, lwarx, stwcx., mftb,
mftbu
In man/powerpc_as.6 (not installed), add a summary of the registers
and addressing modes (like in i386_as.6), describe short forms, update
description of hi16/ha16, add CAVEATS about instructions that some
processors can't run.
If X < 0, then lowering the addi might cause the code to use the stack
space before allocating it. This is a bug because an asynchronous
signal handler can overwrite the unallocated stack space.
Tests pass if one edits the top build.lua to uncomment "qemuppc" from
both vars.plats and vars.plats_with_tests, and one leaves mcg in
plat/qemuppc/descr.
Add or correct some EM instructions in treebuilder.c:
- "lof", "stf": handle negative offsets in load() and store().
- "cuu": add using IR_FROMUI.
- "lim", "sim": keep an entire word in ".ignmask", to be compatible
with mach/powerpc/libem/trp.s and ncg. We also keep a word in
".ignmask" in ncg for both i386 and m68020.
- "trp": pass trap number in register. See comment in
helper_function_with_arg().
- "sig": push the old value of .trppc on the stack.
- "and ?", "ior ?", "xor ?", "com ?", "cms ?", "set ?", "inn ?":
connect to helper functions in libem.
- "blm", "bls": drop call to memmove() and use new helper ".bls4",
because tests/plat/structcopy_e.c can't call memmove().
- "xor s", "cms s": if s is large, fall back on helper function.
- "rol", "ror": add by decomposing each rotate into 4 IR ops.
- "rck s", "bls s": make fatal unless s is word size.
- "loi": push multiple loads in the correct order.
- "dup s", "exg s": if s is large, fall back on helper.
- "dus": add using new helper ".dus4".
- "lxl", "lxa": follow the static chain, not the dynamic chain.
- "lor 1": materialise the stack before pushing the stack pointer.
- "lor 2", "str 2": make fatal.
- "los", "sts": drop calls to memcpy() and use helpers ".los4" and
and ".sts4", so lang/m2/libm2/LtoUset.e starts working.
- "gto": correctly read descriptor.
Change mach/powerpc/mcg/table:
- ANY.L: add for "asp -8".
- LOAD.L: work around register corruption.
- COMPAREUL.I: add for "cms 8".
In the instruction list, put /* kills xer */ for sraw, srawi, subfic;
and correct the (now unused) "addi." and "lfdu".
Change MACHOPT_F from -m3 to -m2. This changes the code for 15 * i
from
slwi r3,r4,4
subfic r5,r4,0
add r3,r3,r5
to
mulli r3,r4,15
If the sequence "slwi subfic addi" takes 3 cycles and 12 bytes, and
mulli takes 3 cycles and 4 bytes, then mulli is better.
Copy and adapt code from mach/{i386,m68020}/ncg/mach.c to pass the
debugging stabs from EM to assembly. The next tools (as, led, cv)
already know how to put the stabs in the Mach-o executable.
Modify the function prolog/prologue so gdb uses fp, not sp, for N_LSYM
and N_PSYM stabs. Simplify prolog() by reducing differences between
stabs and no stabs, and zero and nonzero framesize. For files without
stabs, the new prolog has the same number of instructions and memory
accesses as the old prolog, and to run at about the same speed on my
PowerPC Mac.
This is enough to see some info for global and local variables in gdb
for Mac OS X. I still can't get a backtrace; gdb gets confused
because EM and ncg don't link 0(sp) to the previous stack frame.
I don't expect `ack -mlinuxppc -g` to work with gdb for Linux, because
we prepend underscores to the symbol table, which is correct for
Mach-o but wrong for ELF.
This simplifies parts of the PowerPC table and causes ncg to better
decide whether to push sp or fp to the real stack, or coerce it to
REG3, or coerce it to REG-REG3, or move it to a regvar. These better
decisions remove extra _mr_ instructions.
The idea comes from mach/powerpc/arm/table, where SP has a property
STACKPOINTER and LB has LOCALBASE. I don't need two properties, so I
make one property SPFP for both registers.
When I wrote fef 8, I forgot to test denormalized numbers. Oops. Now
fix two of my mistakes:
- When checking for zero, `extrwi r6, r3, 22, 12` needs to be
`extrwi r6, r3, 20, 12`. There are only 20 bits to extract.
- After the multiplication by 2**64, I forgot to put the fraction in
[0.5, 1) or (-1, 0.5] by setting IEEE exponent = 1022.
Teach fif 8 about signed zero and NaN.
In ncg/table, change cmf so NaN is not equal to any value, and comment
why ordered comparisons don't work with NaN. Also add cost for
fctwiz, remove extra `uses REG`.
Edit comment in cfu8.s because the conditional branch might be before
or after fctwiz.
With my PowerBook G4, a program that converts values from 1.0 to
4000000.0 runs in about 0.32s with the old .cfu8 and 0.29s with this
shrunken .cfu8
Leave a comment about other ways to implement .cfu8
This reduces code size, because ncg emits too many "addi sp, sp, X"
instructions when unstacking things. Now top lowers "addi sp, sp, X"
by lifting other instructions. This sometimes creates chances to
merge or delete _addi_ instructions. If no such chance is found, the
_addi_ remains uselessly lowered.
Edit ncg/table to remove something that top now does.
Edit ncg/mach.c to remove some spaces after commas. This removes a
whitespace difference between *.s and *.so files, because top removes
the space.
_lim_ must use _loe_ (load word external), not _lde_ (load double-word
external).
The new patterns for _lxl_, _lxa_, _lor_, _str_ emit shorter code in
some cases. The change from GPR_EXPR to REG_EXPR allows moving
LXFRAME to a register variable.
Add more "reusing" clauses. We have enough registers that ncg almost
never reuses a register, but sometimes it can reuse r3.
In mach.c, emit one fewer instruction in procedures with no locals.
Fix PowerPC ncg so setjmp() returns the correct value. I got unlucky
when ncg picked r3 for "uses REG"; this destroyed the return value in
r3 and caused the new test to fail.
The new test rck_e.e segfaults on PowerPC unless I make some changes.
The inline code for _rck_ was wrong because it didn't allow the trap
handler to return. _sig_ forgot to push the old trap handler.
Move plat/linuxppc/libsys/trap.s to mach/powerpc/libem/trp.s and
rewrite it with simplified/extended mnemonics. Remove .trap alias for
.trp procedure. Add a missing `mtspr lr, r0` so we can return from
the trap handler. Call write() and _exit() so trp.s works with both
linuxppc and osxppc. Before, Mac OS X was wrongly using the trap.s
for Linux.
In powerpc/libem, simplify .aar4; teach .csa and .csb to raise the
trap if the default target is zero.
C programs don't need these changes. You may relink your C programs
with the changed .csa and .csb, but C code doesn't raise the trap.
Modula-2 code can raise traps, so you may want to relink your Modula-2
programs with the changed libem, but you might keep your old .o files
from Modula-2. You may need to recompile your Pascal programs (delete
old .o files from Pascal) because the Pascal compiler might use _rck_.
I understand `loi 4` more easily than `loi INT32`, because `loi 4`
appears in .e files. So remove INT8, INT16, INT32, INT64.
Add a comment to explain r3 during unconditional jumps.
When storing to a local, stop killing the tokens of other locals,
unless they might overlap with the stored local. This helps some
procedures that juggle locals when the locals aren't in registers.
Also use FRAME_V tokens for locals in statically enclosing procedures.
Rewrite _lxa_ as _lxl_, to skip the `addi ?,?,8` if we can add 8 to
the next constant. The PowerPC code from _lxl_ is now sometimes
better, sometimes worse than before.
The i386 table provided the idea to use %size to find overlapping
locals.
Prefer the rule with REG FREG, by coercing IND_RC_D or IND_RR_D to
FREG. This rule looks better to ncg. When ncg chose between coercion
to REG IND_RC_D or coercion to REG FREG, it chose REG FREG. It only
chose REG IND_RC_D if the stack had exact REG IND_RC_D.
Allow asp 4, exg 4 to shuffle tokens without coercing them into
registers; but comment why dup 4, dup 8 coerce tokens into registers.
Allow dup, dus, exg with larger sizes; and add tests dup_e.e and
exg_e.e to check that dup 20, dus, exg 20 work as well in powerpc as
in i80 and i86.
Then powerpc failed to compile loc 2 loc 4 cuu in dup_e.e. Revise the
integer conversions, so powerpc can compile and pass the test.
When a rule `uses REG ... yields %a`, the result %a is always a
temporary, never a regvar. If the EM code uses _stl_ to put the
result in a regvar, then ncg emits _mr_ to move %a to the regvar.
There are two ways to put the result in the regvar without %a:
1. Yield a token, as in `yields {MUL_RR, %2, %1}`, so that _stl_
can move the token to the regvar without using %a.
2. Provide a pattern, like `sli stl`, that just puts the result
in `{LOCAL, $2}` and not %a.
Allow some tokens, like SUM_RIS and XEQ, onto the stack; and add
tokens like MUL_RR, and patterns like `sli stl`.
Delete patterns for `stl lol` and `sdl ldl` to avoid an extra
temporary %a when the local is a regvar. Delete `lal sti lal loi`
because it would emit wrong code.
Rename token CONST to C. Define set CONST = C + CONST_STACK. The
instructions with CONST operands can now accept CONST_STACK tokens;
some cases of {CONST, %1.val} become %1.
Also simplify two of _rlwinm_ into _slwi_ and _srwi_.
EM instructions _rol_ and _ror_ do rotate an integer left or right.
Our compilers and optimizers never emit _rol_ nor _ror_, but I might
want to use them in the future.
Add _rol_ and _ror_ to powerpc. Fix `rol 4` and `ror 4` in both i80
and i86, where the rules for `rol 4` and `ror 4` seem to have never
been tested until now.
This breaks all machines because the declared return type void
disagrees with the implicit return type int (when I compile mach.c
with clang). Unbreak i386, i80, i86, m68020, powerpc, vc4 by adding
the return types to mach.c. We don't build any other machines; they
are broken since commit a46ee91 (May 19, 2013) declared void prolog()
and commit fd91851 (Nov 10, 2016) declared void mes(), with both
declarations in mach/proto/ncg/fillem.c.
Also fix mach/vc4/ncg/mach.c where type full is long, so fprintf()
must use "%ld" not "%d" to print full nlocals.
In util/ncgg, add two more errors for tables using reglap:
- "Two sizes of reg_float can't be same size"
- "Missing reg_float of size %d to contain %s"
In mach/proto/ncg, rename macro isregvar_size() to PICK_REGVAR(), so
the macro doesn't look like a function. This macro sometimes doesn't
evaluate its second argument.
In mach/powerpc/ncg/mach.c, change type of lfs_set to uint32_t, and
change the left shifts from 1U<<regno to (uint32_t)1<<regno, because
1U would be too small for machines with 16-bit int.
This relocation is specific to PowerPC. @davidgiven suggested the
name RELOPPC_LIS in
https://github.com/davidgiven/ack/pull/52#issuecomment-279856501
Reindent the list in h/out.h and util/led/ack.out.5 because
RELOLIS_PPC is a long name. I use spaces and no tabs because the tabs
looked bad in the manual page.
Because lwzu or stwu moves the pointer, I can remove an addi
instruction from the loop, so the loop is slightly faster.
I wrote a benchmark in Modula-2 that exercises some of these loops. I
measured its time on my old PowerPC Mac. Its user time decreases from
8.401s to 8.217s with the tighter loops.
The result of single-precision fadds, fsubs, and such can go into a
register variable, like we already do with double precision. This
avoids an extra fmr from a temporary register to the regvar.
Do the conversion by calling .cif8 or .cuf8 in libem, as it was done
before my commit 1de1e8f. I used the inline conversion to experiment
with the register allocator, which was too slow until c5bb3be.
Now that libem has the only copy of the code, move some comments and
code changes there.
Rename GPRE to GPR_EXPR, then define FPR_EXPR and FSREG_EXPR. Use
them for moves to register variables.
Keep "kills regvar($1)", because deleting it and recompiling libc
would cause many failures in my test programs. Add comment to warn,
/* ncg fails to infer that regvar($1) is dead! */
Remove "kills LOCAL %off==$1" because it seems to have no effect.
The new feature "reglap" allows two sizes of floating-point register
variables (reg_float), if each register overlaps a single register of
the other size. PowerPC ncg uses reglap to define 4-byte instances
of f14 to f31 that overlap the 8-byte instances.
When ncgg sees the definition of fs14("f14")=f14, it removes the
8-byte f14 from its rvnumbers array, and adds the 4-byte fs14 in its
place. Later, when ncg puts a variable in fs14, if it is an 8-byte
variable, then ncg switches to the 8-byte f14. The code has
/* reglap */ comments in util/ncgg or #ifdef REGLAP in mach/proto/ncg
reglap became necessary because my commit a20b87c caused PowerPC ego
to allocate reg_float in both 4-byte and 8-byte sizes.
After c5bb3be, ncg began to allocate regvars from r13 up. I reorder
the regvars so ncg again allocates them from r31 down. I also reorder
the other registers.
This exposed a bug in my rule for ret 8. It was wrong if item %2 was
in r3, because I moved %1 to r3 before %2 to r4. Fix it by adding
back an individual register class for r3 (called REG3 here, GPR3 in
c5bb3be).
Also fix my typo in mach.c that made a syntax error in assembly.
This removes a wrong-way dependency of libsys on libem. The C
functions in libsys called .ret, but libsys is after libem in the
linker arguments, so the linker didn't find .ret unless something else
had called .ret. Almost everything called .ret, but I got a linker
error when I wrote an assembly program using the EM runtime, because
my assembly program didn't call .ret.
Add a dummy comment to build.lua, so git checkout touches that file,
the build system reconfigures itself, and the *.s glob sees that ret.s
has gone.
Use f14 to f31 as register variables for 8-byte double-precison.
There are no regvars for 4-byte double precision, because all
regvar(reg_float) must have the same size. I expect more programs to
prefer 8-byte double precision.
Teach mach/powerpc/ncg/mach.c to emit stfd and lfd instructions to
save and restore 8-byte regvars. Delay emitting the function prolog
until f_regsave(), so we can use one addi to make stack space for both
local vars and saved registers. Be more careful with types in mach.c;
don't assume that int and long and full are the same.
In ncg table, add f14 to f31 as register variables, and some rules to
use them. Add rules to put the result of fadd, fsub, fmul, fdiv, fneg
in a regvar. Without such rules, the result would go in a scratch
FREG, and we would need fmr to move it to the regvar. Also add a rule
for pat sdl inreg($1)==reg_float with STACK, so we can unstack the
value directly into the regvar, again without a scratch FREG and fmr.
Edit util/ego/descr/powerpc.descr to tell ego about the new float
regvars. This might not be working right; ego usually decides against
using any float regvars, so ack -O1 (not running ego) uses the
regvars, but ack -O4 (running ego) doesn't use the regvars.
Beware that ack -mosxppc runs ego using powerpc.descr but -mlinuxppc
and -mqemuppc run ego without a config file (since 8ef7c31). I am
testing powerpc.descr with a local edit to plat/linuxppc/descr to run
ego with powerpc.descr there, but I did not commit my local edit.
This fixes lxl 1 (so it follows the static chain, not the dynamic
chain) and provides lxl 2 and greater. The Modula-2 compiler uses lxl
for nested procedures, so they can access the variables of the
enclosing procedures.
I added REG_PAIR in cfbc537 to speed up the register allocator,
because ncg was taking about 2 seconds on each sti 8. I defined only
4 such pairs, so allocating REG_PAIR was much faster than allocating
REG REG.
After my last commit c5bb3be, allocation of REG REG is fast, and
REG_PAIR seems unnecessary.
The table for PowerPC had placed each GPR and FPR into an individual
register class (like GPR3, GPR4, FPR1, FPR2), and had used these
classes to coerce stack values into specific registers. But ncg does
not like having many register classes.
In http://tack.sourceforge.net/olddocs/ncg.pdf
Hans van Staveren wrote:
> Every extra property means the register set is more unorthogonal and
> *cg* execution time is influenced by that, because it has to take
> into account a larger set of registers that are not equivalent. So
> try to keep the number of different register classes to a minimum.
Recent changes to the PowerPC table have removed many coercions to
specific registers. Many functions in libem switched from taking
values in registers to taking them from the stack (see dc05cb2).
I now remove all 64 individual register classes of GPR and FPR. In
the few cases where I need a stack value in a specific register, I now
do a move (as the arm and m68020 tables do).
This commit speeds the compilation of some files. For my test file
fconv.c, the compilation time goes from over 20 seconds to under 1
second. My fconv.c has 4 conversions from floats to integers, and the
table has my experimental rules that do the conversions by allocating
4 or 5 registers.
Switch .cms to pass inputs and outputs on the real stack, not in
registers; like we do with .and, .or (81c677d) and .xor (c578c49).
At this point, nearly all functions in libem use the real stack, not
registers, for passing inputs and outputs. This simplifies the ncg
table (which needs fewer lists of specific registers) but slows calls
to libem.
For example, after ba9b021, each call to .aar4 is about 10
instructions slower. I moved 3 inputs and 1 output from registers to
the real stack. A program would take 4 instructions to move registers
to stack, 4 to move stack to registers, and perhaps 2 to adjust the
stack pointer.