nixify
This commit is contained in:
141
doc/abi.txt
Normal file
141
doc/abi.txt
Normal file
@@ -0,0 +1,141 @@
|
||||
==================
|
||||
System V ABI AMD64
|
||||
==================
|
||||
|
||||
|
||||
This document describes concisely the subset of the amd64
|
||||
ABI as it is implemented in QBE. The subset can handle
|
||||
correctly arbitrary standard C-like structs containing
|
||||
float and integer types. Structs that have unaligned
|
||||
members are also supported through opaque types, see
|
||||
the IL description document for more information about
|
||||
them.
|
||||
|
||||
|
||||
- ABI Subset Implemented
|
||||
------------------------
|
||||
|
||||
Data classes of interest as defined by the ABI:
|
||||
* INTEGER
|
||||
* SSE
|
||||
* MEMORY
|
||||
|
||||
|
||||
~ Classification
|
||||
|
||||
1. The size of each argument gets rounded up to eightbytes.
|
||||
(It keeps the stack always 8 bytes aligned.)
|
||||
2. _Bool, char, short, int, long, long long and pointers
|
||||
are in the INTEGER class. In the context of QBE, it
|
||||
means that 'l' and 'w' are in the INTEGER class.
|
||||
3. float and double are in the SSE class. In the context
|
||||
of QBE, it means that 's' and 'd' are in the SSE class.
|
||||
4. If the size of an object is larger than two eightbytes
|
||||
or if contains unaligned fields, it has class MEMORY.
|
||||
In the context of QBE, those are big aggregate types
|
||||
and opaque types.
|
||||
5. Otherwise, recursively classify fields and determine
|
||||
the class of the two eightbytes using the classes of
|
||||
their components. If any is INTEGER the result is
|
||||
INTEGER, otherwise the result is SSE.
|
||||
|
||||
~ Passing
|
||||
|
||||
* Classify arguments in order.
|
||||
* INTEGER arguments use in order `%rdi` `%rsi` `%rdx`
|
||||
`%rcx` `%r8` `%r9`.
|
||||
* SSE arguments use in order `%xmm0` - `%xmm7`.
|
||||
* MEMORY gets passed on the stack. They are "pushed"
|
||||
in the right-to-left order, so from the callee's
|
||||
point of view, the left-most argument appears first
|
||||
on the stack.
|
||||
* When we run out of registers for an aggregate, revert
|
||||
the assignment for the first eightbytes and pass it
|
||||
on the stack.
|
||||
* When all registers are taken, write arguments on the
|
||||
stack from right to left.
|
||||
* When calling a variadic function, %al stores the number
|
||||
of vector registers used to pass arguments (it must be
|
||||
an upper bound and does not have to be exact).
|
||||
* Registers `%rbx`, `%r12` - `%r15` are callee-save.
|
||||
|
||||
~ Returning
|
||||
|
||||
* Classify the return type.
|
||||
* Use `%rax` and `%rdx` in order for INTEGER return
|
||||
values.
|
||||
* Use `%xmm0` and `%xmm1` in order for SSE return values.
|
||||
* If the return value's class is MEMORY, the first
|
||||
argument of the function `%rdi` was a pointer to an
|
||||
area big enough to fit the return value. The function
|
||||
writes the return value there and returns the address
|
||||
(that was in `%rdi`) in `%rax`.
|
||||
|
||||
|
||||
- Alignment on the Stack
|
||||
------------------------
|
||||
|
||||
The ABI is unclear on the alignment requirement of the
|
||||
stack. What must be ensured is that, right before
|
||||
executing a 'call' instruction, the stack pointer `%rsp`
|
||||
is aligned on 16 bytes. On entry of the called
|
||||
function, the stack pointer is 8 modulo 16. Since most
|
||||
functions will have a prelude pushing `%rbp`, the frame
|
||||
pointer, upon entry of the body code of the function is
|
||||
also aligned on 16 bytes (== 0 mod 16).
|
||||
|
||||
Here is a diagram of the stack layout after a call from
|
||||
g() to f().
|
||||
|
||||
| |
|
||||
| g() locals |
|
||||
+-------------+
|
||||
^ | | \
|
||||
| | stack arg 2 | '
|
||||
| |xxxxxxxxxxxxx| | f()'s MEMORY
|
||||
growing | +-------------+ | arguments
|
||||
addresses | | stack arg 1 | ,
|
||||
| |xxxxxxxxxxxxx| /
|
||||
| +-------------+ -> 0 mod 16
|
||||
| | ret addr |
|
||||
+-------------+
|
||||
| saved %rbp |
|
||||
+-------------+ -> f()'s %rbp
|
||||
| f() locals | 0 mod 16
|
||||
| ... |
|
||||
-> %rsp
|
||||
|
||||
Legend:
|
||||
* `xxxxx` Optional padding.
|
||||
|
||||
|
||||
- Remarks
|
||||
---------
|
||||
|
||||
* A struct can be returned in registers in one of three
|
||||
ways. Either `%rax`, `%rdx` are used, or `%xmm0`,
|
||||
`%xmm1`, or finally `%rax`, `%xmm0`. The last case
|
||||
happens when a struct is returned with one half
|
||||
classified as INTEGER and the other as SSE. This
|
||||
is a consequence of the <@Returning> section above.
|
||||
|
||||
* The size of the arguments area of the stack needs to
|
||||
be computed first, then arguments are packed starting
|
||||
from the bottom of the argument area, respecting
|
||||
alignment constraints. The ABI mentions "pushing"
|
||||
arguments in right-to-left order, but I think it's a
|
||||
mistaken view because of the alignment constraints.
|
||||
|
||||
Example: If three 8 bytes MEMORY arguments are passed
|
||||
to the callee and the caller's stack pointer is 16 bytes
|
||||
algined, the layout will be like this.
|
||||
|
||||
+-------------+
|
||||
|xxxxxxxxxxxxx| padding
|
||||
| stack arg 3 |
|
||||
| stack arg 2 |
|
||||
| stack arg 1 |
|
||||
+-------------+ -> 0 mod 16
|
||||
|
||||
The padding must not be at the end of the stack area.
|
||||
A "pushing" logic would put it at the end.
|
||||
1207
doc/il.txt
Normal file
1207
doc/il.txt
Normal file
File diff suppressed because it is too large
Load Diff
98
doc/llvm.txt
Normal file
98
doc/llvm.txt
Normal file
@@ -0,0 +1,98 @@
|
||||
===========
|
||||
QBE vs LLVM
|
||||
===========
|
||||
|
||||
|
||||
Both QBE and LLVM are compiler backends using an SSA
|
||||
representation. This document will explain why LLVM
|
||||
does not make QBE a redundant project. Obviously,
|
||||
everything following is biased, because written by me.
|
||||
|
||||
- Scope
|
||||
-------
|
||||
|
||||
QBE is a much smaller scale project with different goals
|
||||
than LLVM.
|
||||
|
||||
* QBE is for amateur language designers.
|
||||
|
||||
It does not address all the problems faced when
|
||||
conceiving an industry-grade language. If you are
|
||||
toying with some language ideas, using LLVM will
|
||||
be like hauling your backpack with a truck, but
|
||||
using QBE will feel more like riding a bicycle.
|
||||
|
||||
* QBE is about the first 70%, not the last 30%.
|
||||
|
||||
It attempts to pinpoint, in the extremely vast
|
||||
compilation literature, the optimizations that get
|
||||
you 70% of the performance in 10% of the code of
|
||||
full blown compilers.
|
||||
|
||||
For example, copy propagation on SSA form is
|
||||
implemented in 160 lines of code in QBE!
|
||||
|
||||
* QBE is extremely hackable.
|
||||
|
||||
First, it is, and will remain, a small project
|
||||
(less than 8 kloc). Second, it is programmed in
|
||||
non-fancy C99 without any dependencies. Third,
|
||||
it is able to dump the IL and debug information in
|
||||
a uniform format after each pass.
|
||||
|
||||
On my Core 2 Duo machine, QBE compiles in half a
|
||||
second (without optimizations).
|
||||
|
||||
- Features
|
||||
----------
|
||||
|
||||
LLVM is definitely more packed with features, but there
|
||||
are a few things provided in QBE to consider.
|
||||
|
||||
* LLVM does NOT provide full C compatibility for you.
|
||||
|
||||
In more technical terms, any language that provides
|
||||
good C compatibility and uses LLVM as a backend
|
||||
needs to reimplement large chunks of the ABI in
|
||||
its frontend! This well known issue in the LLVM
|
||||
community causes a great deal of duplication
|
||||
and bugs.
|
||||
|
||||
Implementing a complete C ABI (with struct arguments
|
||||
and returns) is incredibly tricky, and not really
|
||||
a lot of fun. QBE provides you with IL operations
|
||||
to call in (and be called by) C with no pain.
|
||||
Moreover the ABI implementation in QBE has been
|
||||
thoroughly tested by fuzzing and manual tests.
|
||||
|
||||
* LLVM IL is more cluttered with memory operations.
|
||||
|
||||
Implementing SSA construction is hard. To save its
|
||||
users from having to implement it, LLVM provides
|
||||
stack slots. This means that one increment of
|
||||
a variable `v` will be composed of three LLVM
|
||||
instructions: one load, one add, and one store.
|
||||
|
||||
QBE provides simple non-SSA temporaries, so
|
||||
incrementing `v` is simply done with one instruction
|
||||
`%v =w add %v, 1`.
|
||||
|
||||
This could seem cosmetic, but dividing the size of
|
||||
the IL by three makes it easier for the frontend
|
||||
writers to spot bugs in the generated code.
|
||||
|
||||
* LLVM IL is more cluttered with type annotations and
|
||||
casts.
|
||||
|
||||
For the sake of advanced optimizations and
|
||||
correctness, LLVM has complex IL types. However,
|
||||
only a few types are really first class and many
|
||||
operations of source languages require casts to be
|
||||
compiled.
|
||||
|
||||
Because QBE makes a much lighter use of types, the
|
||||
IL is more readable and shorter. It can of course be
|
||||
argued back that the correctness of QBE is jeopardized,
|
||||
but remember that, in practice, the large amount
|
||||
of casts necessary in LLVM IL is undermining the
|
||||
overall effectiveness of the type system.
|
||||
15
doc/native_win.txt
Normal file
15
doc/native_win.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
There is an experimental amd64_win (native Windows ABI and calling
|
||||
convention).
|
||||
|
||||
In tree, this is currently only tested via cross-compilation from a
|
||||
Linux host, and using wine to run the tests.
|
||||
|
||||
You'll need something like:
|
||||
|
||||
sudo apt install mingw64-w64 dos2unix wine
|
||||
|
||||
and then
|
||||
|
||||
make check-amd64_win
|
||||
|
||||
should pass.
|
||||
20
doc/rv64.txt
Normal file
20
doc/rv64.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
=========
|
||||
RISC-V 64
|
||||
=========
|
||||
|
||||
- Known issues
|
||||
--------------
|
||||
|
||||
ABI with structs containing floats is not yet supported.
|
||||
|
||||
- Possible improvements
|
||||
-----------------------
|
||||
|
||||
rv64_isel() could turn compare used only with jnz into b{lt,ge}[u].
|
||||
|
||||
- Helpful links
|
||||
---------------
|
||||
|
||||
RISC-V spec: https://github.com/riscv/riscv-isa-manual/releases/latest/download/riscv-spec.pdf
|
||||
ASM manual: https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md
|
||||
ABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
|
||||
23
doc/win.txt
Normal file
23
doc/win.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
===================
|
||||
Windows Quick Start
|
||||
===================
|
||||
|
||||
Only 64-bit versions of windows are supported. To compile
|
||||
this software you will need to get a normal UNIX toolchain.
|
||||
There are several ways to get one, but I will only describe
|
||||
how I did it.
|
||||
|
||||
1. Download and install [@1 MSYS2] (the x86_64 version).
|
||||
2. In an MSYS2 terminal, run the following command.
|
||||
|
||||
pacman -S git make mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb
|
||||
|
||||
3. Restart the MSYS2 terminal.
|
||||
4. In the new terminal, clone QBE.
|
||||
|
||||
git clone git://c9x.me/qbe.git
|
||||
|
||||
5. Compile using `make`.
|
||||
|
||||
|
||||
[1] http://www.msys2.org
|
||||
Reference in New Issue
Block a user