代码之家  ›  专栏  ›  技术社区  ›  ice1000

clang-4.0在初始化全局变量时生成冗余方法

  •  3
  • ice1000  · 技术社区  · 7 年前

    int qaq = 666;
    int tat = 233;
    
    auto hh = qaq + tat;
    

    我使用命令:

    clang-4.0 003.cpp -emit-llvm -S -std=c++11
    

    clang生成如下代码:

    @qaq = global i32 666, align 4
    @tat = global i32 233, align 4
    @hh = global i32 0, align 4
    @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_003.cpp, i8* null }]
    
    ; Function Attrs: noinline uwtable
    define internal void @__cxx_global_var_init() #0 section ".text.startup" {
      %1 = load i32, i32* @qaq, align 4
      %2 = load i32, i32* @tat, align 4
      %3 = add nsw i32 %1, %2
      store i32 %3, i32* @hh, align 4
      ret void
    }
    
    ; Function Attrs: noinline uwtable
    define internal void @_GLOBAL__sub_I_003.cpp() #0 section ".text.startup" {
      call void @__cxx_global_var_init()
      ret void
    }
    

    我被搞糊涂了 _GLOBAL__sub_I_003.cpp

    1 回复  |  直到 7 年前
        1
  •  3
  •   user4442671 user4442671    7 年前

    免责声明:这是我对逻辑的解释,我不是LLVM团队的一员。

    为了理解其背后的原因,您必须理解软件工程中的一个基本概念:

    但首先,让我们让你的例子更有趣一点:

    int qaq = 666;
    int tat = 233;
    
    auto hh = qaq + tat;
    auto ii = qaq - tat;
    

    ; Function Attrs: noinline uwtable
    define internal void @__cxx_global_var_init() #0 section ".text.startup" !dbg !16 {
      %1 = load i32, i32* @qaq, align 4, !dbg !19
      %2 = load i32, i32* @tat, align 4, !dbg !20
      %3 = add nsw i32 %1, %2, !dbg !21
      store i32 %3, i32* @hh, align 4, !dbg !21
      ret void, !dbg !20
    }
    
    ; Function Attrs: noinline uwtable
    define internal void @__cxx_global_var_init.1() #0 section ".text.startup" !dbg !22 {
      %1 = load i32, i32* @qaq, align 4, !dbg !23
      %2 = load i32, i32* @tat, align 4, !dbg !24
      %3 = sub nsw i32 %1, %2, !dbg !25
      store i32 %3, i32* @ii, align 4, !dbg !25
      ret void, !dbg !24
    }
    
    ; Function Attrs: noinline uwtable
    define internal void @_GLOBAL__sub_I_example.cpp() #0 section ".text.startup" !dbg !26 {
      call void @__cxx_global_var_init(), !dbg !28
      call void @__cxx_global_var_init.1(), !dbg !29
      ret void
    }
    

    我们看到,CLANG为每个非平凡初始化发出一个函数,并在 _GLOBAL__sub_I_example.cpp()

    请注意,这与您的示例中应用的逻辑完全相同。

    否则将意味着一种类型的算法:“如果存在单个非平凡的全局初始化,则将代码直接放入翻译单元的全局构造函数中”。

    注意以下几点:

    那么,这种逻辑会给我们带来什么呢?

    • 更多分支需要测试。
    • 从长远来看,需要维护更多的代码。
    • 在非优化构建中,在某些翻译单元的全局初始化中删除单个函数调用。

    保持现状才是正确的决定。