~jojo/Carth

ref: 2219ea535f4a0fd0afd9000ba5c6918c6b276210 Carth/src/Extern.hs -rw-r--r-- 5.0 KiB
Add skeleton module Optimize between Monomorphize & Compile
Make (i8*) the generic ptr type instead of ({}*)

I just think it will play nicer with LLVM. Everything gets messy when
zero-sized types are involved.
Don't capture global (function) variables in closures, wasteful

However, due to a bug somewhere, Boehm GC doesn't seem to register
global variables as roots, at least when running in JIT. This is a
problem, because non-function vars may require heap allocation during
init, and those heap pointers will not be reachable from the roots if
the static global variable location is not marked as root.
Implement binops as "builtin virtual functions"

This way, they only need to be declared for the typechecker and
handled in the codegen, but they don't need to exist as variants in
the AST for the intermediate compilation steps. Some existing variants
could maybe be handled this way too, like transmute.
Change formatting: 90 cols, IndentPolicyFree, etc. Add brittany.yaml

Most people have pretty wide and high res screens at this point. I
can't fit two windows with 100 line length next to eachother with my
font size, but 90 works and most people have smaller font size than me
I think.

Also, change brittanys indentation policy to Free. This almost always
looks better. I just had to disable formatting of imports -- I don't
want to align those, but IndentationPolicyFree insists.

Finally, actually add a project-local brittany config file, so that
anyone (or me in the future / on another computer) can use the same
formatting rules.
Add global variables

Previously, top-level definitions could only be functions. Now,
non-function variables are initialized with `carth_init` in `main`.

Could be interesting to initialize them at compile time instead, using
some kind of compile-time evaluation mechanism, probably using the JIT.
Use Inferred.builtinExterns to expose builtins both to user and Gen

Gen.builtinsHidden - Builtins only usable with Gen.callBuiltin

Inferred.builtinExterns - Available both to the user and
Gen.callBuiltin. Passed through the stages to end up as
Gen.withBuiltins.builtinExterns.
Return void instead of {}. Allows for more tail call optimization

If a function returns {} (i.e. Unit), then

    %x = call {} @foo()
    ret {} %x

is automatically converted by LLVM to something like

   call {} @foo()
   ret {} zeroinitializer

This is a problem, as tail calls are only optimized if ["ret
immediately follows call and ret uses value of call or is
void"](http://llvm.org/docs/CodeGenerator.html#tail-call-optimization). Since
the value (%x) is no longer used after the conversion (zeroinitializer
instead), and {} is not void, the optimization doesn't happen. I
observe this in practice.

So to fix this issue, we either have to get LLVM to not do that stupid
conversion, or return void instead. One way to get LLVM not to do the
inversion would be to represent Unit as e.g. an i8. Then LLVM will be
forced to use %x, as it doesn't know that it's always zero. This
method would likely work, as I have observed that tail calls are
indeed optimized for functions returning integers. However, this would
make units sized, which seems like it would cause trouble or at least
prevent some optimizations.

So I went with the alternative: return void when the type is Unit or
any other single-variant enum. Luckily, not much code needed to be
changed (essentially, use genRetType instead of genType where
appropriate), but the solution is not differently typed, so I'll have
to be a bit careful.
Revert "Use i8* for generic pointer instead of {}*"

This reverts commit 426a43633839ccaefee948f4278cb33dc77920f8.
Use i8* for generic pointer instead of {}*

I haven't actually had any problems due to {}* yet, but LLVM seems to
encourage not pointing to unsized types, so we'll do that.
Fix externs having fastcc & return differently when in tail pos

This is part of improving guarantees of tail call optimization. Still
a little bit to go.

I think the only remaining thing is to change {} to void, as it seems
LLVM doesn't like tail calls otherwise. If we return an int, it's all
good, but if we return unit, we get stack overflow.
Instead of ccc everywhere, generate fastcc wrappers around externs

Pros:

- Extern declarations can now be written in a carth
  interpretation, with currying and all, because the generated wrapper
  will be curried. No need to manually write curried wrappers!

- Fastcc is faster and can optimize tail calls *way* better than
  ccc. We now have almost guaranteed tail call elimination in most
  possible cases.

Cons:

- Carth functions can now not be called from the outside, as they
  don't conform to the C abi. Maybe we'll add a feature to generate
  "reverse-wrappers" for marked carth functions.