title: Accessing struct members and arrays of structs from LLVM IR
body: <p>If I have a C++ program that declares a <code>struct</code>, say:</p>
  
  <pre><code>struct S {
      short s;
      union U {
          bool b;
          void *v;
      };
      U u;
  };
  </code></pre>
  
  <p>and I generate some LLVM IR via the LLVM C++ API to mirror the C++ declaration:</p>
  
  <pre><code>vector&lt;Type*&gt; members;
  members.push_back( IntegerType::get( ctx, sizeof( short ) * 8 ) );
  // since LLVM doesn't support unions, just use an ArrayType that's the same size
  members.push_back( ArrayType::get( IntegerType::get( ctx, 8 ), sizeof( S::U ) ) );
  
  StructType *const llvm_S = StructType::create( ctx, "S" );
  llvm_S-&gt;setBody( members );
  </code></pre>
  
  <p>How can I ensure that <code>sizeof(S)</code> in the C++ code is the same size as the <code>StructType</code> in LLVM IR code?  Same for the offsets of the individual members, i.e., <code>u.b</code>.</p>
  
  <p>It's also the case that I have an array of <code>S</code> allocated in C++:</p>
  
  <pre><code>S *s_array = new S[10];
  </code></pre>
  
  <p>and I pass <code>s_array</code> to LLVM IR code in which I access individual elements of the array.  In order for this to work, <code>sizeof(S)</code> has to be the same in both C++ and LLVM IR so this:</p>
  
  <pre><code>%elt = getelementptr %S* %ptr_to_start, i64 1
  </code></pre>
  
  <p>will access <code>s_array[1]</code> properly.</p>
  
  <p>When I compile and run the program below, it outputs:</p>
  
  <pre><code>sizeof(S) = 16
  allocSize(S) = 10
  </code></pre>
  
  <p>The problem is that LLVM is missing 6 bytes of padding between <code>S::s</code> and <code>S::u</code>.  The C++ compiler makes the <code>union</code> start on a 8-byte-aligned boundary whereas LLVM does not.</p>
  
  <p>I was playing around with <code>DataLayout</code>. For my machine [Mac OS X 10.9.5, g++ Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)], if I print the data layout string, I get:</p>
  
  <pre><code>e-m:o-i64:64-f80:128-n8:16:32:64-S128
  </code></pre>
  
  <p>If I force-set the data layout to:</p>
  
  <pre><code>e-m:o-i64:64-f80:128-n8:16:32:64-S128-a:64
  </code></pre>
  
  <p>where the addition is of <code>a:64</code> which means that an object of aggregate type aligns on a 64-bit boundary, then I get the <em>same</em> size.  So why isn't the default data layout correct?</p>
  
  <hr>
  
  <h1>Complete working program below</h1>
  
  <pre><code>// LLVM
  #include &lt;llvm/ExecutionEngine/ExecutionEngine.h&gt;
  #include &lt;llvm/ExecutionEngine/MCJIT.h&gt;
  #include &lt;llvm/IR/DerivedTypes.h&gt;
  #include &lt;llvm/IR/LLVMContext.h&gt;
  #include &lt;llvm/IR/Module.h&gt;
  #include &lt;llvm/IR/Type.h&gt;
  #include &lt;llvm/Support/TargetSelect.h&gt;
  
  // standard
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;string&gt;
  
  using namespace std;
  using namespace llvm;
  
  struct S {
      short s;
      union U {
          bool b;
          void *v;
      };
      U u;
  };
  
  ExecutionEngine* createEngine( Module *module ) {
      InitializeNativeTarget();
      InitializeNativeTargetAsmPrinter();
  
      unique_ptr&lt;Module&gt; u( module );
      EngineBuilder eb( move( u ) );
      string errStr;
      eb.setErrorStr( &amp;errStr );
      eb.setEngineKind( EngineKind::JIT );
      ExecutionEngine *const exec = eb.create();
      if ( !exec ) {
          cerr &lt;&lt; "Could not create ExecutionEngine: " &lt;&lt; errStr &lt;&lt; endl;
          exit( 1 );
      }
      return exec;
  }
  
  int main() {
      LLVMContext ctx;
  
      vector&lt;Type*&gt; members;
      members.push_back( IntegerType::get( ctx, sizeof( short ) * 8 ) );
      members.push_back( ArrayType::get( IntegerType::get( ctx, 8 ), sizeof( S::U ) ) );
  
      StructType *const llvm_S = StructType::create( ctx, "S" );
      llvm_S-&gt;setBody( members );
  
      Module *const module = new Module( "size_test", ctx );
      ExecutionEngine *const exec = createEngine( module );
      DataLayout const *const layout = exec-&gt;getDataLayout();
      module-&gt;setDataLayout( layout );
  
      cout &lt;&lt; "sizeof(S) = " &lt;&lt; sizeof( S ) &lt;&lt; endl;
      cout &lt;&lt; "allocSize(S) = " &lt;&lt; layout-&gt;getTypeAllocSize( llvm_S ) &lt;&lt; endl;
  
      delete exec;
      return 0;
  }
  </code></pre>