循环外使用的LLVM LoopPass值

时间:2018-06-27 08:31:48

标签: llvm llvm-ir

我正在编写LLVM LoopPass,在其中我需要知道哪些值 在循环外部使用。为此,我有以下代码:

virtual bool runOnLoop(Loop *loop, LPPassManager &LPM)
{
    for (auto it = loop->block_begin(); it != loop->block_end(); it++)
    {
        for (auto inst = (*it)->begin(); inst != (*it)->end(); inst++)
        {
            if (Is_Used_Outside_This_loop(loop,(Instruction *) inst))
            {
                errs() << inst->getName().str();
                errs() << " is used outside the loop\n";
            }
        }
    }
    // ...
}

内部函数乍一看似乎正确,但是下面带有* .ll文件, 它为%tmp5提供了错误的分类,因为它被使用了两次 在循环的基本块内。

bool Is_Used_Outside_This_loop(Loop *loop, Value *v)
{
    int n=0;
    int numUses = v->getNumUses();
    for (auto it = loop->block_begin(); it != loop->block_end(); it++)
    {
        if (v->isUsedInBasicBlock(*it))
        {
            n++;
        }
    }
    if (n == numUses) return false;
    else              return true;
}

以下* .ll代码显示%tmp5被使用了两次 在循环的基本块内。当我仔细搜索API时, 我找不到类似Value :: numUsesInBasicBlock(...)

的任何东西
; Function Attrs: nounwind uwtable
define internal void @foo(i8* %s) #0 {
entry:
  %s.addr = alloca i8*, align 8
  %c = alloca i8, align 1
  store i8* %s, i8** %s.addr, align 8
  store i8 0, i8* %c, align 1
  br label %while.cond

while.cond:    ; preds = %while.body, %entry
  %tmp = load i8*, i8** %s.addr, align 8
  %tmp1 = load i8, i8* %tmp, align 1
  %conv = sext i8 %tmp1 to i32
  %cmp = icmp eq i32 %conv, 97
  br i1 %cmp, label %lor.end, label %lor.rhs

lor.rhs:    ; preds = %while.cond
  %tmp2 = load i8*, i8** %s.addr, align 8
  %tmp3 = load i8, i8* %tmp2, align 1
  %conv2 = sext i8 %tmp3 to i32
  %cmp3 = icmp eq i32 %conv2, 98
  br label %lor.end

lor.end:; preds = %lor.rhs, %while.cond
  %tmp4 = phi i1 [ true, %while.cond ], [ %cmp3, %lor.rhs ]
  br i1 %tmp4, label %while.body, label %while.end

while.body:    ; preds = %lor.end
  %tmp5 = load i8*, i8** %s.addr, align 8
  %incdec.ptr = getelementptr inbounds i8, i8* %tmp5, i32 1
  store i8* %incdec.ptr, i8** %s.addr, align 8
  %tmp6 = load i8, i8* %tmp5, align 1
  store i8 %tmp6, i8* %c, align 1
  br label %while.cond

while.end:    ; preds = %lor.end
  %tmp7 = load i8*, i8** %s.addr, align 8
  %tmp8 = load i8, i8* %tmp7, align 1
  %conv5 = sext i8 %tmp8 to i32
  %cmp6 = icmp eq i32 %conv5, 99
  br i1 %cmp6, label %if.then, label %if.end

if.then:    ; preds = %while.end
  %tmp9 = load i8*, i8** %s.addr, align 8
  %incdec.ptr8 = getelementptr inbounds i8, i8* %tmp9, i32 1
  store i8* %incdec.ptr8, i8** %s.addr, align 8
  br label %if.end

if.end:    ; preds = %if.then, %while.end
  ret void
}

很显然,必须有一种方法,对吗?谢谢!

2 个答案:

答案 0 :(得分:0)

这是我解决的方法,尽管它看起来过于复杂:

virtual bool runOnLoop(Loop *loop, LPPassManager &LPM)
{
    for (auto it = loop->block_begin(); it != loop->block_end(); it++)
    {
        for (auto inst = (*it)->begin(); inst != (*it)->end(); inst++)
        {
            int n=0;
            for (auto use = inst->use_begin(); use != inst->use_end(); use++)
            {
                Instruction *i = (Instruction *) use->getUser();
                if (BasicBlockBelongsToLoop(i->getParent(),loop))
                {
                    n++;
                }
            }
            assert(n <= inst->getNumUses());
            if (n < inst->getNumUses())
            {
                errs() << inst->getName().str();
                errs() << " is used outside the loop\n";
            }
        }
    }
    // ...

我也没有在API中找到如何检查基本块是否属于循环, 所以我不得不写我自己的BasicBlockBelongsToLoop,这里是:

bool BasicBlockBelongsToLoop(BasicBlock *BB, Loop *loop)
{
    for (auto it = loop->block_begin(); it != loop->block_end(); it++)
    {
        if (BB == (*it))
        {
            return true;
        }
    }
    return false;
}

答案 1 :(得分:0)

问题是您的退出条件。您要求使用,然后将其与使用该值的块数进行比较。

因此,如果在同一基本块中两次使用该值,则使用次数为2,并且使用该值的基本块的export const createPost = (postData) => async (dispatch) => { // send postData to server const rawResponse = await fetch(`${Config.address}/post`, { method: 'POST', headers:{ 'Content-Type': 'application/json' }, body: JSON.stringify(postData) }); // we are done with server but we need one more step // turn a raw response to readable JS object const message = await rawResponse.json() // message from server response console.log('Message ', message); // store same object as we sent to server in redux store dispatch({ type: NEW_POST, payload: postData }); } 计数器仅增加一次,因此{{1 }}和n

也许做一个您想要的更简洁的方法是:

n

,然后在numUses方法中输入以下内容:

void FindUsesNotIn(
  llvm::SmallPtrSetImpl<llvm::BasicBlock *> &Blocks,
  llvm::SmallPtrSetImpl<llvm::Value *> &OutUses) {
  for(const auto &b : Blocks)
    for(auto &i : *b)
      for(const auto &u : i.users()) {
        auto *userInst = llvm::dyn_cast<llvm::Instruction>(u);

        if(userInst && !Blocks.count(userInst->getParent())) {
          OutUses.insert(&i);
          break;
        }
      }
}