O'Neill의 PCG PRNG를 구현하는 동안 GCC에서 버그를 발견했다고 생각합니다. ( Godbolt의 컴파일러 탐색기의 초기 코드 )
승산 후, oldstate
로 MULTIPLIER
(RDI에 저장된 결과), GCC는 해당 결과를 추가하지 않는다 INCREMENT
movabs'ing, INCREMENT
다음 rand32_ret.state의 반환 값으로서 사용 도착하는 대신 RDX 할
최소한의 재현 가능한 예 ( Compiler Explorer ) :
#include <stdint.h>
struct retstruct {
uint32_t a;
uint64_t b;
};
struct retstruct fn(uint64_t input)
{
struct retstruct ret;
ret.a = 0;
ret.b = input * 11111111111 + 111111111111;
return ret;
}
생성 된 어셈블리 (GCC 9.2, x86_64, -O3) :
fn:
movabs rdx, 11111111111 # multiplier constant (doesn't fit in imm32)
xor eax, eax # ret.a = 0
imul rdi, rdx
movabs rdx, 111111111111 # add constant; one more 1 than multiplier
# missing add rdx, rdi # ret.b=... that we get with clang or older gcc
ret
# returns RDX:RAX = constant 111111111111 : 0
# independent of input RDI, and not using the imul result it just computed
흥미롭게도 두 멤버를 uint64_t로 변경하는 것처럼 첫 번째 멤버로 uint64_t를 갖도록 구조체를 수정 하면 올바른 코드가 생성 됩니다.
x86-64 System V는 사소한 복사가 가능한 RDX : RAX에서 16 바이트보다 작은 구조체를 반환합니다. 이 경우 RAX의 절반이 정렬을위한 패딩이거나 좁은 유형일 .b
때 두 번째 멤버가 RDX에 .a
있습니다. ( 어쨌든 sizeof(retstruct)
16입니다; 우리는 사용하지 않으므로 __attribute__((packed))
alignof (uint64_t) = 8을 존중합니다.)
이 코드에 GCC가 "잘못된"어셈블리를 생성 할 수있는 정의되지 않은 동작이 포함되어 있습니까?
그렇지 않은 경우 https://gcc.gnu.org/bugzilla/ 에보고되어야합니다.