~jojo/Carth

ref: 0088875fe0b08bd1ddffe4c39c378884ae578550 Carth/src/Codegen.hs -rw-r--r-- 28.6 KiB
Fix some minor warnings
Handle unit and other zero-sized types in alignmentof & sizeof
Refactor Codegen. Separate module for ABI-related stuff

Also had to separate a module for the Gen-monad, as Haskell can't have
cyclical imports.
Allow integer and boolean literals in patterns

Could exploit the existing Match.PCon constructor to represent not
just datatypes, but these other enumerables as well. Didn't have to
make many additions/modifications at all -- quite nice!
Fix incorrect from-label used in phi-node of decision switch
Fix bools not truncated from i8 to i1 for condbr
Improve gen of str lits

Instead of just defining a global var for the raw byte array and
create a Str struct at every "call"site, define 2 global vars -- one
for the raw bytes, and one for the Str structs defined in terms of it.
Scale datatype tag size by n of variants. 1 variant => no tag

Types with only 1 variant have no tag. Types with <=2^n variants have
n-bit tag.
Fix struct member padding set to alignment when remainder = 0
Get rid of extractvalueFromNamed, use lookupDataType in extractvalue
Fix wrong size of bools. Was i1, C ABI says i8.

Not sure exactly what happened before, but in practice, bools
often/always had the opposite value.
Impl sizeof ourselves instead of relying on messy getTypeAllocSize

The problem with the earlier approach was that we had to pull in the
IO-related EncodeAST monad in our Gen stack, and the implementation to
call getTypeAllocSize was kind of messy, as llvm-hs didn't expose it
other than in an Internal module.

EncodeAST in Gen (and Gen') prevented use of `mfix`, which I needed.

Also note that we had to change Map.Strict to Map, as, of course, we
can't have recursive bindings in the strict Map.
Move some Pretty instances from module Codegen to Misc
Pass `byval` when passing by reference

So instead of

LLVM:
  declare @foo(%Foo* %x)

Rust:
  extern fn foo(x: &Foo) { ... }

we do

LLVM:
  declare @foo(%Foo* byval %x)

Rust:
  extern fn foo(x: Foo) { ... }

It just seemed like a nice thing to do, especially now that
we (mostly?) conform to C calling convention / System V ABI.
Make passByRef more exhaustive and correct

I think it's pretty close to System V ABI spec now.

Sadly, access to env of datatypes is needed to do lookup for
NamedTypeReference, and this had something of a chain reaction. Not
only passByRef became Gen', but also toLlvmType! This had some effect
throughout the module.
Don't greedily mark every call as tail -- causes segfaults & stuff!

For now, don't mark any call as tail. Gotta learn how it really works
first. Seems like only calls that are actually in tail-position should
be marked as tail, or mayhem ensues.
Properly mark out-params as sret in function defs
Rename main to start & fix start-related stuff

First, the reason for the rename. Having both an "outer" and an
"inner" main named main (with LLVM kindly generating some suffix to
separate them) was just not very pretty looking. Another problem was
that, while not possible before, e.g. recursing in main would not
work, as the main found would not be the inner main, but the outer
main. Renaming the inner (user defined) main to start alleviates this
issue.

Another approach we could've taken is to rename the outer main, and
tell the linker (via GCC/Clang) that we have another entrypoint than
main. I started working on this, but just appending a "-e outer_main"
flag was no good. The problem was that the entrypoint changed was not
main to outer_main, but rather _start to outer_main. This was no good,
as _start usually sets up some things before calling main, and the
result was segfaults.

Also, now start (main) is treated more like any other global def, and
you can call main from other functions and recurse etc. I had to fix
how main is typechecked a bit for this to work correctly.
Perform beta-reduction in codegen

Lessens amount of generated code by quite a bit, especially for
datatype construction.
Base name mangling on instantiation types instead of type

E.g. "id<Int>" instead of "Id<Fun<Int, Int>>"
Next