Global variable initializer type does not match global variable type

Hello.

I've managed to create a bitcode file (attached; also available at [1]) which produces
a series of identical errors when verified:

Global variable initializer type does not match global variable type!
%i.NilClass* @nil

When ran through llvm-dis and recompiled, through, it verifies successfully. If I
disassemble it one more time, the result is identical to the first disassembly. The
recompiled bitcode file is slightly smaller.

I suspect that the problem is with aggregate type uniqueing. I use ruby-llvm bindings,
LLVM 3.2 to generate the file; the following code demonstrates what I deem the incorrect
behavior:

    # llvm_ty is an LLVM struct type with 2 elements.
    a, b = llvm_ty.element_types
    # Here, I decompose the type and verify that the types of elements
    # match my expectations:
    p a == @types[Monotype.of(VI::Class)] # true
    p b == emit_class_body_type(klass) # true

    # I attempt to reconstruct the type using the elements
    # and check if it's still the same.
    p llvm_ty == LLVM::Type.struct([
         @types[Monotype.of(VI::Class)],
         emit_class_body_type(klass)
      ], false) # false. Why?

Ruby-LLVM bindings compare underlying LLVM pointers when the Type objects are compared
with ==.

The problem manifests itself when the following code contains the initializer assignment:

     datum = @llvm.globals.add llvm_ty, name
     datum.initializer = LLVM::ConstantStruct.const([
         emit_object(klass, klass_name).bitcast_to(
             @types[Monotype.of(VI::Class)]),
         LLVM::Constant.null(emit_class_body_type(klass))
     ])

LLVM::ConstantStruct.const eventually calls the LLVMConstStruct method with the
appropriate arguments; LLVM::Constant.null corresponds to LLVMConstNull.

Any hints are greatly appreciated.

test.bc (752 Bytes)

Peter Zotov писал 09.01.2013 19:59:

Hello.

I've managed to create a bitcode file (attached; also available at
[1]) which produces
a series of identical errors when verified:

> Global variable initializer type does not match global variable type!
> %i.NilClass* @nil

When ran through llvm-dis and recompiled, through, it verifies
successfully. If I
disassemble it one more time, the result is identical to the first
disassembly. The
recompiled bitcode file is slightly smaller.

I suspect that the problem is with aggregate type uniqueing. I use
ruby-llvm bindings,
LLVM 3.2 to generate the file; the following code demonstrates what I
deem the incorrect
behavior:

(snip)

I've ran the good and bad bitcode files for a more compact example (attached)
through llvm-bcanalyzer and diff:

--- bad.xml 2013-01-09 22:57:58.691131492 +0400
+++ good.xml 2013-01-09 22:58:04.153133734 +0400
  ... irrelevant ...
      <STRUCT_NAME abbrevid=7 op0=105 op1=46 op2=78 op3=105 op4=108 op5=67 op6=108 op7=97 op8=115 op9=115/>
      <STRUCT_NAMED abbrevid=8 op0=0 op1=0 op2=6/>
      <POINTER abbrevid=4 op0=7 op1=0/>
- <STRUCT_ANON abbrevid=6 op0=0 op1=0 op2=6/>
    </TYPE_BLOCK_ID>
    <GLOBALVAR abbrevid=4 op0=8 op1=0 op2=2 op3=0 op4=0 op5=0/>
    <CONSTANTS_BLOCK NumWords=5 BlockCodeSize=4>
- <SETTYPE abbrevid=4 op0=9/>
+ <SETTYPE abbrevid=4 op0=7/>
      <NULL/>
    </CONSTANTS_BLOCK>
  ... all the same ...

So it pretty much seems that instantiating a constant struct with a type which
is structurally identical to an existing named struct type creates a new anonymous struct
which is for some reason not deemed to be identical to the named one.

Any ideas why?

bad.bc (340 Bytes)

good.bc (336 Bytes)

Peter Zotov писал 09.01.2013 23:11:

Peter Zotov писал 09.01.2013 19:59:

Hello.

I've managed to create a bitcode file (attached; also available at
[1]) which produces
a series of identical errors when verified:

> Global variable initializer type does not match global variable type!
> %i.NilClass* @nil

When ran through llvm-dis and recompiled, through, it verifies
successfully. If I
disassemble it one more time, the result is identical to the first
disassembly. The
recompiled bitcode file is slightly smaller.

I suspect that the problem is with aggregate type uniqueing. I use
ruby-llvm bindings,
LLVM 3.2 to generate the file; the following code demonstrates what I
deem the incorrect
behavior:

(snip)

I've ran the good and bad bitcode files for a more compact example (attached)
through llvm-bcanalyzer and diff:

--- bad.xml 2013-01-09 22:57:58.691131492 +0400
+++ good.xml 2013-01-09 22:58:04.153133734 +0400
... irrelevant ...
     <STRUCT_NAME abbrevid=7 op0=105 op1=46 op2=78 op3=105 op4=108
op5=67 op6=108 op7=97 op8=115 op9=115/>
     <STRUCT_NAMED abbrevid=8 op0=0 op1=0 op2=6/>
     <POINTER abbrevid=4 op0=7 op1=0/>
- <STRUCT_ANON abbrevid=6 op0=0 op1=0 op2=6/>
   </TYPE_BLOCK_ID>
   <GLOBALVAR abbrevid=4 op0=8 op1=0 op2=2 op3=0 op4=0 op5=0/>
   <CONSTANTS_BLOCK NumWords=5 BlockCodeSize=4>
- <SETTYPE abbrevid=4 op0=9/>
+ <SETTYPE abbrevid=4 op0=7/>
     <NULL/>
   </CONSTANTS_BLOCK>
... all the same ...

So it pretty much seems that instantiating a constant struct with a type which
is structurally identical to an existing named struct type creates a
new anonymous struct
which is for some reason not deemed to be identical to the named one.

Any ideas why?

Solved this. If someone is interested, http://pastie.org/5656833 should be self-explanatory.
This is quite a non-obvious behavior, especially when LLVM is wrapped in bindings.