Se ho un programma C++ che dichiara un struct
, dire:Accesso membri struct e array di struct da LLVM IR
struct S {
short s;
union U {
bool b;
void *v;
};
U u;
};
e generare qualche LLVM IR tramite la LLVM C++ API per rispecchiare dichiarazione ++ C:
vector<Type*> 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->setBody(members);
come posso garantire che sizeof(S)
nel codice C++ è la stessa dimensione della StructType
nel codice LLVM IR? Lo stesso vale per gli offset dei singoli membri, ovvero .
È anche vero che ho un array di S
allocato in C++:
S *s_array = new S[10];
e passo s_array
di codice LLVM IR in cui accede singoli elementi della matrice. Affinché questo funzioni, sizeof(S)
deve essere la stessa sia in C++ e LLVM IR in modo che questo:
%elt = getelementptr %S* %ptr_to_start, i64 1
accederanno s_array[1]
correttamente.
Quando compilare ed eseguire il seguente programma, emette:
sizeof(S) = 16
allocSize(S) = 10
Il problema è che manca LLVM 6 byte di riempimento tra S::s
e S::u
. Il compilatore C++ fa partire union
su un limite allineato a 8 byte mentre LLVM no.
Stavo giocando con DataLayout
. Per la mia macchina [Mac OS X 10.9.5, Apple ha g ++ LLVM versione 6.0 (clang-600.0.57) (sulla base di LLVM 3.5svn)], se stampare la stringa layout dei dati, ottengo:
e-m:o-i64:64-f80:128-n8:16:32:64-S128
Se forzo-impostare il layout dei dati a:
e-m:o-i64:64-f80:128-n8:16:32:64-S128-a:64
cui l'aggiunta è di a:64
che significa che un oggetto di tipo aggregato allinea su un limite di 64 bit, allora ottengo la stessa dimensione. Quindi, perché il layout dei dati predefinito non è corretto?
programma di lavoro completo sotto
// LLVM
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/Support/TargetSelect.h>
// standard
#include <iostream>
#include <memory>
#include <string>
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<Module> u(module);
EngineBuilder eb(move(u));
string errStr;
eb.setErrorStr(&errStr);
eb.setEngineKind(EngineKind::JIT);
ExecutionEngine *const exec = eb.create();
if (!exec) {
cerr << "Could not create ExecutionEngine: " << errStr << endl;
exit(1);
}
return exec;
}
int main() {
LLVMContext ctx;
vector<Type*> 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->setBody(members);
Module *const module = new Module("size_test", ctx);
ExecutionEngine *const exec = createEngine(module);
DataLayout const *const layout = exec->getDataLayout();
module->setDataLayout(layout);
cout << "sizeof(S) = " << sizeof(S) << endl;
cout << "allocSize(S) = " << layout->getTypeAllocSize(llvm_S) << endl;
delete exec;
return 0;
}
Che dire di [getTypeAllocSize()] (http://llvm.org/docs/doxygen/html/classllvm_1_1DataLayout.html#a1d6fcc02e91ba24510aba42660c90e29)? –
OK, questo mi dice quanto è grande. In questo caso, le dimensioni non corrispondono a _non_. Quindi, come faccio a farli corrispondere? –