핵심 인사이트 (3줄)

  1. 본질: WAW (Write After Write)는 두 명령어가 같은 목적지에 쓰려 할 때, 프로그램상 나중 값이 최종값이어야 하는데 실제 하드웨어에서는 먼저 끝난 순서대로 기록되어 최종 상태가 뒤집히는 출력 의존성 (Output Dependency) 문제다.
  2. 가치: 기본 순차 파이프라인에서는 잘 드러나지 않지만, 실행 시간이 다른 연산기와 비순차 실행이 결합된 현대 CPU에서는 성능 향상과 상태 일관성 사이의 핵심 충돌 지점이 된다.
  3. 판단 포인트: WAW는 값 자체의 인과관계보다 "같은 이름의 저장 위치" 때문에 생기는 가짜 충돌이므로, 레지스터 리네이밍 (Register Renaming)리오더 버퍼 (Reorder Buffer, ROB) 로 실행 순서와 커밋 순서를 분리해 해결한다.

Ⅰ. 개요 및 필요성

WAW (Write After Write)는 앞선 명령어와 뒤따르는 명령어가 같은 레지스터나 저장 위치에 결과를 쓰는 상황에서, 나중 명령어의 값이 최종적으로 남아야 하는데 실제 기록 순서가 뒤집혀 옛값이 마지막에 남는 해저드다. 즉 문제의 핵심은 "누가 먼저 계산했는가"가 아니라 "누가 마지막으로 아키텍처 상태를 갱신했는가"에 있다.

고전적인 5단계 파이프라인에서는 대부분 명령어가 같은 WB (Write Back) 시점에 도달하므로 WAW가 잘 보이지 않는다. 그러나 곱셈기, 나눗셈기, FPU (Floating Point Unit)처럼 실행 시간이 다른 연산기가 섞이거나, OoO (Out-of-Order) 실행으로 뒤의 명령어가 먼저 끝날 수 있는 구조에서는 문제가 현실화된다. 이를 통제하지 못하면 프로그램이 의도한 "최신 결과가 최종 상태가 된다"는 규칙이 깨져, 계산은 빨라져도 결과는 틀리는 역설이 생긴다.

WAW를 관리해야 하는 이유는 단순한 해저드 제거를 넘어 아키텍처 상태 (Architectural State) 의 신뢰성을 지키기 위해서다. CPU가 내부적으로 아무리 공격적으로 병렬 실행하더라도, 외부에서 관찰되는 레지스터와 메모리 상태는 프로그램 순서를 존중해야 한다. 결국 WAW 대응은 성능 최적화가 아니라, 고성능 설계를 가능하게 만드는 최소 안전장치다.

┌──────────────────────────────────────────────────────────────────────┐
│        WAW의 핵심: 계산 완료 순서와 최종 기록 순서가 다를 수 있음    │
├──────────────────────────────────────────────────────────────────────┤
│ 프로그램 순서 : I1 ─────────────────────────────▶ I2                 │
│ 의미상 최종값 : I2의 결과가 남아야 함                                │
│                                                                      │
│ 실제 완료 순서: I2 ─────────▶ I1                                      │
│ 실제 기록 결과: I1이 마지막에 쓰면 최종 상태가 뒤집힘                │
└──────────────────────────────────────────────────────────────────────┘

이 그림은 WAW가 "쓰기 두 번" 자체보다 최종 상태의 소유권 충돌이라는 점을 보여준다. 그래서 해결책도 단순 대기가 아니라, 어느 값이 최종 공식 결과인지 보장하는 구조적 장치가 필요하다.

  • 📢 섹션 요약 비유: 두 사람이 같은 칠판을 고치는데, 나중에 온 사람이 최신 정답을 먼저 써놓았어도 먼저 온 사람이 뒤늦게 옛 답을 덮어쓰면 학생들은 틀린 답을 최종 답으로 보게 된다.

Ⅱ. 아키텍처 및 핵심 원리

