如何重新排列 LLVM GEP 指令?
How to re-arragne LLVM GEP instructions?
我有如下所示的 LLVM IR:
for.body: ; preds = %for.cond
%add = add nsw i32 %i.0, 3
%idxprom = sext i32 %add to i64
%arrayidx = getelementptr inbounds i32, i32* %arr, i64 %idxprom
%0 = load i32, i32* %arrayidx, align 4
%add1 = add nsw i32 %sum1.0, %0
%add2 = add nsw i32 %i.0, 2
%idxprom3 = sext i32 %add2 to i64
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%1 = load i32, i32* %arrayidx4, align 4
%add5 = add nsw i32 %sum2.0, %1
%add6 = add nsw i32 %i.0, 1
%idxprom7 = sext i32 %add6 to i64
%arrayidx8 = getelementptr inbounds i32, i32* %arr, i64 %idxprom7
%2 = load i32, i32* %arrayidx8, align 4
%add9 = add nsw i32 %sum3.0, %2
%idxprom10 = sext i32 %i.0 to i64
%arrayidx11 = getelementptr inbounds i32, i32* %arr, i64 %idxprom10
%3 = load i32, i32* %arrayidx11, align 4
%add12 = add nsw i32 %sum4.0, %3
br label %for.inc
我想重新安排上面的 GEP 说明。对于这个例子,它应该像下面这样排列:
%arrayidx11 = getelementptr inbounds i32, i32* %arr, i64 %idxprom10
%arrayidx8 = getelementptr inbounds i32, i32* %arr, i64 %idxprom7
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%arrayidx = getelementptr inbounds i32, i32* %arr, i64 %idxprom
我知道即使是数组访问的使用也必须在这种安排之后移动。所以我正在尝试使用以下代码为每个 GEP 指令获取使用链:
// Get all the use chain instructions
for (Value::use_iterator i = inst1->use_begin(),e = inst1->use_end(); i!=e;++i) {
dyn_cast<Instruction>(*i)->dump();
}
但是我只得到了这段代码的声明指令,我期望得到 %arrayidx4 的以下所有指令:
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%1 = load i32, i32* %arrayidx4, align 4
请帮帮我。提前致谢。
我不太喜欢这个问题,但我今天应该为我的税做文书工作...
您的首要任务是找到 GEP 并将它们按您想要的顺序排序。这样做时,您需要一个单独的列表。 LLVM 的 BasicBlock class 确实提供了一个列表,但作为一般规则,在迭代它时切勿修改该列表。这是允许的,但太容易出错了。
所以在开始时:
std::vector<GetElementPtr *> geps;
for(auto & i : block->getInstList())
if(GetElementPtrInst * g = dyn_cast<GetElementPTrInst>(&i))
geps.push_back(g);
您可以使用任何容器 class,您的项目代码标准可能会建议使用 std::whatever 或 LLVM class。
接下来,将 geps
排序为您喜欢的顺序。我省略了那部分。
之后,将每个GEP移动到块中最新的允许点。那是哪一点?好吧,如果这个块是有效的,那么每个 GEP 已经在它使用的值之后和使用它的指令之前,所以将它移动到可能更晚的点,同时保持它在它的用户会做之前。
for(auto g : geps) {
Instruction * firstUser = nullptr;
for(auto u : g->users()) {
Instruction * i = dyn_cast<Instruction>(u);
if(i &&
i->getParent() == g->getParent() &&
(!firstUser ||
i->comesBefore(firstUser)))
firstUser = i;
}
}
if(firstUser)
g->moveBefore(firstUser);
}
对于每个用户,检查它是否是同一基本块内的指令,如果是,则检查它是否比目前看到的其他用户在块中更早。最后,移动GEP。
您可能更喜欢不同的方法。有几种可能。例如,您可以在对 GEP 进行排序后对其重新排序(使用 moveAfter() 将每个 GEP 移到前一个 GEP 之后),然后使用 users()
和 moveAfter()
的组合来确保所有用户都是在他们使用的说明之后。
for(auto u : foo->users))) {
Instruction * i = dyn_cast<Instruction>(u);
if(i &&
i->getParent() == foo->getParent() &&
i->comesBefore(foo))
i->moveAfter(foo);
}
再次注意,此代码在遍历时从不修改基本块的列表。如果您有任何神秘错误,请先检查一下。
我有如下所示的 LLVM IR:
for.body: ; preds = %for.cond
%add = add nsw i32 %i.0, 3
%idxprom = sext i32 %add to i64
%arrayidx = getelementptr inbounds i32, i32* %arr, i64 %idxprom
%0 = load i32, i32* %arrayidx, align 4
%add1 = add nsw i32 %sum1.0, %0
%add2 = add nsw i32 %i.0, 2
%idxprom3 = sext i32 %add2 to i64
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%1 = load i32, i32* %arrayidx4, align 4
%add5 = add nsw i32 %sum2.0, %1
%add6 = add nsw i32 %i.0, 1
%idxprom7 = sext i32 %add6 to i64
%arrayidx8 = getelementptr inbounds i32, i32* %arr, i64 %idxprom7
%2 = load i32, i32* %arrayidx8, align 4
%add9 = add nsw i32 %sum3.0, %2
%idxprom10 = sext i32 %i.0 to i64
%arrayidx11 = getelementptr inbounds i32, i32* %arr, i64 %idxprom10
%3 = load i32, i32* %arrayidx11, align 4
%add12 = add nsw i32 %sum4.0, %3
br label %for.inc
我想重新安排上面的 GEP 说明。对于这个例子,它应该像下面这样排列:
%arrayidx11 = getelementptr inbounds i32, i32* %arr, i64 %idxprom10
%arrayidx8 = getelementptr inbounds i32, i32* %arr, i64 %idxprom7
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%arrayidx = getelementptr inbounds i32, i32* %arr, i64 %idxprom
我知道即使是数组访问的使用也必须在这种安排之后移动。所以我正在尝试使用以下代码为每个 GEP 指令获取使用链:
// Get all the use chain instructions
for (Value::use_iterator i = inst1->use_begin(),e = inst1->use_end(); i!=e;++i) {
dyn_cast<Instruction>(*i)->dump();
}
但是我只得到了这段代码的声明指令,我期望得到 %arrayidx4 的以下所有指令:
%arrayidx4 = getelementptr inbounds i32, i32* %arr, i64 %idxprom3
%1 = load i32, i32* %arrayidx4, align 4
请帮帮我。提前致谢。
我不太喜欢这个问题,但我今天应该为我的税做文书工作...
您的首要任务是找到 GEP 并将它们按您想要的顺序排序。这样做时,您需要一个单独的列表。 LLVM 的 BasicBlock class 确实提供了一个列表,但作为一般规则,在迭代它时切勿修改该列表。这是允许的,但太容易出错了。
所以在开始时:
std::vector<GetElementPtr *> geps;
for(auto & i : block->getInstList())
if(GetElementPtrInst * g = dyn_cast<GetElementPTrInst>(&i))
geps.push_back(g);
您可以使用任何容器 class,您的项目代码标准可能会建议使用 std::whatever 或 LLVM class。
接下来,将 geps
排序为您喜欢的顺序。我省略了那部分。
之后,将每个GEP移动到块中最新的允许点。那是哪一点?好吧,如果这个块是有效的,那么每个 GEP 已经在它使用的值之后和使用它的指令之前,所以将它移动到可能更晚的点,同时保持它在它的用户会做之前。
for(auto g : geps) {
Instruction * firstUser = nullptr;
for(auto u : g->users()) {
Instruction * i = dyn_cast<Instruction>(u);
if(i &&
i->getParent() == g->getParent() &&
(!firstUser ||
i->comesBefore(firstUser)))
firstUser = i;
}
}
if(firstUser)
g->moveBefore(firstUser);
}
对于每个用户,检查它是否是同一基本块内的指令,如果是,则检查它是否比目前看到的其他用户在块中更早。最后,移动GEP。
您可能更喜欢不同的方法。有几种可能。例如,您可以在对 GEP 进行排序后对其重新排序(使用 moveAfter() 将每个 GEP 移到前一个 GEP 之后),然后使用 users()
和 moveAfter()
的组合来确保所有用户都是在他们使用的说明之后。
for(auto u : foo->users))) {
Instruction * i = dyn_cast<Instruction>(u);
if(i &&
i->getParent() == foo->getParent() &&
i->comesBefore(foo))
i->moveAfter(foo);
}
再次注意,此代码在遍历时从不修改基本块的列表。如果您有任何神秘错误,请先检查一下。