avr-llvm / llvm

[MERGED UPSTREAM] AVR backend for the LLVM compiler library
220 stars 21 forks source link

Support atomic operations #197

Closed shepmaster closed 8 years ago

shepmaster commented 8 years ago

Continuing to chug through compiling the Rust core library, I finally hit on atomics. LLVM has these ISDs defined:

ATOMIC_LOAD
ATOMIC_STORE

ATOMIC_CMP_SWAP
ATOMIC_CMP_SWAP_WITH_SUCCESS
ATOMIC_FENCE
ATOMIC_LOAD_ADD
ATOMIC_LOAD_AND
ATOMIC_LOAD_MAX
ATOMIC_LOAD_MIN
ATOMIC_LOAD_NAND
ATOMIC_LOAD_OR
ATOMIC_LOAD_SUB
ATOMIC_LOAD_UMAX
ATOMIC_LOAD_UMIN
ATOMIC_LOAD_XOR
ATOMIC_SWAP

Conceptually, it's "easy" to implement atomic access. Since there's only one core, the only thing we have to watch out for is an interrupt occurring. That means we can have pseudocode like this:

old_sreg = load SREG
cli
// Run interesting code here
SREG = old_sreg

I'd like to take a crack at this, but without having to re-implement the automatically-generated code for "load 32-bit values" and so on. Do you know if there's a way to wrap existing LLVM generated code in some extra code?

Do you see any overall bad ideas in this?

dylanmckay commented 8 years ago

I believe you should be able to write a custom lowering hook (in AVRISelLowering.cpp call setOperationAction(..., ..., Custom). I wasn't sure if the legalizer tries to lower any illegal values after custom hooks run, but it looks like they must (see AVRISelLowering.cpp:around line 530).

In this function, we are returning nodes in the custom lowering function which are illegal (ISD::EXTRACT_ELEMENT & co). Therefore this would only work if LLVM tries to lower all illegal results from the hook.

You should be able to write a custom hook which creates a cli, one of the ISDNode copy/move nodes, and a sei node. LLVM should then lower the new ISDNode for you. It is definitely worth checking that.

Also, I'm not sure how much LLVM you've played with, but at this level in the pipeline, there is no guarantee your nodes will stay in the same order. I haven't dealt much with this, but LLVM has the concept of glue which sticks two nodes together, so they can't be separated.

Here is an example I found. This should glue the TST and the EXTRACT_ELEMENT nodes together.

SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS3,
                         DAG.getIntPtrConstant(1, DL));
Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
dylanmckay commented 8 years ago

Have picked up work on this from @shepmaster, he got pretty far but got bogged down my LLVM internals :)

Almost got this working. It looks like we can only lower stuff in these hooks to nodes that are defined in ISDNodes or AVRISDNodes. Will need to add a new node for bclr (clear bit from SREG).