WAW는 보통 "선행 명령어가 느리고, 후행 명령어가 빠른" 조합에서 발생한다. 예를 들어 나눗셈은 여러 사이클이 걸리고 덧셈은 1사이클에 끝난다면, 프로그램상 먼저 나온 DIV (Divide)보다 뒤의 ADD (Add)가 먼저 결과를 쓸 수 있다. 이때 두 명령어가 같은 목적지 레지스터를 공유하면, 후행 명령어가 먼저 쓴 최신 값을 선행 명령어가 나중에 덮어쓰는 문제가 생긴다.

프로그램 순서명령어 예시지연 특성WAW 관점의 의미
I1DIV R1, R2, R3다사이클, 완료 느림먼저 나왔지만 늦게 씀
I2ADD R1, R4, R5단사이클, 완료 빠름나중에 나왔지만 먼저 씀
기대 결과R1 = ADD 결과프로그램 순서 기준최신 값이 남아야 함
오류 결과R1 = DIV 결과완료 순서 기준 기록옛값이 최종 상태가 됨

다음 타임라인은 WAW가 왜 생기는지 보여준다. 중요한 점은 I1과 I2 사이에 데이터가 직접 전달되는 것은 아니라는 사실이다. 둘은 단지 같은 "목적지 이름"을 공유할 뿐이므로, 이 해저드는 이름 의존성 (Name Dependency) 의 한 종류다.

┌──────────────────────────────────────────────────────────────────────┐
│           가변 지연 파이프라인에서의 WAW 발생 타임라인              │
├────────┬────────┬────────┬────────┬────────┬────────┬───────────────┤
│ Cycle  │   1    │   2    │   3    │   4    │   5    │   6           │
├────────┼────────┼────────┼────────┼────────┼────────┼───────────────┤
│ I1 DIV │ Issue  │ EX1    │ EX2    │ EX3    │ EX4    │ WB : R1=DIV   │
│ I2 ADD │        │ Issue  │ EX      │ WB:R1=ADD │      │               │
├────────┴────────┴────────┴────────┴────────┴────────┴───────────────┤
│ 문제: ADD가 먼저 쓴 R1을 DIV가 뒤늦게 덮어쓰면, 최종 R1이 잘못된다. │
└──────────────────────────────────────────────────────────────────────┘

현대 CPU는 이를 두 단계로 해결한다. 첫째, 레지스터 리네이밍으로 논리 레지스터 R1을 서로 다른 물리 레지스터에 매핑해 실제 저장 위치 충돌을 없앤다. 둘째, ROB를 이용해 결과가 준비된 순서가 아니라 프로그램 순서대로 커밋 (Commit) 하게 만들어, 아키텍처 상태에는 항상 올바른 최신 값만 반영되도록 한다.

┌──────────────────────────────────────────────────────────────────────┐
│          현대 CPU의 해결 방식: 실행은 자유롭게, 커밋은 순서대로      │
├──────────────────────────────────────────────────────────────────────┤
│ 논리 레지스터 R1                                                     │
│   ├─ I1 DIV  ─▶ PRF P17에 기록 준비                                  │
│   └─ I2 ADD  ─▶ PRF P24에 기록 준비                                  │
│                                                                      │
│ ROB 순서                                                              │
│   [I1 엔트리] ─▶ [I2 엔트리]                                          │
│        │             │                                                │
│ 완료는 I2가 먼저여도, 최종 반영은 ROB가 프로그램 순서로 통제         │
└──────────────────────────────────────────────────────────────────────┘

여기서 PRF (Physical Register File)는 실제 값을 담는 물리 저장소다. 결과적으로 WAW 해결의 핵심은 "같은 이름을 같은 상자에 바로 쓰지 않게 하고, 공식 발표는 순서대로 하게 만드는 것"이다.

  • 📢 섹션 요약 비유: 답안지 번호가 둘 다 1번이면 늦게 채점된 옛 답안이 최신 답안을 밀어낼 수 있다. 그래서 임시 보관함은 따로 쓰고, 최종 성적표에 올릴 때만 출석번호 순서대로 반영해야 한다.

Ⅲ. 비교 및 연결

