swift - 仅在条件编译 block 中设置可选,编译器是否从发布版本中完全删除语句?

标签 swift assembly build

例如:

struct L {
    #if DEBUG
    static let og:((String) -> Void)? = { print($0) }
    #else
    static let og:((String) -> Void)? = nil
    #endif
}
L.og?("Howdy!")
print("Done.")

在此代码的发布版本中,Swift 编译器如何处理 L.og?("Howdy!") 行?它是否完全优化了线路?或者表达式 L.og 在运行时评估为 nil?我如何证明任一答案?

最佳答案

我想我终于回答了我自己的问题。这次修改完全取代了我之前的回答,因为我认为这是错误的。

简答

编译器优化不会删除 Release 构建中的 L.og?("Howdy!") 行。 og? 的解包仍然在运行时发生。

证明

定义“发布”

在一个典型的Xcode项目中,Release的优化是什么?在目标build设置中,它是 SWIFT_OPTIMIZATION_LEVEL = -O

方法

我在 2 个不同的程序上运行了 swiftc -emit-assembly -O

程序A:

struct L {
    #if DEBUG
    static let og:((String) -> Void)? = { print($0) }
    #else
    static let og:((String) -> Void)? = nil
    #endif
}
L.og?("Howdy!")

程序 B:

struct L {
    #if DEBUG
    static let og:((String) -> Void)? = { print($0) }
    #else
    static let og:((String) -> Void)? = nil
    #endif
}

在程序集输出中,A

中的 main
_main:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    pushq   %r13
    pushq   %rax
    .cfi_offset %r13, -24
    cmpq    $-1, _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip)
    jne LBB0_4
LBB0_1:
    movq    _$s4main1LV2ogySScSgvpZ(%rip), %rax
    testq   %rax, %rax
    je  LBB0_3
    movq    _$s4main1LV2ogySScSgvpZ+8(%rip), %r13
    movabsq $36805260308296, %rdi
    movabsq $-1873497444986126336, %rsi
    callq   *%rax
LBB0_3:
    xorl    %eax, %eax
    addq    $8, %rsp
    popq    %r13
    popq    %rbp
    retq
LBB0_4:
    leaq    _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip), %rdi
    leaq    _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0(%rip), %rsi
    callq   _swift_once
    jmp LBB0_1
    .cfi_endproc

    .p2align    4, 0x90

B:

_main:
    pushq   %rbp
    movq    %rsp, %rbp
    xorl    %eax, %eax
    popq    %rbp
    retq

    .p2align    4, 0x90

如果编译器优化掉整行 L.og?("Howdy!"),那么我希望 main 来自 B将与 A 相同。它不是。因此,编译器将其保留。

非可选结果

对于非可选的空闭包,发现了类似的结果。对 L.og("Howdy!") 的调用保留在优化的程序集中,即使调用的是一个空函数。

即:

struct L {
    #if DEBUG
    static let og:((String) -> Void) = { print($0) }
    #else
    static let og:((String) -> Void) = { _ in }
    #endif
}
L.og("Howdy!")

这是优化的 main 程序集:

_main:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    pushq   %r13
    pushq   %rax
    .cfi_offset %r13, -24
    cmpq    $-1, _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip)
    jne LBB0_1
LBB0_2:
    movq    _$s4main1LV2ogyySScvpZ+8(%rip), %r13
    movabsq $36805260308296, %rdi
    movabsq $-1873497444986126336, %rsi
    callq   *_$s4main1LV2ogyySScvpZ(%rip)
    xorl    %eax, %eax
    addq    $8, %rsp
    popq    %r13
    popq    %rbp
    retq
LBB0_1:
    leaq    _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip), %rdi
    leaq    _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0(%rip), %rsi
    callq   _swift_once
    jmp LBB0_2
    .cfi_endproc

    .p2align    4, 0x90

关于swift - 仅在条件编译 block 中设置可选,编译器是否从发布版本中完全删除语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58454708/

相关文章:

sql-server - Visual Studio团队在线服务-运行sql脚本

arrays - 找到用户坐标和坐标数组之间最近的位置

ios - Alamofire 4 和 JSON 中的特殊字符

assembly - 如何在 DOSBox 中使用汇编程序消除字符串中的空格和标点符号?

assembly - 64 位应用程序内存中的布局

Android - 使用 NDK 的 Gradle 构建

Android-NDK构建系统(构建hello-gl2)

swift - 如何将 CVImageBuffer 转换为 Unmanaged<CVImageBuffer>?

ios - 如何向具有用户身份验证的网站发出访问其内容的请求?

c - 如何从汇编指令到 C 代码