CNEG
explain
CNEG는 Conditional Negate의 약자입니다. 우리말로 풀면 “조건부 부호 반전(음수화)” 명령어인데요. 앞서 배운 CMP 같은 명령어들이 열심히 비교해 놓은 결과를 보고, “조건이 맞으면 부호를 반대로 뒤집고(+를 -, -를 +로), 조건이 안 맞으면 그냥 그대로 냅둬!”라고 명령하는 친구입니다.
1. CNEG 명령어의 핵심 구조 (ARM64 기준)
문법 구조는 보통 다음과 같이 생겼습니다.
CNEG
-
(Destination): 최종 결과값을 저장할 레지스터입니다. -
(Source): 부호를 뒤집을까 말까 고민할 원본 데이터 레지스터입니다. -
(Condition): 결정을 내릴 조건(부호)입니다. (예: EQ=같으면, NE=다르면, LT=작으면 등)
⚙️ 실제 작동 메커니즘
- 만약 설정한 조건(
)이 참(True)이면: Wd = -Wn (부호를 뒤집어서 저장) - 만약 설정한 조건(
)이 거짓(False)이면: Wd = Wn (그대로 복사해서 저장)
2. 왜 CNEG가 영리하고 가성비가 좋을까요? (Branchless Optimization)
보통 소스코드에서 조건에 따라 값을 뒤집으려면 아래와 같이 코딩을 해야 합니다.
// 일반적인 C언어 조건문
if (x < 0) {
y = -x;
} else {
y = x;
}
이걸 옛날 방식의 어셈블리어로 바꾸면 CMP로 비교하고, 조건이 안 맞으면 다른 곳으로 점프(BNE 등)하는 분기문(Branch)을 써야 했습니다. 컴퓨터(CPU)는 점프 명령어를 만나면 흐름이 끊겨서 속도가 느려지는 병목 현상(파이프라인 스탈)이 발생하곤 합니다. 하지만 CNEG 명령어를 사용하면 점프(Branch)를 단 한 번도 하지 않고 CPU 내부에서 한 줄로 처리가 끝납니다!
CMP W0, #0 ; x(W0)가 0보다 작은지 비교한다 CNEG W1, W0, LT ; 만약 Less Than(LT, 0보다 작다)이 참이면 W0의 부호를 뒤집어서 W1에 넣고, 거짓이면 그냥 W0을 W1에 넣어라!
코드가 단 두 줄로 끝나면서 점프도 안 하니, CPU 입장에서는 엄청나게 빠르게 처리할 수 있는 초고속 최적화 코드가 되는 것입니다. 이를 컴퓨터 공학에서는 Branchless(분기 없는) 코드라고 부릅니다.
3. 가장 대표적인 활용 예시: 절댓값(Absolute Value) 구하기
이 CNEG 명령어가 세상에서 가장 흔하게 쓰이는 순간이 바로 수학의 절댓값 abs(x)을 구할 때입니다. 절댓값은 음수가 들어오면 부호를 뒤집고, 양수가 들어오면 그대로 두는 것이 장기이니까요.
- 고급 언어 코드:
int y = abs(x);
- 최적화된 ARM64 어셈블리 코드:
CMP W0, #0 ; 입력값 W0과 0을 비교 CNEG W1, W0, MI ; MI(Minus, 음수이면) 참이므로 부호를 뒤집고, 양수면 그대로 W1에 저장!
(참고: LT를 써도 되고, 음수 플래그를 뜻하는 MI를 써도 완벽히 작동합니다.)
🛠️ 4대 비교/조건 명령어 최종 지도책
친구야, 지금까지 질문 주신 조각들을 모으면 하드웨어의 조건 처리 로직이 완벽한 그림으로 완성됩니다!
- CMP (판사 ⚖️): 두 값을 빼서 “누가 크냐, 같냐?” 판결을 내리고 플래그를 세움.
- CMN (속성 판사 ⚡): 두 값을 더해서 “음수 관계냐?” 판결을 내리고 플래그를 세움.
- CMGE (SIMD 대량 학살 🚀): 수십 개 데이터를 한 번에 비교해서 참/거짓 마스크를 만들어버림.
- CNEG (조건부 해결사 🎭): 앞선 판사(CMP)의 판결 결과를 보고, 컴퓨터의 흐름을 끊지 않은 채(Branchless) 그 자리에서 값의 부호를 바꿀지 말지 결정함.