WAW를 제대로 이해하려면 RAW (Read After Write), WAR (Write After Read)와 비교해야 한다. 세 해저드는 모두 순서 문제처럼 보이지만, 실제로는 보호해야 하는 대상이 다르다. RAW는 값의 생산과 소비 사이의 진짜 인과관계 이고, WAR와 WAW는 같은 이름을 공유해서 생기는 가짜 의존성 이다.

항목RAW (Read After Write)WAR (Write After Read)WAW (Write After Write)
보호 대상앞 명령어의 생산 값앞 명령어의 읽기 기회뒤 명령어의 최종 쓰기 결과
본질진성 의존성 (True Dependency)반의존성 (Anti-dependency)출력 의존성 (Output Dependency)
리네이밍 효과근본 해결 불가해결 가능해결 가능
대표 대응포워딩, 스톨, 스케줄링레지스터 리네이밍리네이밍 + 순차 커밋

이 비교에서 중요한 포인트는 WAW가 리네이밍만으로 "충돌 공간"은 줄일 수 있어도, 예외 처리와 정확한 상태 복구까지 생각하면 ROB 같은 순차 커밋 장치가 함께 필요하다는 점이다. 그래서 WAW는 단순한 파이프라인 해저드라기보다, Tomasulo 알고리즘, 스코어보딩, 리네이밍, 정밀 예외 처리까지 이어지는 현대 마이크로아키텍처의 연결 고리로 이해해야 한다.

또한 WAW는 정수 파이프라인보다 가변 지연이 큰 부동소수점 파이프라인, 벡터 파이프라인, AI 가속기에서 더 민감하게 나타난다. 연산 유닛이 다양해질수록 완료 순서는 더 예측 불가능해지기 때문이다. 따라서 고성능 구조일수록 "실행 유연성" 과 "상태 반영 질서" 를 동시에 설계해야 한다.

  • 📢 섹션 요약 비유: RAW는 요리사가 재료를 먼저 만들어야 손님이 먹을 수 있는 자연 순서이고, WAW는 여러 요리사가 같은 주문표를 덮어쓰며 누가 최종 메뉴를 확정할지 충돌하는 행정 문제에 가깝다.

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

실무 설계에서 WAW 대응은 "어떻게 막을까"보다 "어디까지 허용할까"의 문제다. 단순한 인오더 (In-Order) 코어는 WAW 위험이 작지만 성능 한계가 뚜렷하고, 고성능 OoO 코어는 WAW를 숨기기 위해 더 큰 리네이밍 테이블, 더 깊은 ROB, 더 복잡한 예외 복구 회로가 필요하다. 결국 성능, 전력, 면적을 함께 보는 PPA (Power, Performance, Area) 판단이 필수다.

설계 판단 체크포인트

  1. 가변 지연 연산기 존재 여부: DIV, SQRT (Square Root), FPU 연산처럼 완료 시점이 크게 흔들리면 WAW 위험이 커진다.
  2. 리네이밍 자원 충분성: 물리 레지스터 수가 부족하면 리네이밍 윈도우가 좁아져 병렬성 이점이 줄어든다.
  3. 순차 커밋 보장 여부: 결과가 먼저 나와도 예외, 인터럽트, 분기 실패 시 정확히 되돌릴 수 있어야 한다.
  4. 컴파일러/하드웨어 협업 수준: 정적 스케줄링만으로는 한계가 있으므로, 동적 스케줄링 하드웨어와 역할 분담이 필요하다.

채택/회피 판단

  • 채택: 서버용 CPU, 고성능 범용 코어, 벡터/행렬 연산 가속기처럼 ILP (Instruction Level Parallelism) 확보가 중요한 경우
  • 회피 또는 단순화: 초저전력 마이크로컨트롤러, 검증 단순성이 우선인 실시간 제어 코어처럼 구조 복잡도를 낮춰야 하는 경우

안티패턴

  • 완료 순서를 믿고 결과를 즉시 아키텍처 레지스터에 반영하는 설계
  • 리네이밍은 했지만 예외 복구 경로가 약해 정밀 예외 (Precise Exception)를 보장하지 못하는 설계
  • 연산기 확장만 하고 ROB·PRF 규모를 함께 키우지 않아 병렬 실행 폭만 넓힌 설계

