如何将do-while形式的循环更改为LLVM IR中的while-form循环?
答案 0 :(得分:2)
这里有一个小循环示例。循环只是在布尔数组中运行,直到找到第一次出现的true
。我用clang -emit-llvm
编译它以获得优化的llvm IR。
#include <stdio.h>
#include <string.h>
int foo(bool* start){
bool* cond = start;;
while (*cond != true)
cond++;
return cond - start;
}
int bar(bool* start){
bool* cond = start;
do {
}while (*(++cond) != true);
return cond - start;
}
int main(){
bool cond[8];
memset(&cond, 0, sizeof(bool)*8);
cond[5] = true;
printf("%i %i\n", foo(cond), bar(cond));
}
foo函数的IR(仅使用while循环)如下所示:
; Function Attrs: nounwind uwtable
define i32 @_Z3fooPb(i8* %start) #0 {
%1 = alloca i8*, align 8
%cond = alloca i8*, align 8
store i8* %start, i8** %1, align 8
%2 = load i8** %1, align 8
store i8* %2, i8** %cond, align 8
br label %3
; <label>:3 ; preds = %9, %0
%4 = load i8** %cond, align 8
%5 = load i8* %4, align 1
%6 = trunc i8 %5 to i1
%7 = zext i1 %6 to i32
%8 = icmp ne i32 %7, 1
br i1 %8, label %9, label %12
; <label>:9 ; preds = %3
%10 = load i8** %cond, align 8
%11 = getelementptr inbounds i8* %10, i32 1
store i8* %11, i8** %cond, align 8
br label %3
; <label>:12 ; preds = %3
%13 = load i8** %cond, align 8
%14 = load i8** %1, align 8
%15 = ptrtoint i8* %13 to i64
%16 = ptrtoint i8* %14 to i64
%17 = sub i64 %15, %16
%18 = trunc i64 %17 to i32
ret i32 %18
}
和bar,我们得到的时候使用do:
; Function Attrs: nounwind uwtable
define i32 @_Z3barPb(i8* %start) #0 {
%1 = alloca i8*, align 8
%cond = alloca i8*, align 8
store i8* %start, i8** %1, align 8
%2 = load i8** %1, align 8
store i8* %2, i8** %cond, align 8
br label %3
; <label>:3 ; preds = %4, %0
br label %4
; <label>:4 ; preds = %3
%5 = load i8** %cond, align 8
%6 = getelementptr inbounds i8* %5, i32 1
store i8* %6, i8** %cond, align 8
%7 = load i8* %6, align 1
%8 = trunc i8 %7 to i1
%9 = zext i1 %8 to i32
%10 = icmp ne i32 %9, 1
br i1 %10, label %3, label %11
; <label>:11 ; preds = %4
%12 = load i8** %cond, align 8
%13 = load i8** %1, align 8
%14 = ptrtoint i8* %12 to i64
%15 = ptrtoint i8* %13 to i64
%16 = sub i64 %14, %15
%17 = trunc i64 %16 to i32
ret i32 %17
}
bar
的差异非常小我们有一个额外的标签和一个额外的br
因为我们在评估条件之前跳转到循环体并执行它。
因此,转换do的第一件事是摆脱分支并跳转到条件。现在是一个while循环,首先评估条件。这很容易。现在,您有两种选择来处理这种情况。您可以尝试修改条件什么是真正的硬任务,因为您可以将几乎所有内容放在循环条件中。简单的方法是在循环的第一个分支之前复制循环体一次(从;<label>:4
到;<label>:11
的所有内容)。所以你想要改变代码的正确性,你的do-while循环将成为循环前面的循环(循环体执行)。
您可以使用CloneBasicBlock
llvm/Transforms/Utils/Cloning.h
复制循环体
/// CloneBasicBlock - Return a copy of the specified basic block, but without
/// embedding the block into a particular function. The block returned is an
/// exact copy of the specified basic block, without any remapping having been
/// performed. Because of this, this is only suitable for applications where
/// the basic block will be inserted into the same function that it was cloned
/// from (loop unrolling would use this, for example).
///
/// Also, note that this function makes a direct copy of the basic block, and
/// can thus produce illegal LLVM code. In particular, it will copy any PHI
/// nodes from the original block, even though there are no predecessors for the
/// newly cloned block (thus, phi nodes will have to be updated). Also, this
/// block will branch to the old successors of the original block: these
/// successors will have to have any PHI nodes updated to account for the new
/// incoming edges.
///
/// The correlation between instructions in the source and result basic blocks
/// is recorded in the VMap map.
///
/// If you have a particular suffix you'd like to use to add to any cloned
/// names, specify it as the optional third parameter.
///
/// If you would like the basic block to be auto-inserted into the end of a
/// function, you can specify it as the optional fourth parameter.
///
/// If you would like to collect additional information about the cloned
/// function, you can specify a ClonedCodeInfo object with the optional fifth
/// parameter.
///
BasicBlock *CloneBasicBlock(const BasicBlock *BB,
ValueToValueMapTy &VMap,
const Twine &NameSuffix = "", Function *F = nullptr,
ClonedCodeInfo *CodeInfo = nullptr);
我希望这有点帮助。玩得开心!