핵심 인사이트 (3줄 요약)

  1. 본질: 3-주소 명령어 (Three-Address Instruction)는 두 입력과 한 출력의 위치를 각각 분리해 적는 형식이라, 연산 후에도 원본 피연산자가 보존되는 비파괴적 실행 모델을 만든다.
  2. 가치: 이 분리는 레지스터 재사용, 컴파일러 최적화, 파이프라인 병렬화에 유리하며, 현대 RISC (Reduced Instruction Set Computer) 계열 ISA (Instruction Set Architecture)의 기본 문법이 되었다.
  3. 판단 포인트: 장점은 명확하지만 주소 필드가 많아 명령어 폭과 코드 크기가 커지므로, 성능·디코딩 단순성·코드 밀도 사이의 균형을 함께 봐야 한다.

Ⅰ. 개요 및 필요성

3-주소 명령어는 하나의 명령어 안에 목적지 1개와 소스 2개를 독립적으로 적는 형식이다. 대표 예는 ADD R3, R1, R2이며 의미는 R3 ← R1 + R2다. 즉 결과를 저장하는 자리와 입력값을 읽는 자리를 분리해, 연산 이후에도 R1, R2의 값이 그대로 남는다.

이 형식이 중요해진 이유는 수식이 복잡해질수록 "원본을 보존한 채 다음 연산으로 연결할 수 있는가"가 성능을 좌우하기 때문이다. 1-주소나 2-주소 형식은 누산기나 목적지 겸 소스에 값이 덮어써져 중간 복사나 재적재가 자주 필요하다. 반면 3-주소 형식은 수학식의 구조를 기계어에 거의 그대로 옮길 수 있어, 컴파일러가 데이터 의존성을 더 명확하게 추적하고 명령어 재배치를 더 공격적으로 수행할 수 있다.

아래 그림은 3-주소 명령어가 왜 "원본 보존"에 강한지 보여준다.

┌──────────────────────────────────────────────────────────────┐
│     3-주소 명령어의 핵심: 읽는 곳 2개, 쓰는 곳 1개 분리      │
├──────────────────────────────────────────────────────────────┤
│ 명령어: ADD R3, R1, R2                                      │
│                                                              │
│ 읽기 단계                 연산 단계               쓰기 단계   │
│ R1 ───────────────┐                                   ┌─▶ R3 │
│                   ├─▶ ALU (Arithmetic Logic Unit) ────┤      │
│ R2 ───────────────┘                                   └──────│
│                                                              │
│ 결과: R1, R2는 유지되고 R3만 새 값으로 갱신된다.             │
└──────────────────────────────────────────────────────────────┘

핵심은 연산에 참여한 피연산자와 결과 저장 위치가 겹치지 않는다는 점이다. 이 구조는 "한 값을 여러 후속 명령이 동시에 참조"하는 상황에서 특히 강하다. 원본이 살아 있으니 복사 명령을 덜 넣어도 되고, 값의 생존 구간도 더 길게 활용할 수 있다.

  • 📢 섹션 요약 비유: 3-주소 명령어는 재료 두 개를 꺼내 새 그릇에 요리 결과만 담는 방식과 같다. 밀가루 통과 달걀은 그대로 남고, 반죽만 새 볼에 담기니 다음 요리를 이어가기 쉽다.

Ⅱ. 아키텍처 및 핵심 원리

3-주소 명령어는 단순히 주소가 하나 더 많은 포맷이 아니라, 읽기 포트 2개와 쓰기 포트 1개를 전제로 한 실행 모델과 맞물린다. 따라서 이 형식은 명령어 비트 배치, 레지스터 파일 구조, 디코딩 규칙, 즉시값 배치 방식까지 함께 설계해야 제대로 힘을 발휘한다.

