ykjit / yk

yk packages
https://ykjit.github.io/yk/
Other
31 stars 7 forks source link

codegen: what are our alignment requirements? #995

Open vext01 opened 7 months ago

vext01 commented 7 months ago

When we generate JITted code, the JIT frame has it's own stack. We need to start thinking about what the alignment requirements are of storing things to that stack.

I think there are two ways an object can hit the JIT stack:

For the former I think that the only requirements are those of the underlying CPU architecture. In other words, no object that is word-sized [0] or less should straddle a word boundary. Why? Because some CPUs will emit slower code to handle a straddle, some CPUs will actually fault (sparc64/arm I think).

For explicit stack allocations the AOT binary may have been code-genned with certain alignment requirements baked-in, and pointers may be shared across AOT and JIT code (via the shadow stack). For those cases I think we have no choice but to align as LLVM aligned. This would entail carrying the alignment value from the LLVM's alloca into our own IR instruction and when we perform the allocation, ensure (like the dude) that we abide.

[One spanner in the works is that LLVM loads and stores can take an alignment parameter too, but it's rare. For that I suggest we start by assert()ing it can't happen during lowering to our IR]

Does this all sound legit?

I don't actually plan to get alignment 100% correct right now, since we are in sprint mode, but I want to at least have said that I have thought about it :)

Right now we have no explicit stack allocations, and spills are aligned to the size of their allocation. The latter is not strictly correct and often wasteful, but will probably work for now at least on x86_64. A less dodgy scheme for spills is to align to the highest alignment value of the object's constituent "fields" (or sub-objects, whatever you want to call them).

ltratt commented 2 months ago

I am increasingly worried that we haven't thought about alignment at all, anywhere in any part of yk, and we're gradually embedding more assumptions about alignment that are not just incorrect but also unnoticed and hard to track down later.

Rather than start at the end (the codegen), what would be better is to start at the start: ykllvm and yksmp. Can we get alignment data into those parts? If we can, we'll relatively naturally be able to thread it throughout the system.

@vext01 Do you have any sense of whether/how ykllvm and yksmp give us alignment information?

vext01 commented 2 months ago

As discussed offline, our IR works under the assumption that all objects are alignment-safe and the serialiser will reject any load/store that could straddle an alignment boundary.

However we'd like to make alignment more explicit and encode the alignment into our IRs and let the code generator decide whether it wants to handle (or not) misaligned loads/stores.

(Note to self: also encode alignment into allocas, so the codegen can allocate appropriately for (e.g.) implicit alignment requirements external to IRs)

ltratt commented 2 months ago

Note that alignment must be taken account of in not just the codegenm and the stack: optimisations (etc) also need to know about it.