初始化全局变量时,Clang-4.0会生成冗余方法
clang-4.0 generates redundant methods when initializing global variables
我如今正在学习LLVM,通过观察叮当声如何处理复杂情况。我写了(最高级,而不是在功能中):
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
混淆:为什么Clang会生成一个实际上只调用另一个功能的函数(并且不做其他功能)?甚至他们两个都没有参数?
免责声明:这是我对逻辑的解释,我不是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()
中呼叫每个功能。这是有道理的,而且是明智的,因为这种方式整洁地组织了,否则可能会在更大/更复杂的文件中变成混乱。
请注意,这是您示例中所应用的逻辑的完全相同。
这样做
否则将暗示类型的算法:"如果有一个非平凡的全局初始化,然后将代码直接放入翻译单元的全局构造函数"。
请注意以下内容:
- 当前的逻辑已经正确处理了该情况。
- 在优化的代码中,最终结果将完全相同。
那么,这种逻辑真的会给我们带来什么?
- 更多的分支进行测试。
- 更多的机会偶然插入错误。
- 从长远来看可以维护的更多代码。
- 在非优化构建中某些翻译单元的全局初始化中删除单个功能调用。
以正确的方式保持事情是正确的决定。
相关文章:
- 如何擦除冗余输入?
- 使用提升几何缓冲区缩放多边形时的冗余折点
- 我应该担心冗余声明吗?
- Qt的slot(?)将冗余命名空间插入连接
- 方法冗余移动调用的移动语义
- 使用 llvm 和本地值编号算法擦除冗余表达式
- 优化堆上创建的冗余变量
- 如何消除访客模式冗余?
- 表达式模板需要冗余重载
- C++,处理多个构造函数重载和冗余代码
- 使用模板基类消除工厂类派生类冗余的干净方法
- 连接两个文件时如何避免冗余尾随换行符?
- CMake:修改共享库时的冗余链接
- 提升精神 X3:"属性没有预期的大小"冗余
- 如何简化此冗余C++代码?
- 是``if`语句''在modulo之前和分配操作之前的冗余
- 使用最终类说明符时,最终函数说明符是否冗余?
- 初始化全局变量时,Clang-4.0会生成冗余方法
- c++ noob:初始化时避免冗余对象复制的正确方法
- 如何重构冗余的getter/setter方法