구성 요소역할설계 포인트
Opcode수행 연산 지정산술, 논리, 이동, 비교 등 명령 종류 구분
Rd (Destination Register)결과 저장 위치기존 피연산자와 분리되어 비파괴성 확보
Rs1 (Source Register 1)첫 번째 입력주로 왼쪽 피연산자
Rs2 (Source Register 2)두 번째 입력레지스터 또는 즉시값 변형과 결합

현대 RISC 계열에서 3-주소 명령어가 잘 맞는 이유는 고정 길이 포맷과 결합하기 쉽기 때문이다. 예를 들어 32비트 명령어에서 범용 레지스터 GPR (General Purpose Register)가 32개라면, 레지스터 하나를 지정하는 데 5비트가 필요하다. 세 주소를 넣으면 15비트를 쓰고도 연산 코드와 일부 제어 비트를 남길 수 있어, 디코더가 매 사이클 같은 위치에서 Rd, Rs1, Rs2를 빠르게 분리해 낼 수 있다.

아래 그림은 수식 Y = (A + B) * C를 3-주소 방식으로 처리할 때 흐름이 어떻게 단순해지는지 보여준다.

┌──────────────────────────────────────────────────────────────┐
│        수식 변환: 3-주소는 중간 결과를 새 레지스터에 둔다     │
├──────────────────────────────────────────────────────────────┤
│ 1) ADD T1, A, B   ──▶ T1 = A + B                            │
│ 2) MUL Y,  T1, C  ──▶ Y  = T1 × C                           │
│                                                              │
│ A, B, C 보존 ──▶ 중간값 T1 생성 ──▶ 최종값 Y 생성            │
│                                                              │
│ 중간 단계마다 "누구를 덮어쓸지" 고민하지 않아도 된다.       │
└──────────────────────────────────────────────────────────────┘

이 구조는 하드웨어에도 이점이 있다. 디코더는 두 소스를 읽고 한 목적지에 쓰는 규칙을 반복적으로 처리하면 되므로 제어가 단순해지고, 파이프라인의 레지스터 읽기/쓰기 단계가 규칙적으로 정렬된다. 또한 즉시값이 필요한 경우에는 Rs2 자리를 즉시값 필드로 바꾸는 I형 변형을 두어 같은 철학을 유지한 채 확장할 수 있다.

다만 주소를 세 개 담으려면 비트 예산이 빠듯하다. 레지스터 수를 너무 늘리면 주소 비트가 커지고, 즉시값 크기를 늘리면 주소 필드가 줄어든다. 그래서 많은 3-주소 ISA는 "레지스터는 32개 안팎, 명령어 길이는 32비트, 큰 상수는 별도 로드"라는 절충을 선택한다.

  • 📢 섹션 요약 비유: 3-주소 구조는 주방에 도마 두 개와 접시 한 개를 따로 두는 것과 같다. 재료를 올리는 자리와 완성품을 담는 자리를 분리하니 조리 순서가 훨씬 매끄럽다.

Ⅲ. 비교 및 연결

3-주소 명령어의 장점은 다른 주소 수 체계와 비교할 때 더 또렷해진다. 핵심 비교 축은 원본 보존 여부, 명령어 수, 코드 밀도, 디코딩 단순성이다.

항목1-주소 명령어2-주소 명령어3-주소 명령어
기본 모델누산기 중심한 피연산자와 목적지 공유소스 2개와 목적지 분리
연산 형태AC ← AC + XA ← A + BC ← A + B
원본 보존약함한쪽 파괴강함
추가 복사 필요성높음중간낮음
명령어 폭비교적 작음절충형상대적으로 큼
파이프라인 친화성낮음중간높음

2-주소 형식은 코드 밀도 면에서는 매력적이지만, A = A + B처럼 목적지가 입력을 겸하면서 거짓 의존성(False Dependency)을 많이 만든다. 1-주소 형식은 더 단순하지만 누산기 병목이 심하다. 3-주소 형식은 명령어 하나가 약간 커져도, 전체 프로그램 수준에서는 불필요한 MOV, LOAD, STORE 수를 줄여 실행 흐름을 더 매끈하게 만든다.

