csapp 3.11이다
3.11 부동소수점 코드
대충 부동소수점에 대해 알아본다는 내용이다 + 역사랑
3.11.1 부동소수점 이동 및 변환
- 이동:
vmovss
, vmovsd
(메모리↔XMM), vmovaps
, vmovapd
(XMM↔XMM, 정렬 시 예외 주의)
- 변환:
- 부동소수점→정수:
vcvttss2si(q)
, vcvttsd2si(q)
(절단)
- 정수→부동소수점:
vcvtsi2ss(q)
, vcvtsi2sd(q)
(3-피연산자 형식)
- float↔double 변환에 GCC가 두 단계 명령(
vunpcklps
+vcvtps2pd
등)을 생성하는 경우 있음
- 예제 코드에서 레지스터 간 이동, 메모리 전송, 타입 변환이 혼합됨.
요점: 부동소수점 값은 스칼라 이동 명령으로 메모리↔레지스터 간 전송, 변환 명령으로 타입 변경.
3.11.2 프로시저에서의 부동소수점 인자
- 최대 8개의 부동소수점 인자를
%xmm0
~%xmm7
로 전달
- 반환값은
%xmm0
- caller-saved: 호출된 함수가 XMM 레지스터를 보존하지 않음
- 정수/포인터는 범용 레지스터, 부동소수점은 XMM에 배치 → 타입과 순서에 따라 매핑 달라짐
요점: 부동소수점 인자·결과는 XMM 레지스터 사용, 모두 caller-saved.
3.11.3 부동소수점 산술 연산
vadd*
, vsub*
, vmul*
, vdiv*
, vmax*
, vmin*
, sqrt*
(단정도/배정도 버전 존재)
- 첫 소스는 XMM/메모리, 두 번째·목적지는 XMM
- 예제에서 int→double 변환(
vcvtsi2sd
)과 float→double 변환(vunpcklps
+vcvtps2pd
) 사용
요점: 스칼라 산술 명령은 정수 연산과 비슷한 형식, float/double별 버전 존재.
3.11.4 부동소수점 상수
- AVX 부동소수점 연산은 즉시 값(immediate) 사용 불가
- 상수는 메모리에 저장 후 로드 (
.long
2개로 64비트 double 표현)
- 리틀 엔디언이므로 하위 4바이트, 상위 4바이트 순서로 저장
요점: 부동소수점 상수는 코드에 직접 못 넣고, 메모리에 저장해 불러온다.
3.11.5 비트 연산 활용
vxorps
, vandps
, vorps
등 패킹된 데이터 전체에 비트 연산 수행
- 스칼라 데이터에서는 하위 4·8바이트에만 의미
- NaN 생성, 부호 반전 등 간단한 값 조작에 유용
요점: XMM 비트 연산으로 부동소수점 값의 비트 패턴을 간단히 변경 가능.
3.11.6 부동소수점 비교
ucomiss
(float), ucomisd
(double) → S2−S1 비교, ZF/CF/PF 설정
- PF=1이면 NaN 존재 (C 규칙상 NaN 포함 비교는 false)
- ZF=1 → 같음, CF=1 → S2<S1, 나머지 조합으로 크기 판단
- 예제
find_range
함수: NEG/ZERO/POS/OTHER(NaN) 분류
요점: 부동소수점 비교는 조건 코드(ZF, CF, PF) 활용, NaN 판별은 PF로.
3.11.7 관찰
- AVX2 부동소수점 코드는 정수 코드와 구조 유사: 레지스터 활용, 인자 전달 규약 동일
- 데이터 타입 혼합 규칙·명령어 형식이 더 다양
- 패킹 데이터 병렬 연산으로 성능 향상 가능
- 자동 벡터화는 아직 제한적 → GCC 벡터 확장 사용 권장
요점: 구조는 비슷하지만, AVX2는 다양한 형식과 병렬성 지원으로 활용 범위 넓음.
간략 정리
- 3.11.1: 이동·변환 명령으로 메모리↔XMM 간 데이터 전송 및 타입 변경
- 3.11.2: 부동소수점 인자·반환은 XMM 사용, 모두 caller-saved
- 3.11.3: 스칼라 산술 명령 float/double 버전, 정수↔부동소수점 변환 포함
- 3.11.4: 상수는 메모리에 저장 후 로드, 즉시 값 불가
- 3.11.5: XMM 비트 연산으로 부동소수점 값 패턴 조작
- 3.11.6:
ucomis*
로 비교, NaN은 PF=1로 판별
- 3.11.7: 정수 코드와 구조 유사, 병렬 연산 잠재력 큼