[cfe-dev] Clang and packing/unmacking struts uses as arguments/return values

David Mirabito david.mirabito at gmail.com
Thu Feb 13 17:12:17 PST 2014


Hello list,

I am trying to interface some JIT'd code I generate (via the llvm-c API)
with a module I've compiled alongside the jit, which contains certain
runtime functions.

I generate runtime.bc with the same clang invocation as the rest of the
application, except using -O0 and -emit-llvm. This is loaded at runtime and
my I insert new functions into that module as I need them. For runtime
functions that just use scalars, this works well.

I'm having problems with structs, and my clang-generated module seems to
define the struct as I'd expect, but functions that either take this struct
as an arg, or return it seem to fall apart.

I have:
  typedef struct {
    uint32_t value;
    uint32_t carryOut;
    uint32_t overflow;
  } CarryOp_Result;

This was once upon a time defined at the top of the module as { i32, i32,
i32 } as expected, but I've since changed things and now thats not emitted
in my runtime.bc anymore. I guess it's not used/needed.

I also have a function in this runtime.bc module:
  CarryOp_Result addWithCarry( a, b, carryIn);

Which is defined to return { i64, i32 }. I suspect this is because clang
knows the ABI of my host PC and bakes the calling convention into the IR
(x86_64-apple-darwin11.4.2). I know enough not to expect to be able to use
the same .bc on different arches for reasons such as this, at least :)

Because two struct fields are merged, it's not trivial to get the one I'm
interested in. Even if I do emit the required masks and shifts, what if it
all changes tomorrow when I want this to work after recompiling everything
for say, 32b Linux, or ARM with a different calling convention?

So I had the bright idea to add some accessors to the runtime, which I
could feed with the LLVMValue I have, regardless of the actual
representation. This way for a given compile of the runtime everything
would be self-consistent and "just work", neatly sidestepping struct ABI
packing issues ...
    uint32_t carryOpValue(CarryOpResult r) { return r.value; }

... or so I thought, anyway. This actually generates:
  define i32 @CarryOpValue(i64 %v.coerce0, i32 %v.coerce1) #0 { ... }
which takes two arguments, where I expected a single { i64, i32 } argument.

So now, even for my jit to emit
    LLVMValueRef sum = CarryOpValue(addWithCarry(a, b, c));

The call site needs to know to unpack the single LLVMValue (representing
the struct) into two arguments, in order to pass them to the accessor. So
still I need to poke around in the innards of the struct, still knowing how
the compiler felt like packing the struct on a given platform.

Is there a way I can have Clang simply use {i32, i32, i32} for that struct
in a way that GEP/ExtractValue with indices 0, 1, 2 reliably works as
expected?

Alternatively, could I cast between {i64, i32} and {i32, i32, i32} in a
reliable way, would that be safe?
Or any other solution?

If worse comes to worst, I *can* end up writing addWithCarry either by hand
or with the builder API to do exactly what I want, but that's annoying
enough to be the reason I went down the "runtime-module full of helpers"
path in the first place and have clang do the annoying work for me!

Thanks in advance,
DavidM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140214/0d8f49ce/attachment.html>


More information about the cfe-dev mailing list