소프트웨어를 다운로드하려고 할 때, 운영체제뿐만 아니라 x64
, Arm64
같은 옵션들 때문에 어떤 파일을 선택해야 할지 고민한 적 있으신가요?
이러한 선택지는 명령어 집합(ISA: Instruction Set Architecture)이 다르기 때문입니다.
CPU는 명령어를 받아 연산을 수행합니다. 하지만 모든 CPU가 동일한 명령어를 사용하는 것은 아닙니다.
CPU는 특정 명령어 집합을 기반으로 설계되며, 이는 CPU의 언어와도 같습니다.
명령어 집합: CPU가 이해할 수 있는 명령어들의 모음.
- 예시
Intel CPU →x86
,x86-64
명령어 집합.
Apple M1/M2 (ARM CPU) →ARM64
명령어 집합.
아래 사진과 같이 소스코드가 같더라도, 사용하는 명령어 집합이 다르면 실행 파일의 형태가 달라집니다.
명령어 집합의 설계 방식은 크게 CISC와 RISC로 나눌 수 있습니다.
‼️ 여기에서 명령어 길이는 위의 어셈블리 코드를 0과 1로 변환했을 때의 명령어 길이를 뜻합니다!
CISC: 복잡하고 다양한 가변 길이 명령어를 활용하는 구조.
- 특징
- 강력한 명령어 활용 = 적은 수의 명령어로도 프로그램 실행 가능.
- 다양한 주소 지정 방식 사용.
- 한계
- 명령어의 크기과 실행 시간이 일정하지 않아 파이프라이닝에 불리.
- 대부분의 명령어가 사용되지 않음 = 자주 사용되는 명령어만 사용.
- 예시:
x86
,x86-64
(Intel/AMD CPU).
RISC: 단순하고 적은 고정 길이 명령어를 활용하는 구조.
- 특징
- 명령어의 규격화, 실행 시간이 일정 = 파이프라이닝에 유리.
- 메모리 접근 명령어를 load, store 로 제한 = ALU와 가까운 레지스터 적극 활용
- 적은 주소 지정 방식 사용. (대부분 레지스터 주소 지정 방식)
- 한계
- 단순한 명령어로 작업을 수행하기 때문에 더 많은 명령어가 필요.
- 예시:
ARM
(Apple M1/M2, 모바일 기기, 임베디드 시스템).
실행 시간이 왜 달라지는지 궁금하신 분들만 읽으시면 됩니다!
CISC
CISC는 명령어는 가변 길이이기 때문에, 명령어의 길이를 파악하는 과정에서 추가 시간이 소요됩니다. 여기에 더해 복잡한 코드를 실행 가능한 코드 단위로 쪼개는 과정에서 시간이 더 소요되게 됩니다. 또 CISC 명령어는 메모리 접근과 연산을 하나의 명령어로 묶어 처리하는 경우가 많습니다. 때문에 각 명령어를 메모리 접근 단계로 분리하기가 힘들어지고 결국엔 실행 시간이 일정하지 않게 됩니다.
RISC
메모리에 접근하는 과정은 캐시 히트를 할 경우 1~2클럭 내외로 처리되지만 캐시 미스가 발생한 경우 50~200클럭이 요구됩니다. 하지만 이와 관계없이 RISC에서는 메모리 접근을 Load/Store로 제한하여 메모리 접근 단계로 분리할 수 있게 되었고 레지스터 중심으로 연산하기 때문에 메모리 접근 단계의 의존성을 줄일 수 있게 되었습니다. 메모리 접근 단계를 제외하곤 모두 1클럭 내외로 실행되기 때문에 파이프라이닝에 유리합니다.
CISC를 파이썬, RISC를 C언어에 비유하면 이해하기 쉽습니다.