当前位置:  开发笔记 > 编程语言 > 正文

如何在LLVM上创建Loop对象?

如何解决《如何在LLVM上创建Loop对象?》经验,为你挑选了1个好方法。

我想知道LLVM如何创建Loop对象。

与Loop相关的对象很多,例如LoopInfo,LoopBase,Loop等。

但是我找不到他们创建这些对象的LLVM源代码的位置。

我想知道他们如何跟踪后端,以及如何识别这是一个循环。

可以这么说,我想学习有关在LLVM上检测和分析Loop信息的整个原理



1> 小智..:

您可以通过两种方式实现常规循环。一个不使用phi指令,一个使用,但是都使用br运算符。

看下面的代码:

#include 

int main () {

   for(int i = 0; i < 10; i++) {
      printf("Test.\n");
   }

   return 0;
}

在这里,我生成了一个使用Clang与command的示例clang -S loop.c -emit-llvm,使它实现第一个选项:

@.str = private unnamed_addr constant [7 x i8] c"Test.\0A\00", align 1

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

for.cond:                                         ; preds = %for.inc, %entry
  %0 = load i32* %i, align 4
  %cmp = icmp slt i32 %0, 10
  br i1 %cmp, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str, i32 0, i32 0)) #1
  br label %for.inc

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

for.end:                                          ; preds = %for.cond
  ret i32 0
}

; Function Attrs: nounwind
declare i32 @printf(i8*, ...) #0

首先,我们创建标识符来表示我们的i变量和返回值变量,然后将它们分别设置为0。它转到第一个标签并开始循环,首先计算icmp , 指令产生的布尔值,其中slt=“小于符号”。如果%i小于10,则将true存储在中%cmp,否则,将存储false。br紧随其后的指令的语法br i1 , label , label 定义了,如果%cmp为true,则iftrue在这种情况下程序将跳转到标签%for.body,否则,将跳转到iffalse标签%for.end。总结一下,如果%i仍然小于10,如果达到10,它将退出循环。有了br指令的最终知识,该程序其余部分的行为就应该显而易见。

现在,虽然第二种方法要短得多,但稍微复杂一些。我使用Clang使用command生成了此代码clang -S loop.c -emit-llvm -O1,即在1级优化标志上进行标记,导致其实现第二个选项:

@.str = private unnamed_addr constant [7 x i8] c"Test.\0A\00", align 1
@str = private unnamed_addr constant [6 x i8] c"Test.\00"

; Function Attrs: nounwind
define i32 @main() #0 {
entry:
  br label %for.body

for.body:                                         ; preds = %for.body, %entry
  %i.02 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %puts = tail call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @str, i32 0, i32 0))
  %inc = add nuw nsw i32 %i.02, 1
  %exitcond = icmp eq i32 %inc, 10
  br i1 %exitcond, label %for.end, label %for.body

for.end:                                          ; preds = %for.body
  ret i32 0
}

; Function Attrs: nounwind
declare i32 @puts(i8* nocapture readonly) #1

忽略增量技术的有趣语法%inc = add nuw nsw i32 %i.02, 1,它只是整数数学溢出错误处理。我们专注于phi说明这是手册中的描述:

在运行时,“ phi”指令在逻辑上采用由对应于在当前块之前执行的先前基本块的对指定的值。

因此,让我们再次将有问题的代码引起我们的注意:

for.body:
          %i.02 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
          %puts = tail call i32 @puts(i8* getelementptr inbounds ([6 x i8]* @str, i32 0, i32 0))
          %inc = add nuw nsw i32 %i.02, 1
          %exitcond = icmp eq i32 %inc, 10
          br i1 %exitcond, label %for.end, label %for.body

当我们第一次遇到时%i.02,我们通过的最后一个标签是entry。因此,指示我们将其设置%i.02为0。即使我们已经传递了for.body标签,执行命令的最后一个前置程序块仍位于该entry块中,成为entry最后一个标签。接下来,我们调用控制台打印功能。然后,我们声明一个变量%inc并将其设置为'i'变量+ 1,并且这是第一个增量,它将变为0。最后,我们进行了布尔比较,检查我们的'i'值是否小于10,在这种情况下,br指令会将我们发送回顶部。现在是棘手的部分:phi可以告诉代码最后在for.body标签中执行了。这意味着我们仍在for.body前一个块,%inc并且仍在我们的符号表中,这就是为什么我们可以设置%i.02为的原因%inc%inc将继续递增,直到等于10,br指令将跳转到该%for.end标号处,从而退出循环。

有关上述所有说明的更多信息,请访问《LLVM语言参考手册》。

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有