前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LLVM(2)IR入门

LLVM(2)IR入门

作者头像
mingjie
发布2023-10-13 10:28:50
2550
发布2023-10-13 10:28:50
举报

1 不支持类型的隐式转换

代码语言:javascript
复制
int factorial(int val);

int factorial(int val)
{

	if (val <= 2)
		return 1;

	return factorial(val - 1) + factorial(val - 2);
}

int main(int argc, char **argv)
{
	return factorial(2) * 7 == 42;
}

生成IR代码

clang++ -emit-llvm -S t3.cpp -o t3.ll

代码语言:javascript
复制
; ModuleID = 't3.cpp'
source_filename = "t3.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: mustprogress noinline optnone uwtable
define dso_local noundef i32 @_Z9factoriali(i32 noundef %0) #0 {
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i32 %0, ptr %3, align 4
  %4 = load i32, ptr %3, align 4

  %5 = icmp sle i32 %4, 2           /* val <= 2 */ 

  br i1 %5, label %6, label %7      /* if (val <= 2) 真:跳转到6 假:跳转到7 */ 

6:                                                ; preds = %1
  store i32 1, ptr %2, align 4      /* 1存到2号寄存器 */ 
  br label %15

7:                                                ; preds = %1
  %8 = load i32, ptr %3, align 4
  %9 = sub nsw i32 %8, 1
  %10 = call noundef i32 @_Z9factoriali(i32 noundef %9)
  %11 = load i32, ptr %3, align 4
  %12 = sub nsw i32 %11, 2
  %13 = call noundef i32 @_Z9factoriali(i32 noundef %12)
  %14 = add nsw i32 %10, %13
  store i32 %14, ptr %2, align 4
  br label %15

15:                                               ; preds = %7, %6
  %16 = load i32, ptr %2, align 4    /* 2号寄存器中取出值 */ 
  ret i32 %16
}

; Function Attrs: mustprogress noinline norecurse optnone uwtable
define dso_local noundef i32 @main(i32 noundef %0, ptr noundef %1) #1 {
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca ptr, align 8
  store i32 0, ptr %3, align 4
  store i32 %0, ptr %4, align 4
  store ptr %1, ptr %5, align 8
  %6 = call noundef i32 @_Z9factoriali(i32 noundef 2)
  %7 = mul nsw i32 %6, 7
  %8 = icmp eq i32 %7, 42
  %9 = zext i1 %8 to i32
  ret i32 %9
}

attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"clang version 16.0.6 (https://github.com/llvm/llvm-project.git 7cbf1a2591520c2491aa35339f227775f4d3adf6)"}

严格类型机制,不支持任何形式的隐式转换,例如

代码语言:javascript
复制
ret i32 %16

改成 

ret i32 %5

执行opt -passes=verify --color t3.ll

代码语言:javascript
复制
$ opt -passes=verify --color t3.ll
opt: t3.ll:32:11: error: '%5' defined with type 'i1' but expected 'i32'
  ret i32 %5

2 善用语法手册

例如上面的%6 = call noundef i32 @_Z9factoriali(i32 noundef 2)函数调用语法,如何找到call的全部使用方法?

语法手册
在这里插入图片描述
在这里插入图片描述
语法
在这里插入图片描述
在这里插入图片描述
案例
在这里插入图片描述
在这里插入图片描述
递归调用案例
在这里插入图片描述
在这里插入图片描述

3 Basic Blocks:基本块

基本块在 LLVM 中起着重要的作用,它们用于进行优化、分析和代码生成。基本块可以被视为一个原子操作单元,可以在其中执行各种优化技术,例如常量传播、复制传播、死代码消除等。基本块还可以用于生成目标代码,因为它们提供了代码的基本结构。

在这里插入图片描述
在这里插入图片描述

在上面案例中:

在这里插入图片描述
在这里插入图片描述

4 callgraph

IR支持打印callgraph:

代码语言:javascript
复制
$ opt -passes=print-callgraph t3.ll

Call graph node <<null function>><<0x6e5ef20>>  #uses=0
  CS<None> calls function '_Z9factoriali'
  CS<None> calls function 'main'

Call graph node for function: '_Z9factoriali'<<0x6e63490>>  #uses=4
  CS<0x6e5df60> calls function '_Z9factoriali'
  CS<0x6e5e070> calls function '_Z9factoriali'

Call graph node for function: 'main'<<0x6e63570>>  #uses=1
  CS<0x6e5e8c0> calls function '_Z9factoriali'

5 IR遵循SSA规则

Static Single Assignment (SSA):

  • Every variable is assigned exactly once.
  • Every variable is defined before it is used.

每个变量只能赋值一次。 变量在使用前必须定义。

为什么要这么做?如果编译器遇到如下代码

代码语言:javascript
复制
 x = 100
 x = 200
 a = x

明显第一个x=100是无效的,但编译器需要去选择保留100还是200。 如果遵循SSA规则:

代码语言:javascript
复制
x1 = 100
x2 = 200
a = x2

编译器无需选择,可以直接抛弃x1的值即可。

当然这只是SSA的一个基本的使用场景,有些更复杂的优化必须基于SSA来简化场景。

5 IR结构

在这里插入图片描述
在这里插入图片描述

6 todo

用到的话继续把Tutorial-Bridgers-LLVM_IR_tutorial.pdf指针、类型部分看完。

代码语言:javascript
复制
.c -> .ll:clang -emit-llvm -S a.c -o a.ll
.c -> .bc: clang -emit-llvm -c a.c -o a.bc
.ll -> .bc: llvm-as a.ll -o a.bc
.bc -> .ll: llvm-dis a.bc -o a.ll
.bc -> .s: llc a.bc -o a.s
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 不支持类型的隐式转换
  • 2 善用语法手册
    • 语法手册
      • 语法
        • 案例
          • 递归调用案例
          • 3 Basic Blocks:基本块
          • 4 callgraph
          • 5 IR遵循SSA规则
          • 5 IR结构
          • 6 todo
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档