ASR 명령어 (Arithmetic Shift Right)
Summary
정의: 레지스터 값을 오른쪽으로 시프트하되, 부호 비트(최상위 비트)를 유지하며 빈 자리를 채우는 산술 시프트 명령어. 부호 있는(signed) 정수의 나눗셈이나 부호 유지 시프트 연산에 사용됨.
기본 문법
ASR Xd, Xn, #shift // 즉치값만큼 시프트
ASR Xd, Xn, Xm // 레지스터 값만큼 시프트
ASRV Xd, Xn, Xm // ASR의 정식 명칭 (레지스터 버전), 어셈블러가 ASR로 자동 변환
32비트 버전: ASR Wd, Wn, #shift 형태로 동일하게 사용 가능.
LSR과의 핵심 차이 — 부호 처리
| 명령어 | 정식 명칭 | 빈 자리 채움 방식 | 용도 |
|---|---|---|---|
LSR |
Logical Shift Right | 항상 0으로 채움 | 부호 없는(unsigned) 값 |
ASR |
Arithmetic Shift Right | 부호 비트(N) 로 채움 | 부호 있는(signed) 값 |
예시 비교 (8비트 기준 단순화):
값: 0b10000000 (signed로는 -128, unsigned로는 128)
LSR #1 → 0b01000000 (64) // 무조건 0으로 채움
ASR #1 → 0b11000000 (-64) // 부호비트(1) 유지하며 채움
판단 기준: 데이터가 부호 있는 정수(signed)일 때는 반드시 ASR을 써야 함. LSR을 잘못 사용하면 음수 값의 부호가 깨져 완전히 다른 결과가 나옴.
“ASL”에 대하여 — 존재하지 않는 이유
결론부터: ARM64에는 ASL이라는 독립 니모닉이 존재하지 않음. 이는 설계 원리상 당연한 결과임.
이유:
- 왼쪽 시프트는 부호와 무관하게 빈 자리를 항상 0으로 채우면 됨 (산술적으로도, 논리적으로도 결과가 동일함)
- 왼쪽으로 시프트할 때는 최상위 비트가 밀려나가는 구조이므로, “부호를 유지하며 채운다”는 개념 자체가 성립하지 않음
- 따라서 ARM64는 왼쪽 시프트를
LSL(Logical Shift Left) 하나로 통합함
정리:
| 방향 | 부호 없는 | 부호 있는 |
|---|---|---|
| 왼쪽 | LSL | LSL (동일) |
| 오른쪽 | LSR | ASR (별도) |
오른쪽 시프트에서만 LSR/ASR이 분리되는 비대칭 구조이며, 이 때문에 “ASL”이라는 대응 명령어가 애초에 필요 없어 존재하지 않는 것임.
ASR과 나눗셈의 관계
중요한 실전 활용: ASR #n은 부호 있는 정수를 2^n으로 나누는 연산과 (거의) 동일함.
asr x0, x0, #1 // x0 = x0 / 2 (signed, 산술적으로 근사)
asr x0, x0, #3 // x0 = x0 / 8 (signed)
주의할 함정: 음수를 나눌 때 ASR은 내림(floor) 방향으로 반올림하지만, C언어의 정수 나눗셈은 0 방향(truncation) 으로 반올림함. 즉:
-7 / 2 (C언어 기준) = -3 (0 방향으로 자름)
-7 asr 1 (산술 시프트) = -4 (음의 무한대 방향으로 내림)
결과적 영향: 컴파일러가 signed 나눗셈을 최적화할 때 단순히 ASR만 쓰지 않고, 음수 보정을 위한 추가 명령어(ADD, CSEL 등)를 함께 생성하는 경우가 많음. 순수 ASR 단독으로는 C언어의 정수 나눗셈 의미론을 완벽히 재현하지 못하기 때문임.
예제 코드
.global _start
.align 2
.text
_start:
mov x0, #-16 // x0 = -16 (signed)
asr x1, x0, #2 // x1 = -16 asr 2 = -4 (부호 유지)
lsr x2, x0, #2 // x2 = -16 lsr 2 = 매우 큰 양수 (부호 깨짐, unsigned 해석)
mov x0, #0
mov x16, #1
svc #0x80
비교 결과 설명: 동일한 -16 값에 대해 ASR은 부호를 유지하여 -4라는 올바른 산술 결과를 내지만, LSR은 -16을 unsigned 64비트 값(매우 큰 양수)으로 취급하여 전혀 다른 결과를 만듦. 이 차이가 ASR과 LSR을 구분해서 써야 하는 근본적 이유임.
Shifted Register 형태로도 자주 활용됨
ASR은 단독 명령어보다 다른 명령어의 shift operand로 결합되어 더 자주 관찰됨:
add x0, x1, x2, asr #3 // x2를 산술 시프트 후 x1과 덧셈
sub x0, x1, x2, asr #1
이런 결합형 사용 때문에 ASR 단독 명령어 형태보다 다른 산술 명령어의 부속 옵션으로 등장하는 빈도가 더 높은 편임.