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

LCC common code changes from Gigatron-LCC #48

Open
wants to merge 24 commits into
base: master
Choose a base branch
from

Conversation

lb3361
Copy link

@lb3361 lb3361 commented Sep 8, 2021

Here is a list of changes to the LCC common code that were required for the Gigatron VCPU backend. The changes have been reorganized as a succession of self-contained commits that can be taken independently with suitable comments. The 61ab and 7e12 commits are of general interest as they fix bugs that appear when compiling cpp or rcc with optimization enabled on a modern gcc-9 compiler on x86_64.

The gigatron backend (see https://raw.githubusercontent.com/lb3361/gigatron-lcc/master/src/gigatron.md) is very unusual because each lcc "instruction" can be a long sequence of opcodes that use the accumulator in a nearly optimal way. So instead of convering a tree with instructions, we map tree segments to sequences of instructions. Here is what the comment in gigatron.md says:

Once LCC has encoded a C function as a forest of trees, the LCC/Lburg code generator computes an optimal cover of the trees with assembly instructions in which only the registers are left to be specified. This optimality ignores the effects of the limited number of registers and the specialization of registers. When such problems occur, the register allocator spills registers to memory as needed for correctness, but without regard for optimality. That does not work well for a simplistic CPU like the Gigagron VCPU. Once vAC is allocated, there is nothing left one can do. The following code repurposes the LCC mechanisms in the following way. The LCC register allocator no longer deals with actual registers but with a piece of page zero memory that we call registers. Instead of computing a cover of the trees with instruction, we cover the trees with sequences of instructions that use the accumulator vAC and the scratch registers (T0..T3) as they see fit. The LBURG grammar is no longer a tree grammar, but a transducer that converts tree fragments into sequences. As a result, each nonterminal must be defined by two components: the role it occupies on the tree grammar and the role it occupies in the sequence grammar.

lb3361 and others added 24 commits September 8, 2021 18:15
Explanation: compiling with optimization often
defines memmove as __builtin_memmove with
subtle incompatibilities.
Explanation: Compilers expect dyamically allocated structs
to be aligned like the biggest builtin type (at least 16 bytes on x86_64)
and uses this knowledge when it optimizes structure copies using
128 bits SSE instructions (which require proper alignement.)
This fixes crashes when compiling rcc with gcc-9 -O4
Explanation: sometimes it is not obvious that compilation failed
because the error message is swamped in lots of warning messages.
Explanation: LOADs are also used for conversions.
This was an issue with the gigatron backend.
Explanation: This makes it easy to add new template escapes.
Explanation: This is useful for the admitedly
unconventional gigatron backend.
Explanation: the existing code assumes that non-terminal 1 is stmt
and that all genreloads can be processed as stmts. This is not
true for the admitedly unconventional gigatron backend. This
patch removes this assumption, allowing genreload to operate
anywhere in a tree cover.
Explanation: the existing code assumes sizeof(long)>=sizeof(int)>sizeof(short).
This is not true on the gigatron where both ints and shorts are 16 bits.
In the end I decided to implement the full set of rules.
Explanation: this prevents useless code when
the c contains no-op casts (which may
make sense for portability in fact.)

it used to replace truncating conversion with loads.
but nothing is needed when truncating to the same size!
This seems to enhance the whole bonus-match and
removal of useless cse code.
Explanation: assignargs relocates variable passed
in a register but allocated to a different register.
This eliminates the need to do this
inside the backend funcion() call. The mips
backend could be simplified for instance (but I
didn't do it because I cannot test it.)
…lburg rules

This allows to define a predicate that enables/disables
specific lburg rules when spilling is in effect.
Explanation: this provides an opportunity
to override the default register allocation
using more information than doing so in
prelabel. The gigatron backend uses
this to better use the accumulator vAC.
Explanation: backends that deal with RMW opcodes (INCR etc.)
can follow cse variables to find more opportunities
to use such efficient but tricky opcodes.
@lb3361 lb3361 changed the title Lcc pull request LCC common code changes from Gigatron-LCC Sep 9, 2021
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.

2 participants