由于原始答案是“预编辑”问题的正确答案,所以我正在为新问题写一个全新的答案(我猜结构实际上并不相同)。
问题不在于
DataLayout
因此[但您需要DataLayout来解决问题,因此在开始制作LLVM-IR之前需要更新代码以创建模块]
union
在
struct
具有较少的对齐限制:
struct S {
short s; // Alignment = 2
union U {
bool b; // Alignment = 1
void *v; // Alignment = 4 or 8
};
U u; // = Alignment = 4 or 8
};
现在在LLVM代码生成器中:
members.push_back( IntegerType::get( ctx, sizeof( short ) * 8 ) );
members.push_back( ArrayType::get( IntegerType::get( ctx, 8 ), sizeof( S::U ) ) );
结构中的第二个元素是
char dummy[sizeof(S::U)]
,其对齐要求为1。因此,当然,LLVM将对齐
结构
与具有更严格对齐标准的C++编译器不同。
在这种特殊情况下,使用
i8 *
(又名
void *
)代替数组
i8
很明显
bitcast
在访问的值时,根据需要转换为其他类型
b
]
要以完全通用的方式解决此问题,需要生成
结构
由在
协会
,然后用足够的
char
元素以弥补最大的尺寸。
我现在要吃点东西了,但我会用一些代码来解决它,但它比我最初想象的要复杂一些。
这是
main
上面的posted修改为使用指针而不是
烧焦
阵列:
int main() {
LLVMContext ctx;
vector<Type*> members;
members.push_back( IntegerType::get( ctx, sizeof( short ) * 8 ) );
members.push_back( PointerType::getUnqual( IntegerType::get( ctx, 8 ) ) );
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;
}
还有一些微小的变化来掩盖这一事实
setDataLayout
在您的LLVM版本和我使用的LLVM之间发生了变化。
最后是允许使用任何类型的通用版本:
Type* MakeUnionType( Module* module, LLVMContext& ctx, vector<Type*> um )
{
const DataLayout dl( module );
size_t maxSize = 0;
size_t maxAlign = 0;
Type* maxAlignTy = 0;
for( auto m : um )
{
size_t sz = dl.getTypeAllocSize( m );
size_t al = dl.getPrefTypeAlignment( m );
if( sz > maxSize )
maxSize = sz;
if( al > maxAlign)
{
maxAlign = al;
maxAlignTy = m;
}
}
vector<Type*> sv = { maxAlignTy };
size_t mas = dl.getTypeAllocSize( maxAlignTy );
if( mas < maxSize )
{
size_t n = maxSize - mas;
sv.push_back(ArrayType::get( IntegerType::get( ctx, 8 ), n ) );
}
StructType* u = StructType::create( ctx, "U" );
u->setBody( sv );
return u;
}
int main() {
LLVMContext ctx;
Module *const module = new Module( "size_test", ctx );
ExecutionEngine *const exec = createEngine( module );
DataLayout const *const layout = exec->getDataLayout();
module->setDataLayout( *layout );
vector<Type*> members;
members.push_back( IntegerType::get( ctx, sizeof( short ) * 8 ) );
vector<Type*> unionMembers = { PointerType::getUnqual( IntegerType::get( ctx, 8 ) ),
IntegerType::get( ctx, 1 ) };
members.push_back( MakeUnionType( module, ctx, unionMembers ) );
StructType *const llvm_S = StructType::create( ctx, "S" );
llvm_S->setBody( members );
cout << "sizeof(S) = " << sizeof( S ) << endl;
cout << "allocSize(S) = " << layout->getTypeAllocSize( llvm_S ) << endl;
delete exec;
return 0;
}
请注意,在这两种情况下,您都需要
比特铸造
转换地址的操作
b
-在第二种情况下,还需要位转换
结构
进入
无效*
,但假设您实际上想要泛型
协会
支持,无论如何你都必须这样做。
生成
协会
类型可以在这里找到,这是我的Pascal编译器的
variant
[这是Pascal制作
协会
]:
https://github.com/Leporacanthicus/lacsap/blob/master/types.cpp#L525
以及代码生成,包括比特流:
https://github.com/Leporacanthicus/lacsap/blob/master/expr.cpp#L520