Compiler construction 如何在LLVM中演示冗余删除?
我想演示一下LLVM中使用了冗余删除 我从opt中找到了选项-gvn(全局值编号)。我测试了以下示例:Compiler construction 如何在LLVM中演示冗余删除?,compiler-construction,clang,llvm,compiler-optimization,llvm-clang,Compiler Construction,Clang,Llvm,Compiler Optimization,Llvm Clang,我想演示一下LLVM中使用了冗余删除 我从opt中找到了选项-gvn(全局值编号)。我测试了以下示例: int foo(int a, int b) { int c, d, e, f, g; c = a + b; d = a + b; e = a; f = e + b; g = c + d + e + f; return f; } 通过这些程序: clang -S -emit-llvm eg.c llvm-as eg.ll opt -g
int foo(int a, int b) {
int c, d, e, f, g;
c = a + b;
d = a + b;
e = a;
f = e + b;
g = c + d + e + f;
return f;
}
通过这些程序:
clang -S -emit-llvm eg.c
llvm-as eg.ll
opt -gvn eg.ll -o eg_opt.ll
但是,我观察到与以前相同的add操作数
莱尔
例如
define i32 @foo(i32 %a, i32 %b) #0 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
%e = alloca i32, align 4
%f = alloca i32, align 4
%g = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
%0 = load i32, i32* %a.addr, align 4
%add = add nsw i32 %0, %b
store i32 %add, i32* %c, align 4
%1 = load i32, i32* %a.addr, align 4
%2 = load i32, i32* %b.addr, align 4
%add1 = add nsw i32 %1, %2
store i32 %add1, i32* %d, align 4
%3 = load i32, i32* %a.addr, align 4
store i32 %3, i32* %e, align 4
%4 = load i32, i32* %b.addr, align 4
%add2 = add nsw i32 %3, %4
store i32 %add2, i32* %f, align 4
%5 = load i32, i32* %c, align 4
%6 = load i32, i32* %d, align 4
%add3 = add nsw i32 %5, %6
%7 = load i32, i32* %e, align 4
%add4 = add nsw i32 %add3, %7
%add5 = add nsw i32 %add4, %add2
store i32 %add5, i32* %g, align 4
%8 = load i32, i32* %f, align 4
ret i32 %8
}
我错过什么了吗?我想你要的是
-instcombine
通行证。使用-instcombine
优化您的代码将导致以下IR
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = add nsw i32 %a, %b
ret i32 %1
}
Instcombine尝试从IR中删除尽可能多的冗余指令
编辑:
但是如果你想使用gvn,你必须首先把你的IR变成一个“更好”的SSA形式
使用-mem2reg
将您的IR变成完美的SSA形式:
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = add nsw i32 %a, %b
%2 = add nsw i32 %a, %b
%3 = add nsw i32 %a, %b
%4 = add nsw i32 %1, %2
%5 = add nsw i32 %4, %a
%6 = add nsw i32 %5, %3
ret i32 %3
}
现在使用-gvn
可以减少冗余的添加指令:
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = add nsw i32 %a, %b
%2 = add nsw i32 %1, %1
%3 = add nsw i32 %2, %a
%4 = add nsw i32 %3, %1
ret i32 %1
}
Edit2:
根据lazyCoder的评论:通过别名分析支持-gvn
,也会导致冗余消除:
首先使用-basica
会产生以下IR:
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
%e = alloca i32, align 4
%f = alloca i32, align 4
%g = alloca i32, align 4
store i32 %a, i32* %1, align 4
store i32 %b, i32* %2, align 4
%3 = load i32, i32* %1, align 4
%4 = load i32, i32* %2, align 4
%5 = add nsw i32 %3, %4
store i32 %5, i32* %c, align 4
%6 = load i32, i32* %1, align 4
%7 = load i32, i32* %2, align 4
%8 = add nsw i32 %6, %7
store i32 %8, i32* %d, align 4
%9 = load i32, i32* %1, align 4
store i32 %9, i32* %e, align 4
%10 = load i32, i32* %e, align 4
%11 = load i32, i32* %2, align 4
%12 = add nsw i32 %10, %11
store i32 %12, i32* %f, align 4
%13 = load i32, i32* %c, align 4
%14 = load i32, i32* %d, align 4
%15 = add nsw i32 %13, %14
%16 = load i32, i32* %e, align 4
%17 = add nsw i32 %15, %16
%18 = load i32, i32* %f, align 4
%19 = add nsw i32 %17, %18
store i32 %19, i32* %g, align 4
%20 = load i32, i32* %f, align 4
ret i32 %20
}
然后是-gvn
结果:
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
%e = alloca i32, align 4
%f = alloca i32, align 4
%g = alloca i32, align 4
store i32 %a, i32* %1, align 4
store i32 %b, i32* %2, align 4
%3 = add nsw i32 %a, %b
store i32 %3, i32* %c, align 4
store i32 %3, i32* %d, align 4
store i32 %a, i32* %e, align 4
store i32 %3, i32* %f, align 4
%4 = add nsw i32 %3, %3
%5 = add nsw i32 %4, %a
%6 = add nsw i32 %5, %3
store i32 %6, i32* %g, align 4
ret i32 %3
}
保存加载和存储的位置。是否尝试使用-basica?如果没有别名分析,它将不会触及那些负载存储。或者,更好的是,使用mem2reg获取SSA。它不仅更有可能被优化,而且更容易遵循。
define i32 @foo(i32 %a, i32 %b) #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
%e = alloca i32, align 4
%f = alloca i32, align 4
%g = alloca i32, align 4
store i32 %a, i32* %1, align 4
store i32 %b, i32* %2, align 4
%3 = add nsw i32 %a, %b
store i32 %3, i32* %c, align 4
store i32 %3, i32* %d, align 4
store i32 %a, i32* %e, align 4
store i32 %3, i32* %f, align 4
%4 = add nsw i32 %3, %3
%5 = add nsw i32 %4, %a
%6 = add nsw i32 %5, %3
store i32 %6, i32* %g, align 4
ret i32 %3
}