Jeśli mam program C++, który deklaruje struct
, powiedzieć:Dostęp do członków struct i tablice kodowanym z LLVM IR
struct S {
short s;
union U {
bool b;
void *v;
};
U u;
};
i wygenerować jakiś LLVM IR za pomocą LLVM C++ API do lustrzanych deklarację 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);
Skąd mogę mieć pewność, że sizeof(S)
w kodzie C++ jest taki sam rozmiar jak StructType
w kodzie LLVM IR? To samo dotyczy przesunięć poszczególnych elementów, tj. u.b
.
Jest to również przypadek, że ma szereg S
przydzielonych C++
S *s_array = new S[10];
i przechodzą s_array
kodu LLVM IR, w którym dostęp do poszczególnych elementów tablicy. Aby to działało, sizeof(S)
musi być taka sama zarówno w C++ i LLVM IR więc to:
%elt = getelementptr %S* %ptr_to_start, i64 1
uzyska dostęp s_array[1]
prawidłowo.
Kiedy skompilować i uruchomić program poniżej, Wyjścia:
sizeof(S) = 16
allocSize(S) = 10
Problemem jest to, że brakuje LLVM 6 bajtów wypełnienia między S::s
i S::u
. Kompilator C++ sprawia, że union
zaczyna się od granicy wyrównanej do 8 bajtów, podczas gdy LLVM nie.
Bawiłem się z DataLayout
. Na moim komputerze [Mac OS X 10.9.5, g ++ Jabłko LLVM w wersji 6.0 (dzyń-600.0.57) (oparty na LLVM 3.5svn)], jeśli mogę wydrukować ciąg układ danych, uzyskać:
e-m:o-i64:64-f80:128-n8:16:32:64-S128
Jeśli wymusić ustawiony układ danych do:
e-m:o-i64:64-f80:128-n8:16:32:64-S128-a:64
gdzie dodatek jest a:64
co oznacza, że obiekt typu kruszywa wyrównany na granicy 64-bitowej, a następnie pojawia się samą rozmiar. Dlaczego więc domyślny układ danych nie jest poprawny?
Kompletny program roboczy poniżej
// 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;
}
Co z [getTypeAllocSize()] (http://llvm.org/docs/doxygen/html/classllvm_1_1DataLayout.html#a1d6fcc02e91ba24510aba42660c90e29)? –
OK, to mówi mi, jak duży jest. W takim przypadku rozmiary _nie_ pasują. Jak mogę je dopasować? –