1. LLVM在x86和x64下都和Microsft C++ ABI的吻合程度不够。目前已知在以下情况下会出错:
以下情况我没有完整测试过:
-
返回值为单个浮点
-
返回值为向量(_m128 / <4 x float>)
-
参数为向量(_m128 / <4xfloat>)
所以建议大家统一将是结构体的返回值和参数以引用/指针的形式传递。
对于大小为4个或者8个字节的结构体如果希望按值传递,那么需要在LLVM函数的签名上使用i32/i64作为参数类型,并使用bit cast在函数体内强制转换成结构体。
2. LLVM提供了很多的Intrinsics,例如SSE指令集。它在Module上提供了一个getOrCreateTargetIntrinsic,但实际上这个函数是坑爹的。有两个方法可以正确的创建并获取指令集:
-
使用Module::getOrInsertFunction( intrinsic_name, intrinsic_function_type )。它会自动识别intrinsic的名称并创建function或者是intrinsic。指令需要使用全名。例如 llvm.x86.sse.sqrt.ps.
-
或者使用Ilvm::Intrinsic::getDeclaration( id ) 来创建。这个id可以在intrinsics.gen中找到。
因为LLVM生成的Intrinsic是全平台的,所以可以在x86上指定ARM汇编的生成,反之亦然。
3. 默认情况下,LLVM的JIT是不会启用InliningPass的,Optimization Level指定为Aggressive也不会。这意味着inlinehint和alwaysinline都是失效的。如果需要inlining得自己修改JIT的源代码。
4. UndefValue是个好东西。这个常量可以使生成的汇编少一条初始化指令。比方说用0初始化,可能对应的汇编就是 xor reg, reg。如果用了Undef,那这条指令就没了。
5. TypeBuilder很好用,只是不能生成struct等复杂的类型。不过你可以对它做一些修改以让它支持struct和vector。这个时候Boost.MPL就能派上用场了。不过要当心MPL带来漫长的编译时间。