The intermediate representation is very custom-tailored to ANI
programs. For example, there are no functions or function calls
anywhere -- only chunks of code that can be "dispatched" by the
runtime. We also have locking as a primitive in the IR, since proper
synchronization of data is such a big deal for the language. There are
some traditional things like expressions and assignments in there, but
since ANI's execution model flies in the face of conventional
imperative programming, I felt that doing an IR that was specially
tailored to ANI would be the easiest way to go.
>
> Out of interest, is there a reason your not using something slightly
> higher level like LLVM? I know compiling it is a slog, but you get
> optimization and portability for free and good optimization frameworks
> are man-years of effort. From the looks of genner.h it wouldn't be
> difficult to translate between the different IRs. (LLVM uses SSA, but
> it's not pure, it has Load and Store instructions that you can use and
> then you can get it to translate into pure SSA, and then binary). It
> doesn't look like it would be that difficult to hack something
> together.
We're not compiling to LLVM or such frameworks because it doesn't give
nearly the amount of control that we need to make ANI programs run
with their massive parallelism. Not only do we need native
instruction-level granularity with our thread dispatching (which
compiling to LLVM wouldn't give us), but anic does some really
unconventional things to allow its level of multithreading -- all
existing frameworks I know of don't have any support for the stuff
we're planning to do.
For example, we derive a logical partitioning schema for the entire
memory space during compilation so that object data can be statically
proven to never collide even under multithreading, and almost all
references are bound via offset rather than pointer. This means that
we need full control over how the program is linked and at which exact
offset each component is linked relative to the rest. A framework that
takes away from us this level of control would ruin our compilation
design.
It's true that full optimizations aren't easy to do from scratch, but
there's really no other way to go. anic compiles quite differently
from the other compilers out there and trades binary flexibility for
statically safe parallelism. Such an ambitious goal requires
rethinking the execution model as a whole, and all intermediate
frameworks I've seen are incompatible at the design level with what
we're doing.
Adrian
(project lead)
I just looked at nanojit and although it looks interesting, it doesn't
look like a good fit for anic. We already have our own IR that
suffices and integrates well with the language, and I think the effort
to learn nanojit and mold our IR to its exact spec, and the dangers
with relying on a third-party codebase (and being impacted by their
bugs) is too great for a native compiler like this one.
Doing it ourselves will probably be quicker than learning and
integrating into nanojit's prescribed format, and although web
browsers can afford to crash or have minor problems if incorrect code
is produced once in a million cases, having anic produce subtly
incorrect parallel code because of the tiniest problem in nanojit
would not only be unacceptable, but a nightmare to debug and a
publicity blow to the language that we can't afford to take.
That's just my personal thoughts on the matter, but I reserve the
right to be convinced of the merits of integrating with a back-end
platform that seems acceptable -- I just haven't seen one that looks
like it would work well enough (yet).
>
> Thanks, I hope I'm not bothering you,
Don't worry -- not at all.
Adrian
Since all ANI programs can be represented as trees, we treat the
entire memory space as an array representing a tree, which very
closely corresponds to the layout of the data structures represented
in source. Of course, different parts of the memory space are
represented by trees of different arity (binary, ternary, etc.) --
anic handles the proper mapping. Threads are dispatched onto known
offsets into the correct data structures (this is all calculated by
the compiler), and since this is a top-down tree, dispatching properly
guarantees no data collisions. Large parts of the tree are passed
around via entangling the tree and swapping child nodes, to avoid the
overhead of actually ever copying any tree data.
It's even more complicated than that when a child needs more memory
(it recursively looks to steal memory from siblings).
I plan on writing a document about how all of this works in anic soon
(since I'm working on the partitioner/allocator right now).
Cheers,
Adrian
On 20 Aug., 00:25, Ultimus Freelance <ulti...@gmail.com> wrote:
lightning maybe. Just simple cpp macros, no lib in between.
My self-written perl5 JIT is also super simple, but it starts to get
bigger
and bigger the more CPU's and different data structures you have to
support.
And asmdump is just the first step.
You probably also need a 2nd linking step, and dump the coff/elf
header.
JIT'ting would be much easier.
Do you need PIC, label fixups?
Don't you need to link some runtime library?
Reini Urban