RISC vs CISC
CPU가 이해하는 명령어의 종류와 모양을 정해 둔 약속을 명령어 집합 구조(ISA, Instruction Set Architecture)라고 합니다. 소프트웨어가 보는 CPU의 얼굴이라서, 같은 ISA를 따르는 CPU는 같은 프로그램을 실행할 수 있습니다. ISA를 설계하는 철학은 크게 둘로 나뉩니다. RISC(Reduced Instruction Set Computer)는 단순한 명령어를 적은 종류로 제공하고 길이를 고정해 하드웨어를 단순하게 만들며, CISC(Complex Instruction Set Computer)는 한 명령어가 메모리 접근과 연산을 함께 하는 것처럼 복잡한 일을 하도록 풍부한 명령어를 제공합니다.
대표적으로 ARM과 RISC-V는 RISC 계열, x86은 CISC 계열로 불립니다. 같은 일을 하더라도 RISC는 보통 단순한 명령어를 더 많이, CISC는 더 적게 씁니다. 다만 오늘날의 구분은 예전만큼 뚜렷하지 않습니다. 현대 x86 CPU는 복잡한 명령어를 안쪽에서 단순한 마이크로 연산으로 나눠 실행하기 때문에, 겉모습은 CISC여도 실행 방식은 RISC와 비슷해졌습니다. 이 토픽에서는 두 철학이 명령어 길이, 메모리 접근 방식, 성능 식에서 어떻게 다른지 봅니다.
핵심 개념
ISA와 구현의 구분
ISA는 소프트웨어가 볼 수 있는 명령어, 레지스터, 주소 지정 방식의 약속이고, 마이크로아키텍처는 그것을 하드웨어로 구현하는 방법입니다. 같은 ISA를 서로 다른 구현으로 만들 수 있습니다.
핵심 개념
RISC의 특징
단순하고 길이가 일정한 명령어, 적은 종류의 주소 지정 방식, 많은 레지스터, 그리고 연산은 레지스터끼리 하고 메모리는 load/store 명령으로만 접근하는 구조가 대표적입니다. 디코딩과 파이프라인 구현이 단순해집니다.
핵심 개념
CISC의 특징
한 명령어가 여러 단계의 작업(예: 메모리 값을 읽어 더하고 다시 저장)을 하고, 명령어 길이가 가변적이며, 연산 명령어가 메모리 피연산자를 직접 다룰 수 있습니다. 같은 프로그램이 더 적은 명령어로 표현될 수 있습니다.
핵심 개념
load/store 구조
연산 명령어는 레지스터만 다루고, 메모리와 레지스터 사이의 이동은 load와 store 명령어가 맡는 구조입니다. 메모리 접근이 명령어마다 눈에 보여 파이프라인과 스케줄링을 단순하게 합니다.
핵심 개념
마이크로 연산
현대 x86 CPU는 명령어를 해독해 더 단순한 내부 연산(마이크로 연산, micro-op)으로 바꿔 실행합니다. 복잡한 ISA를 유지하면서 안쪽 실행 엔진은 단순한 연산 단위로 설계하는 방식입니다.
핵심 개념
CPU 시간 식
CPU 시간 = 명령어 수 × 명령어당 평균 사이클(CPI) × 사이클 시간입니다. RISC는 명령어 수가 늘고 CPI가 낮아지는 경향, CISC는 명령어 수가 줄고 CPI가 높아지는 경향이 있지만 실제 성능은 세 요소의 곱으로 정해집니다.
RISC와 CISC의 배경
RISC라는 이름은 1980년 데이비드 패터슨(David Patterson)과 데이비드 디츨(David Ditzel)의 논문 "The Case for the Reduced Instruction Set Computer"에서 널리 알려졌습니다. 이 논문은 VLSI 시대의 CPU를 RISC로 구현하는 편이 더 알맞을 수 있다고 주장했습니다. CISC는 이에 대비해 기존의 복잡한 ISA 설계를 가리키는 말로 쓰이게 되었습니다. 이후 ARM, MIPS, RISC-V 같은 RISC 계열 ISA와 x86 계열 ISA가 각자 발전해 왔습니다.
숫자로 확인하기
자주 하는 오해
면접에서 이렇게 물어요
면접 질문
RISC와 CISC의 차이는 무엇인가요?
RISC는 단순하고 길이가 일정한 명령어를 쓰고 연산은 레지스터끼리 하며 메모리 접근은 load/store가 맡습니다. CISC는 복잡한 명령어와 가변 길이를 쓰고 연산 명령어가 메모리 피연산자를 다룰 수 있습니다.
면접 질문
대표적인 예와 오늘날의 경계는?
ARM과 RISC-V가 RISC, x86이 CISC의 대표입니다. 다만 현대 x86 CPU는 복잡한 명령어를 마이크로 연산으로 바꿔 실행하므로 두 방식의 경계가 예전보다 흐려졌습니다.
면접 질문
RISC가 파이프라인에 유리하다고 하는 이유는?
명령어 길이가 같고 형식이 단순해 해독이 쉽고, 메모리 접근이 load/store로 분리되어 단계별 동작이 규칙적이기 때문입니다. 그래서 파이프라인 구현이 단순해집니다.
면접 질문
성능은 어떻게 비교하나요?
CPU 시간 = 명령어 수 × CPI × 사이클 시간 식으로 비교합니다. 명령어 수만 보거나 클럭만 봐서는 부족하고, 같은 프로그램에서 세 요소를 곱해 봐야 합니다.
실제 시스템에서는
함께 보면 좋은 토픽
참고 자료
같은 C 코드가 ISA마다 다른 명령어가 됨
// C: 포인터가 가리키는 값에 y를 더함 void add_to(int *p, int y) { *p += y; } ; x86-64 (Intel 문법): 메모리 피연산자를 직접 다루는 명령어 1개 add DWORD PTR [rdi], esi ret ; RISC-V (RV64): load → 연산 → store lw a5, 0(a0) addw a5, a5, a1 sw a5, 0(a0) ret ; AArch64 (Arm): RISC-V처럼 메모리 접근을 load/store 명령으로만 함 ldr w2, [x0] add w2, w2, w1 str w2, [x0] ret
x86-64에서는 add DWORD PTR [rdi], esi 한 명령어가 메모리에서 읽고, 더하고, 메모리에 다시 씁니다. RISC-V와 AArch64는 연산 명령어가 레지스터만 다루므로 load, 연산, store의 세 명령어로 나뉩니다. 이 출력은 컴파일러와 최적화 수준에 따라 달라질 수 있는 예시입니다. 배포판에 따라 x86-64 출력 앞에 endbr64가 붙기도 합니다. 직접 확인하려면 gcc -O2 -S로 어셈블리를 만들어 보거나 대상 아키텍처의 크로스 컴파일러를 쓰면 됩니다. 어느 쪽이 더 낫다는 뜻이 아니라, 같은 일을 표현하는 방식이 ISA 철학에 따라 달라진다는 것을 보여 줍니다.
명령어 길이 — 가변과 고정
; objdump -d 출력 예: 주소, 기계어 바이트, 어셈블리 ; x86-64: 명령어마다 길이가 다름 (2바이트, 1바이트) 0: 01 37 add DWORD PTR [rdi], esi 2: c3 ret ; RISC-V: 기본 명령어는 모두 4바이트 (압축 확장 C를 쓰지 않을 때) 0: 00052783 lw a5, 0(a0) 4: 00b787bb addw a5, a5, a1 8: 00f52023 sw a5, 0(a0) c: 00008067 ret
x86의 두 명령어는 2바이트와 1바이트로 길이가 다릅니다. 명령어의 길이는 앞의 바이트를 해석해야 알 수 있어서 시작 위치를 찾는 일이 앞에서 뒤로 이어집니다. RISC-V의 기본 명령어는 모두 4바이트라서 다음 명령어가 항상 4바이트 뒤에서 시작합니다. 위 기계어는 예시이며 컴파일러와 옵션에 따라 달라질 수 있습니다. 이 예시에서는 x86이 메모리 피연산자 덧셈을 명령어 하나(3바이트)로 처리해 코드가 작고, 고정 4바이트 RISC-V는 명령어 길이가 일정해 디코딩이 단순합니다. 다만 RISC-V에는 2바이트 압축(C) 확장이 있어 같은 코드가 더 작아질 수 있으므로, 실제 크기는 명령어 조합과 확장에 따라 달라집니다.
내 컴퓨터의 아키텍처 확인
# 리눅스/맥: 머신 아키텍처 (x86_64, aarch64 등) uname -m # 실행 파일이 어느 아키텍처용인지 확인 file ./server # 예: ELF 64-bit LSB executable, x86-64 ... 또는 ... ARM aarch64 ... # 컨테이너 이미지를 두 아키텍처용으로 빌드 docker buildx build --platform linux/amd64,linux/arm64 -t app:latest .
ISA가 다르면 기계어가 달라서 x86용 실행 파일은 Arm CPU에서 그대로 실행되지 않습니다. uname -m은 현재 머신의 아키텍처를, file 명령은 실행 파일이 어느 아키텍처용인지 알려 줍니다. Arm 기반 서버나 노트북을 함께 쓴다면 컨테이너 이미지를 linux/amd64와 linux/arm64 모두 빌드해 두는 방법이 있습니다. 여러 플랫폼 이미지를 로컬에 적재하려면 containerd 이미지 스토어를 켜야 하고, 그렇지 않으면 --push로 레지스트리에 올립니다. 인터프리터나 가상 머신 위에서 도는 코드(자바 바이트코드, 파이썬 스크립트)는 그 인터프리터가 해당 아키텍처를 지원하면 소스를 바꾸지 않고 실행됩니다.
Q1
RISC 아키텍처의 특징으로 옳은 것은?
Q2
CISC 아키텍처의 특징으로 옳은 것은?
Q3
대표적인 아키텍처를 알맞게 짝지은 것은?