代码之家  ›  专栏  ›  技术社区  ›  0xdeadbeef

未启用优化标志时gcc内联程序集编译错误?

  •  0
  • 0xdeadbeef  · 技术社区  · 2 年前

    我已经学习内联汇编将近一个月了,作为另一个实践问题,我正在尝试总结两个问题 uint512 使用内联汇编,一开始我得到了我想要的,代码经过编译,我能够用下面的代码得到正确的结果。尽管在这之前,我只是用优化标志编译我的程序-O2和-O3。

    但当我试图删除编译标志中的-O1、-O2或-O3时,它会产生一个编译错误 error: 'asm' operand has impossible constraints , 这可能是什么原因?

    我假设因为优化被禁用,程序实际上试图使用比我的CPU更多的寄存器?。但我只使用了8个寄存器(或者可能不再使用了?),我的输入是否存储在另外8个寄存器中?

    // uint512 += uint512
    void uint512_add(unsigned long *sum, unsigned long *add) {
        asm volatile(
            "add %[adn0], %[sum0]\n\t"
            "adc %[adn1], %[sum1]\n\t"
            "adc %[adn2], %[sum2]\n\t"
            "adc %[adn3], %[sum3]\n\t"
            "adc %[adn4], %[sum4]\n\t"
            "adc %[adn5], %[sum5]\n\t"
            "adc %[adn6], %[sum6]\n\t"
            "adc %[adn7], %[sum7]"
            :
            [sum0]"+r"(sum[0]), [sum1]"+r"(sum[1]),
            [sum2]"+r"(sum[2]), [sum3]"+r"(sum[3]),
            [sum4]"+r"(sum[4]), [sum5]"+r"(sum[5]),
            [sum6]"+r"(sum[6]), [sum7]"+r"(sum[7])
            :
            [adn0]"m"(add[0]), [adn1]"m"(add[1]),
            [adn2]"m"(add[2]), [adn3]"m"(add[3]),
            [adn4]"m"(add[4]), [adn5]"m"(add[5]),
            [adn6]"m"(add[6]), [adn7]"m"(add[7])
            : "memory", "cc"
        );
    }
    
    1 回复  |  直到 2 年前
        1
  •  1
  •   Peter Cordes    2 年前

    如果删除一些操作数,比如只进行256位加法,您会注意到 禁用优化后,GCC希望将一个指针直接指向单独寄存器中的每个内存操作数 ,而不是为它们中的每一个发明相对于同一个基址的寻址模式。所以它的寄存器用完了。(见本章中间部分) Strange 'asm' operand has impossible constraints error 用于演示此功能的编译器输出。)

    你可能想要 __attribute__((optimize("-O3"))) 在这个函数或其他函数上,这样它就不会阻止程序的其他部分编译。


    而且,这不需要“记忆”重击器;你不写任何记忆,你只通过 "m" 操作数。它也不需要是易变的:它除了编写代码之外没有任何副作用 "+r" 输入/输出寄存器。除了 sum7 从技术上讲,这些应该是 "+&r" 早期的clobber操作数,因为您在读取所有输入和输入输出操作数之前写入它们,但GCC基本上没有合理的方式来重叠指针和整数输入/输出之间的寄存器。

    你也可以让编译器选择 "mre" 而不是强制内存源操作数,即使源操作数是编译时常量或在寄存器中。但是,如果这使得它为您的实际用例生成了更糟糕的asm(例如,单独 mov 加载到regs而不是内存源中 adc )那也许 "me" () "e" constraint 就像 "i" 但只允许适合32位有符号整数的常数,即安全地用作64位操作数大小的立即数,用于除 压敏电阻 .)


    顺便说一句,对于clang(但不是GCC),您根本不需要内联asm:使用 typedef unsigned _ExtInt(512) uint512; -看到了吗 256-bit arithmetic in Clang (extended integers)