【问题标题】:How to demo redundancy removal in LLVM?如何演示 LLVM 中的冗余删除?
【发布时间】:2016-02-28 20:19:19
【问题描述】:

我想演示 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 -gvn eg.ll -o eg_opt.ll

但是,我观察到 add 操作的数量与以前相同。

例如.ll

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
  %1 = load i32, i32* %b.addr, align 4
  %add = add nsw i32 %0, %1
  store i32 %add, i32* %c, align 4
  %2 = load i32, i32* %a.addr, align 4
  %3 = load i32, i32* %b.addr, align 4
  %add1 = add nsw i32 %2, %3
  store i32 %add1, i32* %d, align 4
  %4 = load i32, i32* %a.addr, align 4
  store i32 %4, i32* %e, align 4
  %5 = load i32, i32* %e, align 4
  %6 = load i32, i32* %b.addr, align 4
  %add2 = add nsw i32 %5, %6
  store i32 %add2, i32* %f, align 4
  %7 = load i32, i32* %c, align 4
  %8 = load i32, i32* %d, align 4
  %add3 = add nsw i32 %7, %8
  %9 = load i32, i32* %e, align 4
  %add4 = add nsw i32 %add3, %9
  %10 = load i32, i32* %f, align 4
  %add5 = add nsw i32 %add4, %10
  store i32 %add5, i32* %g, align 4
  %11 = load i32, i32* %f, align 4
  ret i32 %11
}

eg_opt.ll

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
}

我错过了什么吗?

【问题讨论】:

  • 您是否尝试过使用-basicaa?如果没有别名分析,它不会触及那些负载存储。
  • 或者,更好的是,使用 mem2reg 获取 SSA。它不仅更有可能被优化,而且更容易遵循。

标签: compiler-construction clang llvm compiler-optimization llvm-clang


【解决方案1】:

我认为-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
 }

编辑2:

来自lazyCoder 的评论:通过别名分析支持-gvn 也会导致冗余删除:

首先使用 -basicaa 会产生以下 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
}

保存加载和存储的位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-17
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    相关资源
    最近更新 更多