【问题标题】:How to map multiple same type loops under a function to the generated basic block in LLVM IR?如何将函数下的多个相同类型的循环映射到 LLVM IR 中生成的基本块?
【发布时间】:2018-06-04 18:48:09
【问题描述】:

如果循环是不同类型的,那么我可以很容易地用名称识别它们,但是如果有多个相同类型的循环(比如 5 个while 循环),我如何识别 LLVM IR 中的基本块对应于哪个基本块源代码中的哪个循环?

当我们依次访问代码和 LLVM IR 时,手动识别很容易,但我正在研究如何以编程方式识别相同内容。

例如,我在 C 中有以下源代码:

int main()
{
   int count=1;
   while (count <= 4)
   {
        count++;
   }
   while (count > 4)
   {
        count--;
   }
   return 0;
}

当我执行命令 clang -S -emit-llvm fileName.c 时,我得到了 fileName.ll 创建,内容如下:

; ModuleID = 'abc.c'
source_filename = "abc.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.0.23026"

; Function Attrs: noinline nounwind uwtable
define i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  %count = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 1, i32* %count, align 4
  br label %while.cond

while.cond:                                       ; preds = %while.body, %entry
  %0 = load i32, i32* %count, align 4
  %cmp = icmp sle i32 %0, 4
  br i1 %cmp, label %while.body, label %while.end

while.body:                                       ; preds = %while.cond
  %1 = load i32, i32* %count, align 4
  %inc = add nsw i32 %1, 1
  store i32 %inc, i32* %count, align 4
  br label %while.cond

while.end:                                        ; preds = %while.cond
  br label %while.cond1

while.cond1:                                      ; preds = %while.body3, %while.end
  %2 = load i32, i32* %count, align 4
  %cmp2 = icmp sgt i32 %2, 4
  br i1 %cmp2, label %while.body3, label %while.end4

while.body3:                                      ; preds = %while.cond1
  %3 = load i32, i32* %count, align 4
  %dec = add nsw i32 %3, -1
  store i32 %dec, i32* %count, align 4
  br label %while.cond1

while.end4:                                       ; preds = %while.cond1
  ret i32 0
}

attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"}

现在为给定的源文件创建了两个基本块while.condwhile.cond1,我如何识别源代码中哪个基本块是哪个while循环?

【问题讨论】:

    标签: c llvm llvm-ir llvm-c++-api llvm-codegen


    【解决方案1】:

    在我尝试回答之前,我只想指出,根据选择的优化级别或使用opt 手动选择的传递,信息可能不存在或可能不准确(例如,由于内联、克隆、等)。

    现在,将低级表示和源代码关联起来的方法是使用调试信息(例如,使用DWARF 格式)。要生成调试信息,您需要在编译期间使用-g 命令行标志。

    对于 LLVM IR,如果您查看 Loop API,就会发现相关调用,例如 getStartLoc。所以你可以做这样的事情(例如在llvm::Function pass 的runOn 方法内):

    llvm::SmallVector<llvm::Loop *> workList;
    auto &LI = getAnalysis<llvm::LoopInfoWrapperPass>(CurFunc).getLoopInfo();
    
    std::for_each(LI.begin(), LI.end(), [&workList](llvm::Loop *e) { workList.push_back(e); });
    
    for(auto *e : workList) {
      auto line = e->getStartLoc().getLine();
      auto *scope = llvm::dyn_cast<llvm::DIScope>(e->getStartLoc().getScope());
      auto filename = scope->getFilename();
    
      // do stuff here
    }
    

    另外,对于BasicBlock,还可以使用Instruction中的调试相关方法(如getDebugLoc),并结合调用Loop的其他方法,如getHeader等。

    另外,请注意,有一个 getLoopID 方法为每个循环使用一个内部唯一 ID,但这并不总是存在,它受我在开始时提到的潜在省略的影响。无论如何,如果您需要对其进行操作,请查看 LLVM 源代码中遵循 setLoopID 方法的示例(例如在 lib/Transforms/Scalar/LoopRotation.cpp 中)。

    【讨论】:

    • 你能帮我解决我必须包含在getAnalysis()方法中的头文件吗
    • getAnalysis 方法被所有的 pass 类继承,所以它应该是随时可用的。 LoopInfoWrapperPass 可从llvm/Analysis/LoopInfo.h 获得。我认为在 LLVM 源代码树上使用 grep 或类似工具会有很大帮助。
    • 您可能还想看看this repo。它用数字 ID 注释循环。你可以做出相应的调整。
    • 感谢您的回复,我会在我实施时在这里更新。
    • 如果将其发布在问题中会有所帮助;这就是为什么 SO 政策需要发布您的一些代码的原因。无论如何,对于独立工具,您必须“手动”生成LoopInfo。为此,您可以查看unittests 子目录中的测试套件,例如,Analysis/LoopInfoTest.cpprunWithLoopInfo 函数内部,通过的llvm::Function 的独立LoopInfo 对象是使用其构造的DominatorTree。我不确定这个测试是否在 4.0.1 中可用,但它在当前的主干(6.0.1)中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    相关资源
    最近更新 更多