【问题标题】:Clang optimisation breaks code?Clang优化会破坏代码?
【发布时间】:2015-12-24 12:30:47
【问题描述】:

我已经尝试准备最小可行的代码示例:

#include <stdio.h>
#include <inttypes.h>
#include <string.h>

typedef struct FECPUFlags {
    uint16_t CF:1; // carry flag
    uint16_t PF:1; // parity flag
    uint16_t AF:1; // adjust flag
    uint16_t ZF:1; // zero flag
    uint16_t SF:1; // sign flag
    uint16_t TF:1; // trap flag
    uint16_t IF:1; // interrupt enable flag
    uint16_t DF:1; // direction flag
    uint16_t OF:1; // overflow flag
} FECPUFlags;

uint16_t fe_cpuflags_16(FECPUFlags cpuRegister) {
    uint16_t result = 0;

    result = result | cpuRegister.CF;
    result = result | (cpuRegister.PF << 2);
    result = result | (cpuRegister.AF << 4);
    result = result | (cpuRegister.ZF << 6);
    result = result | (cpuRegister.SF << 7);
    result = result | (cpuRegister.DF << 10);
    result = result | (cpuRegister.OF << 11);

    return result;
}

int main() {
    FECPUFlags flag;
#define ENUM(F) for(int i=0;i<=1;i++,flag.F=i)

    ENUM(CF) ENUM(PF) ENUM(AF) ENUM(ZF) ENUM(SF) ENUM(DF) ENUM(OF) {
        printf("0x%X\n",fe_cpuflags_16(flag));
    }

    return 0;
}

叮当版本

Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.0.0

应用程序的输出因优化模式而异。铿锵 -O0 与铿锵 -O3。

这里是优化版的disasm

_fe_cpuflags_16:
0000000100000d70        pushq   %rbp
0000000100000d71        movq    %rsp, %rbp
0000000100000d74        movl    %edi, %eax
0000000100000d76        andl    $0x1, %eax
0000000100000d79        leal    (%rdi,%rdi), %ecx
0000000100000d7c        andl    $0x4, %ecx
0000000100000d7f        orl     %eax, %ecx
0000000100000d81        leal    (,%rdi,4), %eax
0000000100000d88        andl    $0x10, %eax
0000000100000d8b        orl     %ecx, %eax
0000000100000d8d        shll    $0x3, %edi
0000000100000d90        movl    %edi, %ecx
0000000100000d92        andl    $0x40, %ecx
0000000100000d95        orl     %eax, %ecx
0000000100000d97        movl    %edi, %eax
0000000100000d99        andl    $0x80, %eax
0000000100000d9e        orl     %ecx, %eax
0000000100000da0        movl    %edi, %ecx
0000000100000da2        andl    $0x400, %ecx            ## imm = 0x400
0000000100000da8        orl     %eax, %ecx
0000000100000daa        andl    $0x800, %edi            ## imm = 0x800
0000000100000db0        orl     %ecx, %edi
0000000100000db2        movzwl  %di, %eax
0000000100000db5        popq    %rbp
0000000100000db6        retq

有趣的是,如果我在枚举之前将 memset 置零 - 代码可以正常工作。

什么样的优化可能会破坏这段代码?或者这段代码可能已经以某种方式被破坏了?

【问题讨论】:

  • “优化破坏代码” - 是的,这是 UB 的明确标志。
  • @KarolyHorvath 只是想了解我做错了什么。枚举确保我感兴趣的所有标志都已初始化。即使我手动初始化未使用的 TF/IF - 优化的应用程序仍然会给出不同的结果。
  • "枚举确保我感兴趣的所有标志都已初始化。" - 不。
  • 只有 TF/IF 未初始化。但正如我已经写过的——TF/IF 的事先初始化并没有给出任何结果。但是完整的 memset 标志确实提供了正确的结果。

标签: c optimization clang compiler-optimization


【解决方案1】:

您正在使用您的 FECPUFlags flag; 而不对其进行初始化。

这是undefined behavior。任何事情都有可能发生。

【讨论】:

  • 枚举确保我感兴趣的每个标志都被初始化
  • @AlexanderSmirnov 不,它没有。 for(int i=0;i&lt;=1;i++,flag.F=i) 在循环体执行后设置它的值。例如只有在执行完所有其他循环后才设置 CF。
【解决方案2】:

你有一个未初始化的变量,稍后会访问它,所以你有未定义的行为。

FECPUFlags flag;

(某些)标志的初始化仅在循环的第二次执行中发生:

#define ENUM(F) for(int i=0;i<=1;i++,flag.F=i)
                                     ^^^

【讨论】:

    猜你喜欢
    • 2012-08-12
    • 2016-04-22
    • 1970-01-01
    • 2016-12-12
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2022-07-05
    相关资源
    最近更新 更多