在 LLVM IR 中调用 x86 MMX 内在函数
Invoking x86 MMX intrinsics in LLVM IR
我应该如何在 LLVM 中调用 MMX 内部函数?此代码导致断言失败,因为内部参数的类型不正确。但是,我猜不出正确的类型。
最有可能的假设是 "MMX vector" 之类的东西会起作用。但是我还找不到处理这些类型的合适的代码片段。
Value* IRGenContext::emitSaturatingSubUI8(Value* lho, Value* rho, const Twine& name)
{
Type* mmxType = Type::getX86_MMXTy(session_.lctx());
std::vector<Type*> paramTypes = { mmxType, mmxType };
std::vector<Value*> paramVals = {
irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, lho, mmxType),
irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, rho, mmxType)
};
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b, paramTypes);
Value* intrinsicResult = irBuilder().CreateCall(subsIntr, paramVals, name);
return irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, intrinsicResult, getUOctaTy());
}
Function* IRGenContext::getIntrinsic(llvm::Intrinsic::ID id, llvm::ArrayRef<llvm::Type*> Tys)
{
return llvm::Intrinsic::getDeclaration(module_.get(), id, Tys);
}
IR 表示如下所示:
它导致断言错误:
Assertion failed: DAG.getTargetLoweringInfo().isTypeLegal(PartVT) &&
"Copying to an illegal type!", file
F:\cpp\llvm-git\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp,
line 376
; ModuleID = 'jit_module_560'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
define void @jit_fn559(i8* %cookie) {
Block_6010:
%0 = call i64 @_readRegUint(i8* %cookie, i8 2)
%1 = call i64 @_readRegUint(i8* %cookie, i8 3)
%2 = call i64 @_readRegUint(i8* %cookie, i8 4)
br label %Block_6010.split
Block_6010.split: ; preds = %Block_6010
%reg561 = phi i64 [ 0, %Block_6010 ]
%reg562 = phi i64 [ %0, %Block_6010 ]
%reg563 = phi i64 [ %1, %Block_6010 ]
%reg564 = phi i64 [ %2, %Block_6010 ]
%"#c1010100" = or i64 %reg561, 0
%"#c1020200" = or i64 %reg562, 0
%"#c1030300" = or i64 %reg563, 0
%"#c1040400" = or i64 %reg564, 0
%3 = bitcast i64 %"#c1020200" to x86_mmx
%4 = bitcast i64 %"#c1030300" to x86_mmx
%5 = call x86_mmx @llvm.x86.mmx.psubs.b.x86mmx.x86mmx(x86_mmx %3, x86_mmx %4)
%6 = bitcast x86_mmx %5 to i64
call void @_storeMemUint64(i8* %cookie, i64 %"#c1040400", i64 0, i64 %6)
%7 = call i64 @_readSpRegUint(i8* %cookie, i8 4)
call void @_pop(i8* %cookie, i64 %7, i8 0)
ret void
}
declare i64 @_readRegUint(i8*, i8)
declare void @_storeRegUint(i8*, i8, i64)
declare x86_mmx @llvm.x86.mmx.psubs.b.x86mmx.x86mmx(x86_mmx, x86_mmx)
declare void @_storeMemUint64(i8*, i64, i64, i64)
declare i64 @_readSpRegUint(i8*, i8)
declare void @_pop(i8*, i64, i8)
您可以在位于 llvm/include/llvm/IR/
.
的 Intrinsics TableGen 文件中查找 Intrinsic 所需的类型
来自IntrinsicsX86.td
3583 def int_x86_mmx_psub_b : GCCBuiltin<"__builtin_ia32_psubb">,
3584 Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty],
3585 [IntrNoMem]>;
在您的情况下,您需要 x86mmx_ty
。作为获得此指令正确类型的提示,您可以询问 clang。
编译对内置函数的调用,该调用将生成带有垃圾标志值的内在函数:
void foo()
{
__builtin_ia32_psubb(42, "42"); // we need the error
}
结果:
test.c:3:24: error: passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(8 * sizeof(char)))) char' (vector of 8 'char' values)
__builtin_ia32_psubb(42, "42");
所以这个内部函数的正确类型是 vector of 8 char
。
由于内在函数没有类型重载,因此您不应调用
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b, paramTypes);
参数类型:
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b);
非常适合您的目的。
我应该如何在 LLVM 中调用 MMX 内部函数?此代码导致断言失败,因为内部参数的类型不正确。但是,我猜不出正确的类型。 最有可能的假设是 "MMX vector" 之类的东西会起作用。但是我还找不到处理这些类型的合适的代码片段。
Value* IRGenContext::emitSaturatingSubUI8(Value* lho, Value* rho, const Twine& name)
{
Type* mmxType = Type::getX86_MMXTy(session_.lctx());
std::vector<Type*> paramTypes = { mmxType, mmxType };
std::vector<Value*> paramVals = {
irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, lho, mmxType),
irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, rho, mmxType)
};
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b, paramTypes);
Value* intrinsicResult = irBuilder().CreateCall(subsIntr, paramVals, name);
return irBuilder().CreateCast(llvm::Instruction::CastOps::BitCast, intrinsicResult, getUOctaTy());
}
Function* IRGenContext::getIntrinsic(llvm::Intrinsic::ID id, llvm::ArrayRef<llvm::Type*> Tys)
{
return llvm::Intrinsic::getDeclaration(module_.get(), id, Tys);
}
IR 表示如下所示:
它导致断言错误:
Assertion failed: DAG.getTargetLoweringInfo().isTypeLegal(PartVT) && "Copying to an illegal type!", file F:\cpp\llvm-git\llvm\lib\CodeGen\SelectionDAG\SelectionDAGBuilder.cpp, line 376
; ModuleID = 'jit_module_560'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
define void @jit_fn559(i8* %cookie) {
Block_6010:
%0 = call i64 @_readRegUint(i8* %cookie, i8 2)
%1 = call i64 @_readRegUint(i8* %cookie, i8 3)
%2 = call i64 @_readRegUint(i8* %cookie, i8 4)
br label %Block_6010.split
Block_6010.split: ; preds = %Block_6010
%reg561 = phi i64 [ 0, %Block_6010 ]
%reg562 = phi i64 [ %0, %Block_6010 ]
%reg563 = phi i64 [ %1, %Block_6010 ]
%reg564 = phi i64 [ %2, %Block_6010 ]
%"#c1010100" = or i64 %reg561, 0
%"#c1020200" = or i64 %reg562, 0
%"#c1030300" = or i64 %reg563, 0
%"#c1040400" = or i64 %reg564, 0
%3 = bitcast i64 %"#c1020200" to x86_mmx
%4 = bitcast i64 %"#c1030300" to x86_mmx
%5 = call x86_mmx @llvm.x86.mmx.psubs.b.x86mmx.x86mmx(x86_mmx %3, x86_mmx %4)
%6 = bitcast x86_mmx %5 to i64
call void @_storeMemUint64(i8* %cookie, i64 %"#c1040400", i64 0, i64 %6)
%7 = call i64 @_readSpRegUint(i8* %cookie, i8 4)
call void @_pop(i8* %cookie, i64 %7, i8 0)
ret void
}
declare i64 @_readRegUint(i8*, i8)
declare void @_storeRegUint(i8*, i8, i64)
declare x86_mmx @llvm.x86.mmx.psubs.b.x86mmx.x86mmx(x86_mmx, x86_mmx)
declare void @_storeMemUint64(i8*, i64, i64, i64)
declare i64 @_readSpRegUint(i8*, i8)
declare void @_pop(i8*, i64, i8)
您可以在位于 llvm/include/llvm/IR/
.
来自IntrinsicsX86.td
3583 def int_x86_mmx_psub_b : GCCBuiltin<"__builtin_ia32_psubb">,
3584 Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty],
3585 [IntrNoMem]>;
在您的情况下,您需要 x86mmx_ty
。作为获得此指令正确类型的提示,您可以询问 clang。
编译对内置函数的调用,该调用将生成带有垃圾标志值的内在函数:
void foo()
{
__builtin_ia32_psubb(42, "42"); // we need the error
}
结果:
test.c:3:24: error: passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(8 * sizeof(char)))) char' (vector of 8 'char' values)
__builtin_ia32_psubb(42, "42");
所以这个内部函数的正确类型是 vector of 8 char
。
由于内在函数没有类型重载,因此您不应调用
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b, paramTypes);
参数类型:
Function* subsIntr = getIntrinsic(llvm::Intrinsic::x86_mmx_psubs_b);
非常适合您的目的。