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.
This would become necessary if something failed on a platform with
16-bit int (EM_WSIZE == 2).
Remove unreachable `ret 0`. If reached, it wouldn't work to return
from _m_a_i_n.
Don't output '\0' in "@@FINISHED\0".
Cast code to unsigned int. This helps platforms with 16-bit int, by
doing only the low 16 bits of the bitwise-and. It also removes the
"(warning) conversion of long to pointer loses accuracy".
ncgg has parsed the optional conditional expression (optexpr) of each
splitting coercion since commit 72b83cc in 1985; but for almost 33
years, ncg has ignored the expression in c2_expr.
Few tables had conditional coercions (I only found them in arm and
m68020), and no tables had conditional splitting coercions, so this
only becomes a problem now as I try to add a conditional splitting
coercion to powerpc.
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.
The code used `sphl` to set the stack pointer, but the correct value
was in de, not hl. Fix by swapping the values of de and hl, so `sphl`
is now correct. When we shrink an integer from 4 to 2 bytes, both
registers de and hl point to copies of the result, but only one
register preserves the stack below the result.
This fixes writehex() in tests/plat/lib/test.c, when I compile it with
ack -mcpm, so it preserves the pointer to "0123456789abcdef", so it
writes hexadecimal digits and not garbage.
This bug goes back to commit 157b243 of Mar 18, 1985, so the bug is
32 years old, and probably the oldest bug that I ever fixed.
I compiled tests/plat/lib/test.c with ack -mcpm, but i80 ncg did emit
wrong code in writehex(uint32_t) for
"0123456789abcdef"[code & 0xf]
The code called '.and' to evaluate `code & 0xf`, then tried to call
'.cii' to narrow the result from 4 to 2 bytes, but it passed garbage
instead of 4 to '.cii'. The rule for '.and' was
pat and defined($1)
kills ALL
uses dereg={const2,$1}
gen Call {label,".and"}
This failed to kill register de={const2,4}, so ncg pushed de,
expecting to push 4, but actually pushing garbage.
Fix such rules using `mvi a,...` or `lxi de,...` so ncg doesn't track
the token in the register. This is like the i86 table. A different
fix would use a dummy instruction `killreg a` or `killreg de` like the
m68020 table.
Also correct 1 to $1 when calling '.exg'.
I made a syntax error in some .e file, and em_encode dumped core
because a 64-bit pointer didn't fit in a 32-bit int. Now use stdarg
to pass pointers to error() and fatal().
Stop using the number of errors as the exit status. Many systems use
only the low 8 bits of the exit status, so 256 errors would become 0.
Also change modules/src/print to accept const char *buf
gcc gave an error because the `char *` parameter doesn't match the
`const char *` in the prototype of regsave(). clang didn't give an
error. I added the prototype in commit 5301cce.
This uncovers a problem in il/il_aux.c: it passes 3 arguments to
getlines(), but the function expects 4 arguments. I add FALSE as the
4th argument. TRUE would fill in the list of mesregs. IL uses
mesregs during phase 1, but this call to getlines() is in phase 2.
TRUE would leak memory unless I added a call to Ldeleteset(mesregs).
So I pass FALSE.
Functions passed to go() now have a `void *` parameter because
no_action() now takes a `void *`.
*Important:* Do `make clean` to work around a problem and prevent
infinite rebuilds, https://github.com/davidgiven/ack/issues/68
I edit tokens.g in util/LLgen/src, so I regenerate tokens.c. The
regeneration script bootstrap.sh can't find LLgen, but I can run the
same command by typing the path to llgen.
aprintf() returns a const char *; the assignment to char * caused both
clang and gcc to warn of the dropped const.
Commit 893471a introduced a tiny memory leak, because GetFile()
stopped freeing buf. The const return type of aprintf() suggests that
the buffer must not be freed.
Now use Malloc() to allocate the buffer and free() to free it. This
also checks if we are out of memory, because Malloc() does the check
and aprintf() currently doesn't.
Silence warning from clang at `if (ch2 = ...)`
Delete `|| rm %{outs}` in build.lua, because it hid the exit status of
tabgen, so if tabgen failed, the build continued and failed later.
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.
Files that #include "equiv.h" must do so after including "data.h", now
that a function prototype in equiv.h uses type rl_p from data.h.
Adjust style, changing some `for(...)` to `for (...)`. The style in
mach/proto/ncg is less than consistent; the big annoyance now is that
some files want tabs at 4 spaces, others want tabs at 8 spaces.
Put the declarations in "data.h", because that header declares the
types cost_t and token_p. Also #include <cgg_cg.h> from "data.h" to
get types c3_p and set_p, and guard <cgg_cg.h> against multiple
inclusion.
*Important:* You must "make clean" after checking out this commit,
because the build had copied the old "assert.h" to several places in
obj/. If you don't "make clean", then the compiler finds the old
"assert.h" before libc <assert.h>, and the build fails because this
commit removes badassertion() in subr.c. After "make clean", the
compiler finds libc <assert.h> and the build succeeds.
Switch from custom assert() to libc assert() in mach/proto/as.
Continue to disable asserts if DEBUG == 0.
This change found a problem in the build system; comm2.y was missing
depedencies on comm0.h and comm1.h. Add the missing dependencies to
the cppfile rule. Allow the dependencies by modifying cppfile in
first/build.lua to act like cfile if t.dir is false.
Now that comm2.y gets rebuilt, I must fix the wrong prototype of
yyparse() in comm1.h.
I got unlucky as induo() in comm5.c was reading beyond the end of the
array. It found an operator "= " ('=' then space) in the garbage, so
it returned a garbage token number, and "VAR = 123" became a syntax
error. Unbreak induo() by terminating the array.