首页 > 解决方案 > How to change the operand type in the instruction from 32bit to 64bit in LLVM?

问题描述

I am a newbie to LLVM. And I am trying to change the type of the loop variable (PHINode). For example, I have an IR as follows:

for.cond1.preheader:                              ; preds = %entry, %for.inc15
  %k.03 = phi i32 [ 0, %entry ], [ %inc16, %for.inc15 ]
  br label %for.cond4.preheader

for.cond4.preheader:                              ; preds = %for.cond1.preheader, %for.inc12
  %indvars.iv5 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next6, %for.inc12 ]
  br label %for.body6

for.body6:                                        ; preds = %for.cond4.preheader, %for.body6
  ......
  %add7 = add nsw i32 %2, 1
  ......

for.inc12:                                        ; preds = %for.body6
  ......

for.inc15:                                        ; preds = %for.inc12
  %inc16 = add nuw nsw i32 %k.03, 1
  %exitcond9 = icmp ne i32 %inc16, 100
  br i1 %exitcond9, label %for.cond1.preheader, label %for.end17, !llvm.loop !7 ​

I want to change the type of the variable %k.03, hoping it will change from 32bit to 64bit. And recursively change all its references (Uses) to 64bit. The effect is as follows:

for.cond1.preheader:                              ; preds = %entry, %for.inc15
  %k.03 = phi i64 [ 0, %entry ], [ %inc16, %for.inc15 ]
  br label %for.cond4.preheader

for.cond4.preheader:                              ; preds = %for.cond1.preheader, %for.inc12
  %indvars.iv5 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next6, %for.inc12 ]
  br label %for.body6

for.body6:                                        ; preds = %for.cond4.preheader, %for.body6
  ......
  %add7 = add nsw i32 %2, 1
  ......

for.inc12:                                        ; preds = %for.body6
  ......

for.inc15:                                        ; preds = %for.inc12
  %inc16 = add nuw nsw i64 %k.03, 1
  %exitcond9 = icmp ne i64 %inc16, 100
  br i1 %exitcond9, label %for.cond1.preheader, label %for.end17, !llvm.loop !7 ​

Then my approach is as follows:

static void __ChangeInsTo64Bit(User *inst) {
  if (!std::strcmp(cast<Instruction>(inst)->getOpcodeName(), "br")) {
    return;
  }
  if (std::strcmp(cast<Instruction>(inst)->getOpcodeName(), "icmp")) {
    inst->mutateType(inst->getType()->getWithNewBitWidth(64));
  }
  for (auto OI = inst->op_begin(), OE = inst->op_end(); OI != OE; ++OI) {
    Value *val = *OI;
    val->mutateType(val->getType()->getWithNewBitWidth(64));
    LLVM_DEBUG(dbgs() << "The Operand is: " << val->getName() 
                      << "; The bitwidth is: " << val->getType()->getIntegerBitWidth() << "\n");
  }
}

static void  __ChangePHINodeWidthTo64(Loop *OuterLoop, ScalarEvolution *SE) {

  PHINode *OuterPHINode = OuterLoop->getInductionVariable(*SE);
  if (!OuterPHINode) {
    return ;
  }

  unsigned int outerPHIWidth = OuterPHINode->getType()->getIntegerBitWidth();

  if (outerPHIWidth == 32) {
    __ChangeInsTo64Bit(OuterPHINode);
    for (User* user : OuterPHINode->users()) {
      __ChangeInsTo64Bit(user);
      for (User* u : user->users()) {
        __ChangeInsTo64Bit(u);
      }
    }
  }
}

Through the above code, I can achieve my goal, but weirdly modify the data type in the basic block for.body6:

%add7 = add nsw i32 %2, i64 1

This will cause program errors. Can someone help me point out the wrong point in my approach or provide the correct approach?


标签: c++clangllvmllvm-irllvm-gcc

解决方案


if (!std::strcmp(cast<Instruction>(inst)->getOpcodeName(), "br")) {
    return;
}

if (std::strcmp(cast<Instruction>(inst)->getOpcodeName(), "icmp")) {
  inst->mutateType(inst->getType()->getWithNewBitWidth(64));
}

这似乎是一种非常笨拙且容易出错的 RTTI 方式,尤其是因为 LLVM 提供了isa<>用于该目的的模板。

举个例子,“icmp”检查将匹配所有不是icmp 的内容(因为!条件前面没有),我希望这不是您的本意。

至少,以下内容等同于您的代码并且更清晰:

if (isa<BranchInst>(inst)) {
    return;
}

if (!isa<ICmpInst>(inst)) {
  inst->mutateType(inst->getType()->getWithNewBitWidth(64));
}

在第二个测试之前删除否定应该至少解决您的部分问题。


推荐阅读