[DEBUG]类型冲突[整型转换]

发布于 2019-10-02  4 次阅读


调试过程

最近在写创建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
例如如果vValue *指向i1的表达式的指针,将其转换为i32

v = Builder.CreateIntCast(v, Type::getInt32Ty(Context), true);

i32转i1

上个方法不能用于将i32转换为i1 。 它会将值截断为最低有效位。 所以i32 2将导致i1 0
但是我们需要把非零i32转换为i1 1i32 0转换为i1 0
如果vValue *指针指向一个i32的表达式,将其转换为i1

v = Builder.CreateICmpNE(v, ConstantInt::get(Type::getInt32Ty(Context), 0, true));

这里相当于间接用到了上面调试出来的,CreateICmpNE的返回值是i1的特性,巧妙地转换了类型。

PS

更多的类型在doxygen可以看到