실무에서는 WAW를 없앴다고 끝이 아니다. 해결 구조가 분기 예측 실패, 인터럽트, speculative execution 취소와도 자연스럽게 이어져야 진짜 완성된 설계다.

  • 📢 섹션 요약 비유: 놀이공원에서 놀이기구를 많이 늘리는 것만으로는 운영이 되지 않는다. 탑승권 번호표와 출입 통제가 함께 있어야 마지막 탑승 기록이 뒤죽박죽되지 않는다.

Ⅴ. 기대효과 및 결론

WAW를 제대로 다루면 CPU는 같은 이름 충돌에 발목 잡히지 않고, 여러 연산기를 더 공격적으로 병렬 활용할 수 있다. 이는 단순 성능 향상뿐 아니라, 가변 지연 연산기 도입 자유도와 설계 확장성을 높인다는 점에서 중요하다. 즉 WAW 해결은 해저드 제거를 넘어, 현대 프로세서가 "질서 있는 무질서"를 구현하게 해주는 기반 기술이다.

다만 그 대가도 분명하다. 리네이밍과 ROB는 면적과 전력을 소모하고, 설계 검증 난도를 크게 높인다. 따라서 모든 시스템이 같은 수준의 WAW 대응 구조를 가질 필요는 없으며, 목표 성능과 예외 정밀도 요구 수준에 맞춰 구조를 선택해야 한다.

결국 WAW는 "쓰기 충돌"이 아니라 최종 상태를 누가 대표하느냐의 문제로 기억하는 것이 정확하다. 현대 CPU는 내부에서는 자유롭게 먼저 끝내고, 외부에 보이는 상태만 프로그램 순서대로 정리함으로써 이 문제를 해결한다.

  • 📢 섹션 요약 비유: 연주자는 각자 먼저 연습을 끝낼 수 있지만, 무대에서 관객에게 들려줄 최종 합주는 지휘자가 악보 순서대로 맞춰야 한다. WAW 해결은 바로 그 지휘 역할이다.

📌 관련 개념 맵

개념연결 포인트
출력 의존성 (Output Dependency)WAW의 이론적 분류로, 최종 쓰기 순서 보장이 핵심이다.
레지스터 리네이밍 (Register Renaming)같은 논리 목적지를 서로 다른 물리 목적지로 분리해 이름 충돌을 없앤다.
리오더 버퍼 (Reorder Buffer, ROB)실행 완료 순서와 무관하게 프로그램 순서대로 결과를 커밋하게 만든다.
물리 레지스터 파일 (Physical Register File, PRF)리네이밍된 결과값이 임시로 저장되는 실제 공간이다.
정밀 예외 (Precise Exception)WAW가 통제되어야 예외 시점의 아키텍처 상태를 정확히 복원할 수 있다.

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

순차 파이프라인
    │
    ▼
고정 지연 WB (Write Back) 중심 설계
    │
    ▼
가변 지연 연산기 · 슈퍼스칼라 발행
    │
    ▼
WAW (Write After Write) 노출
    │
    ▼
레지스터 리네이밍 · ROB 기반 순차 커밋
    │
    ▼
정밀 예외 · 고성능 OoO 마이크로아키텍처

이 흐름은 WAW가 단독 개념이 아니라, 단순 파이프라인에서 고성능 비순차 구조로 발전하는 과정에서 드러난 설계 과제임을 보여준다.

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

  1. 두 친구가 같은 이름표가 붙은 상자에 그림을 넣으려는데, 나중에 넣은 그림이 최종 그림이 되어야 해요.
  2. 그런데 먼저 시작한 친구가 늦게 와서 옛날 그림을 맨 마지막에 넣으면, 상자 안에는 틀린 그림이 남아요.
  3. 그래서 컴퓨터는 친구마다 임시 상자를 따로 주고, 마지막 발표할 때만 순서를 맞춰서 하나를 고른답니다.