alignment issue, getting corrupt double values

I'm having an issue where a certain set of types and insert/extractvalue
are producing the incorrect values. It appears as though extractvalue
getting my sub-structure is not getting the correct data.

I have these types:

%outer = type { i32, %inner, i1 }
%inner = type { double, i32 }

The trouble is that when I have a value of type %outer then proceed to
extract the components of the contained %inner structure I get corrupt
values. If I don't have the "i1" type in there everything works fine,
leading me to think it is something to do with alignment. I do the
extraction with code like this:

  %o = call %outer @eval_expr()
  %s = extractvalue %outer %o, 1
  %s1 = extractvalue %inner %s, 0

The %s1 value is not correct (not what was inserted). I think extraction
is the problem and not insertion: in another version I store the value
to a global variable and dump the bytes of the structure, which can then
be properly extracted in C++ code. The value is produced with this code
(in a separate function):

  %s0 = insertvalue %inner undef, double 1.500000e+00, 0
  %s1 = insertvalue %inner %s0, i32 2, 1
  %s2 = insertvalue %outer undef, i32 1, 0
  %s3 = insertvalue %outer %s2, %inner %s1, 1

I've attached the full sample code which shows the error and where it

types.ll (1.27 KB)

I also saw this issue before. Llvm seems have trouble returning general struct values from functions. One easy workaround is to use packed struct type.

Hope this helps.


I can confirm that if I generate the value directly (not via a return)
then the expected values are extracted from the structure. So it is
perhaps a return value issue.

I think most backends treat struct return by value as returning multiple values in registers; for instance, {i32, i64} returns into {EAX, RDX} on x86-64. Since most architectures don’t specify any more than two return registers and you can’t really “spill” a return value, weird poorly-tested things probably happen if you try to return a struct with more elements than the backend has return registers for. You could try returning larger structs indirectly using an sret pointer like Clang does.

I do pass the return as the first parameter pointer now. I didn't know
about sret, I guess I should mark it is as such (does it help
optimization then?)

I also think it is kind of dangerous that LLVM silently accepts returns
of larger structures and then produces invalid code. Note that it does
actually pass by pointer if the backend can't return it directly, just
in certain cases it fails to produce correct code.

You should definitely file a bug. Did you build LLVM with assertions enabled? If not, try rebuilding with assertions, and you might get an indication of what’s breaking instead of silent bad behavior.


Yes, assertions are enabled: I get them all the time, just not here. :wink:

I'll file a defect.