이 지점에서 RISC와 CISC (Complex Instruction Set Computer)의 철학 차이도 연결된다. RISC는 고정 길이·레지스터 중심·단순 디코딩을 선호하므로 3-주소 명령어와 잘 맞는다. 반대로 x86 같은 CISC는 겉으로는 2-주소 또는 메모리 피연산자 형식을 많이 쓰지만, 내부 마이크로-연산으로 쪼갤 때는 사실상 3-주소 형태로 재구성해 병렬 실행에 활용한다. 즉 3-주소는 외부 ISA 문법일 뿐 아니라, 현대 마이크로아키텍처 내부에서 선호되는 실행 단위이기도 하다.

컴파일러 관점에서도 연결성이 크다. IR (Intermediate Representation)이나 SSA (Static Single Assignment) 형태가 3-주소와 닮아 있는 이유는, 각 연산 결과를 새 이름에 바인딩할수록 데이터 흐름 분석과 최적화가 쉬워지기 때문이다. 결국 3-주소는 "하드웨어가 좋아하는 형식"이면서 동시에 "컴파일러가 생각하기 쉬운 형식"이다.

  • 📢 섹션 요약 비유: 1-주소는 계산대를 하나만 둔 가게, 2-주소는 계산대 겸 포장대를 함께 쓰는 가게, 3-주소는 계산대와 포장대를 분리한 가게와 같다. 공간은 조금 더 쓰지만 손님 흐름은 가장 덜 막힌다.

Ⅳ. 실무 적용 및 기술사 판단

실무에서 3-주소 명령어는 단순한 교과서 개념이 아니라, 컴파일러 백엔드·임베디드 ISA 설계·벡터 명령 확장을 판단할 때 기준이 된다. 특히 성능을 중시하는 설계에서는 "명령어 한 줄의 짧음"보다 "전체 데이터 흐름의 단순함"이 더 중요할 때가 많다.

1) 채택이 유리한 경우

  1. 파이프라인 병렬화가 중요한 경우: 독립 레지스터를 유지하므로 명령어 스케줄링과 아웃오브오더(Out-of-Order) 실행이 수월하다.
  2. 컴파일러 최적화를 크게 활용하는 경우: 공통 부분식 제거, 명령어 재배치, 레지스터 할당이 더 자연스럽다.
  3. 고정 길이 디코딩이 필요한 경우: 임베디드 프로세서, 교육용 ISA, 간결한 디코더 설계에 적합하다.

2) 주의가 필요한 경우

  1. 코드 크기가 매우 중요한 경우: 주소 필드가 많아 플래시 메모리나 명령 캐시 압박이 커질 수 있다.
  2. 즉시값 사용 빈도가 높은 경우: 세 주소와 큰 상수를 동시에 담기 어려워 추가 로드가 늘 수 있다.
  3. 레지스터 수가 부족한 경우: 형식은 3-주소라도 실제로는 스필(Spill) 증가로 장점이 줄어든다.

아래 그림은 실무 판단을 위한 대표적인 균형점을 정리한 것이다.

┌──────────────────────────────────────────────────────────────┐
│            3-주소 채택 판단: 성능과 코드 크기의 균형          │
├──────────────────────────────────────────────────────────────┤
│ 성능 우선 설계                                                │
│   ├─ 원본 보존 필요 큼                                        │
│   ├─ 파이프라인/병렬화 중요                                   │
│   └─ 3-주소 채택에 유리                                       │
│                                                              │
│ 메모리 절약 우선 설계                                          │
│   ├─ 명령어 저장 공간 제한 큼                                 │
│   ├─ 압축 명령어 필요                                          │
│   └─ 2-주소 또는 압축 확장 병행 고려                           │
└──────────────────────────────────────────────────────────────┘

