LLVM 学习(三) -样例学习
@2022-04-17 09:28:38
@sizaif
LLVM IR 样例学习
1. 基本语法
- 编写
c
代码
# hello.c
#include <stdio.h>
int add(int a,int b){
return a + b;
}
int main() {
int a = 10;
int b = 22;
printf("%d\n",add(a,b));
return 0;
}
- 将
c
源码转换为LLVM IR-ll
格式
$ clang -emit-llvm -S hello.c -o hello.ll
- 生成的
hello.ll
内容如下
; ModuleID = 'hello.c'
source_filename = "hello.c"
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"
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @add(i32 noundef %0, i32 noundef %1) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
store i32 %0, i32* %3, align 4
store i32 %1, i32* %4, align 4
%5 = load i32, i32* %3, align 4
%6 = load i32, i32* %4, align 4
%7 = add nsw i32 %5, %6
ret i32 %7
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 10, i32* %2, align 4
store i32 22, i32* %3, align 4
%4 = load i32, i32* %2, align 4
%5 = load i32, i32* %3, align 4
%6 = call i32 @add(i32 noundef %4, i32 noundef %5)
%7 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 noundef %6)
ret i32 0
}
declare dso_local i32 @printf(i8* noundef, ...) #1
attributes #0 = { noinline nounwind 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 = { "frame-pointer"="all" "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}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
注解是以 ; 分隔且直到当前行的结尾
@代表全局标识符(函数,全局变量);
%代表局部标识符(寄存器名称也就是局部变量,类型)。
alloca指令:用于分配内存堆栈给当前执行的函数,当这个函数返回其调用者时自动释放,
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @add(i32 noundef %0, i32 noundef %1) #0 {
%3 = alloca i32, align 4 ; 分配一个内存到局部变量%3,4字节对齐
%4 = alloca i32, align 4 ; 分配一个内存到局部变量%4,4字节对齐
store i32 %0, i32* %3, align 4 ; 将i32类型的变量%0存到内存%3中, 4字节对齐
store i32 %1, i32* %4, align 4 ; 将i32类型的变量%1存到内存%4中, 4字节对齐
%5 = load i32, i32* %3, align 4 ; 读取变量%3内存中的数据存放到临时变量%5中,4字节对齐
%6 = load i32, i32* %4, align 4 ; 读取变量%4内存中的数据存放到临时变量%6中,4字节对齐
%7 = add nsw i32 %5, %6 ; 将变量%5,%6中的数据进行add运算,结构存到%7中
ret i32 %7 ; 返回i32类型的%7
}
-
hello.ll
转回hello.bc
bitcode格式$ llvm-as hello.ll -o hello.bc root@0187031113b5:/home/workhome/llvm_test# ll total 20 drwxr-xr-x 2 root root 4096 Apr 17 02:09 ./ drwxr-xr-x 1 root root 4096 Apr 16 06:51 ../ -rw-r--r-- 1 root root 2456 Apr 17 02:09 hello.bc -rw-r--r-- 1 root root 142 Apr 17 02:06 hello.c -rw-r--r-- 1 root root 1838 Apr 17 02:06 hello.ll
-
执行
hello.bc
$ lli hello.bc root@0187031113b5:/home/workhome/llvm_test# lli hello.bc 32
2. if 语句
# if.c
#include <stdio.h>
int main()
{
int a = 11;
if(a%2 == 0)
return 0;
else
return 1;
}
# if.ll
; ModuleID = 'if.c'
source_filename = "if.c"
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: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 11, i32* %2, align 4
%3 = load i32, i32* %2, align 4
%4 = srem i32 %3, 2 ; srem 带符号整数求余
%5 = icmp eq i32 %4, 0 ; 比较 %4 与0 是否相等
br i1 %5, label %6, label %7 ; 分支选择,根据%5结果跳转到%6或%7
6: ; preds = %0
store i32 0, i32* %1, align 4
br label %8
7: ; preds = %0
store i32 1, i32* %1, align 4
br label %8
8: ; preds = %7, %6
%9 = load i32, i32* %1, align 4
ret i32 %9
}
attributes #0 = { noinline nounwind 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}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
- 通过
icmp
指令进行比较,产生一个结果值 br
指令根据结果值,跳转到相应的分支入口- 分支执行完成后,根据
br
无条件分支跳转到结束分支
3. While 语句
# while.c
#include <stdio.h>
int main()
{
int a = 0, b = 1;
while(a < 10)
{
a++;
b *= a;
}
return b;
}
#while.ll
; ModuleID = 'while.c'
source_filename = "while.c"
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: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 0, i32* %2, align 4
store i32 1, i32* %3, align 4
br label %4 ; 进入标签%4, 进入while循环入口
; 进入while循环入口
4: ; preds = %7, %0
%5 = load i32, i32* %2, align 4
%6 = icmp slt i32 %5, 10 ; 比较%5 小于10
br i1 %6, label %7, label %13 ; 根据%6 比较的结果分支进入%7 或%13
; while 循环 body
7: ; preds = %4
%8 = load i32, i32* %2, align 4 ; 从%2中读取值 以i32类型存到%8中
%9 = add nsw i32 %8, 1 ; %9 = %8 +1
store i32 %9, i32* %2, align 4 ; 将%9 存到%2中
%10 = load i32, i32* %2, align 4 ; 从%2中读取值 以i32类型存到%10中
%11 = load i32, i32* %3, align 4 ; 从%3中读取值 以i32类型存到%11中
%12 = mul nsw i32 %11, %10 ; %12 = %11 * %10
store i32 %12, i32* %3, align 4 ; 将%12 存到%3中
br label %4, !llvm.loop !4
13: ; preds = %4
%14 = load i32, i32* %3, align 4
ret i32 %14
}
attributes #0 = { noinline nounwind 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}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
!4 = distinct !{!4, !5}
!5 = !{!"llvm.loop.mustprogress"}
- 通过
icmp
指令进行循环条件比较 - 通过
br
指令进行控制跳转 loop
循环,直到 跳出到while.end
4. for 语句
#for.c
#include <stdio.h>
int main(){
int i = 1;
int a = 0;
for(; i <= 50; i++){
a += i;
}
printf("%d\n",a);
return 0;
}
#for.ll
; ModuleID = 'for.c'
source_filename = "for.c"
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"
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 1, i32* %2, align 4
store i32 0, i32* %3, align 4
br label %4 ; 跳转到for循环入口
; for 循环入口
4: ; preds = %11, %0
%5 = load i32, i32* %2, align 4
%6 = icmp sle i32 %5, 50
br i1 %6, label %7, label %14 ; 循环loop控制
; for 循环 body
7: 1 ; preds = %4
%8 = load i32, i32* %2, align 4
%9 = load i32, i32* %3, align 4
%10 = add nsw i32 %9, %8
store i32 %10, i32* %3, align 4
br label %11
; for 循环 第三部分操作
11: ; preds = %7
%12 = load i32, i32* %2, align 4
%13 = add nsw i32 %12, 1
store i32 %13, i32* %2, align 4
br label %4, !llvm.loop !4
14: ; preds = %4
%15 = load i32, i32* %3, align 4
%16 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 noundef %15)
ret i32 0
}
declare dso_local i32 @printf(i8* noundef, ...) #1
attributes #0 = { noinline nounwind 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 = { "frame-pointer"="all" "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}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
!4 = distinct !{!4, !5}
!5 = !{!"llvm.loop.mustprogress"}
if
,for
,while
三个结构类型, 即 条件判断+循环控制
5. Switch
#switch.c
#include <stdio.h>
int main(){
int i = 1;
int a = 0;
for(; i <= 50; i++){
a += i;
switch(a){
case 15:
printf("a = 25, i = %d\n ",i);
break;
case 105:
printf("a = 105, i= %d\n ",i);
break;
case 990:
printf("a = 990, i = %d\n ",i);
break;
}
}
printf("%d\n",a);
return 0;
}
#switch.ll
; ModuleID = 'switch.c'
source_filename = "switch.c"
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"
@.str = private unnamed_addr constant [18 x i8] c"a = 25, i = %d\0A \00", align 1
@.str.1 = private unnamed_addr constant [19 x i8] c"a = 105, i= %d\0A \00", align 1
@.str.2 = private unnamed_addr constant [19 x i8] c"a = 990, i = %d\0A \00", align 1
@.str.3 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 1, i32* %2, align 4
store i32 0, i32* %3, align 4
br label %4 ; 进入for循环入口
# for循环入口
4: ; preds = %22, %0
%5 = load i32, i32* %2, align 4
%6 = icmp sle i32 %5, 50
br i1 %6, label %7, label %25
; for循环 body
7: ; preds = %4
%8 = load i32, i32* %2, align 4
%9 = load i32, i32* %3, align 4
%10 = add nsw i32 %9, %8
store i32 %10, i32* %3, align 4
%11 = load i32, i32* %3, align 4
switch i32 %11, label %21 [ ; switch 判断a
i32 15, label %12
i32 105, label %15
i32 990, label %18
]
; label %12
12: ; preds = %7
%13 = load i32, i32* %2, align 4
%14 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([18 x i8], [18 x i8]* @.str, i64 0, i64 0), i32 noundef %13)
br label %21
; label %12
15: ; preds = %7
%16 = load i32, i32* %2, align 4
%17 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([19 x i8], [19 x i8]* @.str.1, i64 0, i64 0), i32 noundef %16)
br label %21
; label %12
18: ; preds = %7
%19 = load i32, i32* %2, align 4
%20 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([19 x i8], [19 x i8]* @.str.2, i64 0, i64 0), i32 noundef %19)
br label %21
21: ; preds = %7, %18, %15, %12
br label %22
; for 循环尾部+1
22: ; preds = %21
%23 = load i32, i32* %2, align 4
%24 = add nsw i32 %23, 1
store i32 %24, i32* %2, align 4
br label %4, !llvm.loop !4
25: ; preds = %4
%26 = load i32, i32* %3, align 4
%27 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i64 0, i64 0), i32 noundef %26)
ret i32 0
}
declare dso_local i32 @printf(i8* noundef, ...) #1
attributes #0 = { noinline nounwind 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 = { "frame-pointer"="all" "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}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
!4 = distinct !{!4, !5}
!5 = !{!"llvm.loop.mustprogress"}
6. 结构体
//struct.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
struct People{
char *num;
int age;
char name[10];
};
struct Class{
int id;
struct People people;
};
int main(){
struct Class class;
class.id = 1;
class.people.num = "211501";
class.people.age = 22;
strcpy(class.people.name, "test");
printf("id = %d ; age = %d ; num = %s; name = %s\n",class.id,class.people.age,class.people.num,class.people.name);
return 0;
}
可读struct.ll
文件
; ModuleID = 'struct.c'
source_filename = "struct.c"
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"
%struct.Class = type { i32, %struct.People }
%struct.People = type { i8*, i32, [10 x i8] } ; i32类型 10*i8的空间
@.str = private unnamed_addr constant [7 x i8] c"211501\00", align 1
@.str.1 = private unnamed_addr constant [5 x i8] c"test\00", align 1
@.str.2 = private unnamed_addr constant [42 x i8] c"id = %d ; age = %d ; num = %s; name = %s\0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca %struct.Class, align 8 ; 分配%struct.Class空间给%2
store i32 0, i32* %1, align 4
; 指令来获得指向数组的元素和指向结构体成员的指针
; 获取class第一个成员的指针给%3 即 int id;
%3 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 0
; 分配1给指针%3 即 class.id = 1
store i32 1, i32* %3, align 8
; 获取class的第二个成员指针给%4 即 struct People people;
%4 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
; 获取class.people结构体的第一个成员指针给%5
%5 = getelementptr inbounds %struct.People, %struct.People* %4, i32 0, i32 0
; 分配@.str的内容给%5 即 class.people.num = "211501";
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0), i8** %5, align 8
; 获取class结构体的第二个成员指针给%6 即 struct People people;
%6 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
; 获取class.people结构体的第二个成员指针给%7 即 int age;
%7 = getelementptr inbounds %struct.People, %struct.People* %6, i32 0, i32 1
; 分配 22 给 %7 指针指向地址 即 class.people.age = 22;
store i32 22, i32* %7, align 8
; 获取class结构体的第二个成员指针给%8 即 struct People people;
%8 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
; 获取class.people结构体的第三个成员指针给%9 即 char name[10];;
%9 = getelementptr inbounds %struct.People, %struct.People* %8, i32 0, i32 2
; 获取%9指针指向的第一个地址
%10 = getelementptr inbounds [10 x i8], [10 x i8]* %9, i64 0, i64 0
; 调用strcpy函数 分配@.str.1
%11 = call i8* @strcpy(i8* noundef %10, i8* noundef getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0)) #3
; 为了输出printf 做准备
%12 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 0
%13 = load i32, i32* %12, align 8
%14 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
%15 = getelementptr inbounds %struct.People, %struct.People* %14, i32 0, i32 1
%16 = load i32, i32* %15, align 8
%17 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
%18 = getelementptr inbounds %struct.People, %struct.People* %17, i32 0, i32 0
%19 = load i8*, i8** %18, align 8
%20 = getelementptr inbounds %struct.Class, %struct.Class* %2, i32 0, i32 1
%21 = getelementptr inbounds %struct.People, %struct.People* %20, i32 0, i32 2
%22 = getelementptr inbounds [10 x i8], [10 x i8]* %21, i64 0, i64 0
%23 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([42 x i8], [42 x i8]* @.str.2, i64 0, i64 0), i32 noundef %13, i32 noundef %16, i8* noundef %19, i8* noundef %22)
ret i32 0
}
; Function Attrs: nounwind
declare dso_local i8* @strcpy(i8* noundef, i8* noundef) #1
declare dso_local i32 @printf(i8* noundef, ...) #2
attributes #0 = { noinline nounwind 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 = { nounwind "frame-pointer"="all" "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 #2 = { "frame-pointer"="all" "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 #3 = { nounwind }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}
结构体和数组需要现使用getelementptr
获取指向数组或结构成员的指针,然后根据指针指向的内容进行赋值或做运算
7. 牛刀小试
//main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
puts("plz input two numbers");
size_t bufsize = 100;
char* buf = malloc(bufsize);
getline(&buf, &bufsize, stdin);
double f1 = atof(buf);
getline(&buf, &bufsize, stdin);
double f2 = atof(buf);
printf("%.2f + %.2f = %.2f \n", f1, f2, f1+f2);
free(buf);
return 0;
}
转换成可读 ll
文件
$ clang -emit-llvm -S main.c -o main.ll
; ModuleID = 'main.c'
source_filename = "main.c"
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"
%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
%struct._IO_marker = type opaque
%struct._IO_codecvt = type opaque
%struct._IO_wide_data = type opaque
@.str = private unnamed_addr constant [22 x i8] c"plz input two numbers\00", align 1
@stdin = external dso_local global %struct._IO_FILE*, align 8
@.str.1 = private unnamed_addr constant [21 x i8] c"%.2f + %.2f = %.2f \0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4 ; 分配空间
%2 = alloca i64, align 8 ; 分配空间
%3 = alloca i8*, align 8 ; 分配空间
%4 = alloca double, align 8 ; 分配空间
%5 = alloca double, align 8 ; 分配空间
store i32 0, i32* %1, align 4 ; 分配默认值0
; 调用输出
%6 = call i32 @puts(i8* noundef getelementptr inbounds ([22 x i8], [22 x i8]* @.str, i64 0, i64 0))
store i64 100, i64* %2, align 8 ; 存储100 到 i64指针%2
%7 = load i64, i64* %2, align 8
%8 = call noalias i8* @malloc(i64 noundef %7) #4 ; 动态分配内存大小为%7的空间
store i8* %8, i8** %3, align 8 ; 将分配的空间存到%3指针
%9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
; 输入的%9
%10 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %9)
%11 = load i8*, i8** %3, align 8
%12 = call double @atof(i8* noundef %11) #5
store double %12, double* %4, align 8
%13 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
%14 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %13)
%15 = load i8*, i8** %3, align 8
%16 = call double @atof(i8* noundef %15) #5
store double %16, double* %5, align 8
%17 = load double, double* %4, align 8
%18 = load double, double* %5, align 8
%19 = load double, double* %4, align 8
%20 = load double, double* %5, align 8
%21 = fadd double %19, %20
%22 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([21 x i8], [21 x i8]* @.str.1, i64 0, i64 0), double noundef %17, double noundef %18, double noundef %21)
%23 = load i8*, i8** %3, align 8
call void @free(i8* noundef %23) #4
ret i32 0
}
declare dso_local i32 @puts(i8* noundef) #1
; Function Attrs: nounwind
declare dso_local noalias i8* @malloc(i64 noundef) #2
declare dso_local i64 @getline(i8** noundef, i64* noundef, %struct._IO_FILE* noundef) #1
; Function Attrs: nounwind readonly willreturn
declare dso_local double @atof(i8* noundef) #3
declare dso_local i32 @printf(i8* noundef, ...) #1
; Function Attrs: nounwind
declare dso_local void @free(i8* noundef) #2
attributes #0 = { noinline nounwind 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 = { "frame-pointer"="all" "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 #2 = { nounwind "frame-pointer"="all" "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 #3 = { nounwind readonly willreturn "frame-pointer"="all" "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 #4 = { nounwind }
attributes #5 = { nounwind readonly willreturn }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}