调试过程
最近在写创建loop的IR maker,但是在边界条件比较的地方,直接assert退出了。
Assertion failed: getOperand(0)->getType() == getOperand(1)->getType() && "Both operands to ICmp instruction are not of the same type!", file ***\llvm-8.0.1.src\include\llvm/IR/Instructions.h, line 1195
跟踪到相关源代码
Value* EndCond = Builder.CreateICmpULT ( IndVar, EndVal, "endcond" );
outs() << EndCond->getType();
EndCond = Builder.CreateICmpNE ( EndCond, Builder.getInt32 ( 0 ), "loopcond" );
这块地方报了上述错误,提示操作数间类型不匹配。
CreateICmpNE
的第二个操作数是i32类型的。那么我们看第一个操作数的类型。
翻看Value
类的实现,有getType()
函数,但是在Type
类中,类型只有如下17种,没有对integer作位数的细化。
enum TypeID {
// PrimitiveTypes - make sure LastPrimitiveTyID stays up to date.
VoidTyID = 0, ///< 0: type with no size
HalfTyID, ///< 1: 16-bit floating point type
FloatTyID, ///< 2: 32-bit floating point type
DoubleTyID, ///< 3: 64-bit floating point type
X86_FP80TyID, ///< 4: 80-bit floating point type (X87)
FP128TyID, ///< 5: 128-bit floating point type (112-bit mantissa)
PPC_FP128TyID, ///< 6: 128-bit floating point type (two 64-bits, PowerPC)
LabelTyID, ///< 7: Labels
MetadataTyID, ///< 8: Metadata
X86_MMXTyID, ///< 9: MMX vectors (64 bits, X86 specific)
TokenTyID, ///< 10: Tokens
// Derived types... see DerivedTypes.h file.
// Make sure FirstDerivedTyID stays up to date!
IntegerTyID, ///< 11: Arbitrary bit width integers
FunctionTyID, ///< 12: Functions
StructTyID, ///< 13: Structures
ArrayTyID, ///< 14: Arrays
PointerTyID, ///< 15: Pointers
VectorTyID ///< 16: SIMD 'packed' format, or other vector type
};
通过IntegerTyID
的注释,我们找到llvm/IR/DerivedTypes.h
头文件,在里面找到了获取整数位数的函数
unsigned Type::getIntegerBitWidth() const {
return cast<IntegerType>(this)->getBitWidth();
}
我们调试后发现CreateICmpULT
返回的是i1
类型的,和i32
类型的不匹配。这个时候需要转换一下,这里选择把i1转为i32,当然也可以把i32的改为i1类型(会有截断问题,下面会介绍)。
注意需要引入DerivedTypes.h头文件
#include "llvm/IR/DerivedTypes.h"
Value* EndCond = Builder.CreateICmpULT ( IndVar, EndVal, "endcond" );
outs() << "TypeID is :"<<(EndCond->getType())->getTypeID();
if ( EndCond->getType()->isIntegerTy() )
outs() <<"\nthe bit width is : "<< EndCond->getType()->getIntegerBitWidth() << "\n";
else
outs() << "\nNot integer\n";
EndCond = Builder.CreateIntCast (
EndCond, Type::getInt32Ty ( Context ),
true );
EndCond = Builder.CreateICmpNE ( EndCond, Builder.getInt32 ( 0 ), "loopcond" );
调试出EndCond的类型
TypeID is :11
the bit width is : 1
i1与i32的类型互转
i1转i32
使用IRBuilder::CreateIntCast
例如如果v
是Value *
指向i1
的表达式的指针,将其转换为i32
:
v = Builder.CreateIntCast(v, Type::getInt32Ty(Context), true);
i32转i1
上个方法不能用于将i32
转换为i1
。 它会将值截断为最低有效位。 所以i32 2
将导致i1 0
。
但是我们需要把非零i32转换为i1 1
,i32 0
转换为i1 0
。
如果v
是Value *
指针指向一个i32
的表达式,将其转换为i1
:
v = Builder.CreateICmpNE(v, ConstantInt::get(Type::getInt32Ty(Context), 0, true));
这里相当于间接用到了上面调试出来的,CreateICmpNE
的返回值是i1
的特性,巧妙地转换了类型。
PS
更多的类型在doxygen可以看到
网友评论