기술사 답안에서는 "3-주소가 항상 우월하다"고 쓰면 부족하다. 정확한 판단은 성능 중심이면 3-주소가 유리하지만, 코드 밀도와 즉시값 표현력까지 고려하면 압축 명령어 또는 혼합 포맷이 필요하다는 식으로 정리해야 한다. 실제 ARM Thumb, RISC-V C 확장은 이 한계를 메우기 위해 등장한 사례다.

  • 📢 섹션 요약 비유: 3-주소는 넓은 작업대가 있는 공방과 같다. 일은 빨라지지만 공간 임대료가 비싸면, 접이식 작업대를 같이 써야 전체 운영이 좋아진다.

Ⅴ. 기대효과 및 결론

3-주소 명령어의 가장 큰 효과는 데이터 흐름을 명확하게 만든다는 점이다. 원본을 보존하므로 명령어 간 의존 관계가 드러나고, 레지스터 재사용과 병렬 실행 기회가 커진다. 그 결과 컴파일러는 더 공격적인 최적화를 수행할 수 있고, 프로세서는 더 예측 가능한 파이프라인을 구성할 수 있다.

반면 대가도 분명하다. 주소 필드가 늘수록 명령어는 커지고, 코드 밀도는 나빠지며, 큰 즉시값을 직접 넣기 어려워진다. 그래서 현대 설계는 3-주소를 기본으로 삼되, 압축 명령어·벡터 전용 포맷·즉시값 확장 명령을 함께 두어 약점을 보완한다.

결국 3-주소 명령어는 "가장 많은 정보를 한 줄에 적는 방식"이 아니라, 연산의 의미를 가장 깨끗하게 보존하는 방식으로 기억해야 한다. 시험에서는 비파괴성·파이프라인 친화성·코드 밀도 저하를 함께 적는 것이 핵심이고, 실무에서는 ISA의 성능 철학을 드러내는 설계 선택으로 이해하면 된다.

  • 📢 섹션 요약 비유: 3-주소 명령어는 정리정돈이 잘된 책상과 같다. 책상은 조금 넓게 차지하지만, 물건이 섞이지 않아 결국 더 빠르고 정확하게 일할 수 있다.

📌 관련 개념 맵

개념연결 포인트
2-주소 명령어 (Two-Address Instruction)목적지와 소스가 겹쳐 원본 파괴가 발생하는 비교 대상
Load/Store Architecture메모리는 읽고 쓰기만 하고, 연산은 레지스터에서 수행하는 3-주소 RISC의 기본 운영 방식
Register Renaming외부 명령어의 의존성을 내부 물리 레지스터로 풀어 병렬성을 높이는 기법
SSA (Static Single Assignment)결과를 새 이름에 저장하는 3-주소적 사고를 컴파일러 수준에서 체계화한 표현
Compressed ISA3-주소의 코드 크기 약점을 보완하기 위해 도입되는 압축 명령 집합

📈 관련 키워드 및 발전 흐름도

누산기 중심 1-주소
        │
        ▼
절충형 2-주소
        │
        ▼
비파괴 3-주소 + 고정 길이 디코딩
        │
        ├─▶ RISC 파이프라인 최적화
        ├─▶ 컴파일러 SSA/IR 친화성 강화
        └─▶ 압축 명령어 · 벡터 확장으로 보완

이 흐름은 "주소 수 증가" 자체보다, 연산 의미를 얼마나 명시적으로 표현하느냐가 아키텍처 발전의 핵심이었음을 보여준다.

👶 어린이를 위한 3줄 비유 설명

  1. 3-주소 명령어는 친구 둘이 재료를 주고, 다른 빈 그릇에 완성품을 담는 약속이에요.
  2. 그래서 원래 재료를 망가뜨리지 않고, 다음 요리에도 다시 쓸 수 있어요.
  3. 대신 그릇 이름을 세 개나 적어야 해서 메모는 조금 더 길어져요.