【发布时间】:2015-09-01 02:16:27
【问题描述】:
如果我有一个声明 struct 的 C++ 程序,请说:
struct S {
short s;
union U {
bool b;
void *v;
};
U u;
};
我通过 LLVM C++ API 生成一些 LLVM IR 来镜像 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 );
如何确保 C++ 代码中的 sizeof(S) 与 LLVM IR 代码中的 StructType 大小相同?单个成员的偏移量相同,即u.b。
这也是我在 C++ 中分配了一个S 数组的情况:
S *s_array = new S[10];
然后我将 s_array 传递给 LLVM IR 代码,在其中我访问数组的各个元素。为了使其正常工作,sizeof(S) 在 C++ 和 LLVM IR 中必须相同,因此:
%elt = getelementptr %S* %ptr_to_start, i64 1
将正确访问s_array[1]。
当我编译并运行下面的程序时,它会输出:
sizeof(S) = 16
allocSize(S) = 10
问题是 LLVM 在 S::s 和 S::u 之间缺少 6 个字节的填充。 C++ 编译器使union 以 8 字节对齐的边界开始,而 LLVM 则没有。
我在玩DataLayout。对于我的机器 [Mac OS X 10.9.5, g++ Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)],如果我打印数据布局字符串,我会得到:
e-m:o-i64:64-f80:128-n8:16:32:64-S128
如果我将数据布局强制设置为:
e-m:o-i64:64-f80:128-n8:16:32:64-S128-a:64
其中添加的是a:64,这意味着聚合类型的对象在 64 位边界上对齐,然后我得到 same 大小。那么为什么默认数据布局不正确呢?
下面的完整工作程序
// 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;
}
【问题讨论】:
-
好的,这告诉我它有多大。在这种情况下,大小不匹配。那么如何让它们匹配呢?