---
title: "register renaming: 같은 x5의 세 명령이 서로 다른 값을 지키는 법"
author: "브레이브브라우저쓰자"
published_at: "2026-10-14T23:52:03.981Z"
updated_at: "2026-10-06T00:35:12.020Z"
tags: ["register renaming"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/register-renaming-%EA%B0%99%EC%9D%80-x5%EC%9D%98-%EC%84%B8-%EB%AA%85%EB%A0%B9%EC%9D%B4-%EC%84%9C%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EA%B0%92%EC%9D%84-%EC%A7%80%ED%82%A4%EB%8A%94-%EB%B2%95"
ai_assisted: true
---

# register renaming: 같은 x5의 세 명령이 서로 다른 값을 지키는 법

이 글은 AI가 활용됐습니다.

[원문](https://ariser.io/@writer_a9817d5a8de0/register-renaming-%EA%B0%99%EC%9D%80-x5%EC%9D%98-%EC%84%B8-%EB%AA%85%EB%A0%B9%EC%9D%B4-%EC%84%9C%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EA%B0%92%EC%9D%84-%EC%A7%80%ED%82%A4%EB%8A%94-%EB%B2%95)

프로그램에는 같은 레지스터 이름이 자주 등장한다. 그런데 그 이름이 겹친다는 이유만으로 두 명령을 항상 차례대로 실행해야 하는 것은 아니다. 앞의 결과를 정말 필요로 하는 경우와, 서로 다른 값을 우연히 같은 이름에 담는 경우를 구분하면 실행할 수 있는 순서가 달라진다. register renaming은 이 구분을 실제 하드웨어의 저장 공간으로 옮기는 장치다.

## 같은 x5라도 다른 시점의 값이다

다음과 같은 가상 명령열을 보자. 각 줄의 번호는 프로그램 순서이며, x1에는 접근할 주소가 들어 있다.

```text
I1: x5 = load[x1]
I2: x6 = x5 + 1
I3: x5 = x7 + 2
```

I2는 I1이 읽어 온 값을 사용해야 한다. 이것이 실제 데이터 의존인 RAW, 즉 먼저 쓴 결과를 나중에 읽는 관계다. 이름을 아무리 바꾸어도 load 결과가 도착하기 전에 그 결과에 1을 더할 수는 없다.

반면 I1과 I3는 둘 다 x5에 쓴다는 관계다. 두 결과를 같은 저장 칸에 바로 쓰면 실행 완료 순서에 따라 최종 값이 뒤집힐 수 있다. 이것이 WAW다. I2가 옛 x5를 읽기도 전에 I3가 그 칸을 덮어쓰는 문제는 WAR다. 두 문제는 필요한 계산 결과가 서로 이어져서 생긴 것이 아니라, 제한된 이름과 저장 칸을 재사용하기 때문에 생긴다. BOOM의 원문 문서는 renaming의 목적을 WAW와 WAR를 제거하고 RAW를 남기는 것으로 설명한다. [BOOM, The Purpose of Renaming](https://docs.boom-core.org/en/latest/sections/rename-stage.html#the-purpose-of-renaming)

## 결과마다 별도의 물리적 자리를 준다

처음에 x5→p10, x6→p11, x7→p12, x1→p1이라고 매핑되어 있다고 하자. p는 실제 데이터를 담는 물리 레지스터 번호다. 새 목적지에는 사용하지 않는 번호를 하나씩 배정한다.

| 명령 | 읽을 물리 레지스터 | 새 목적지 | 그 이름의 이전 목적지 |
|---|---|---|---|
| I1 | p1 | p20 | p10 |
| I2 | p20 | p21 | p11 |
| I3 | p12 | p22 | p20 |

I1을 변환하면 x5의 현재 매핑이 p20이 된다. 따라서 뒤의 I2는 x5라는 이름 대신 p20을 읽는 명령으로 바뀐다. I3가 다시 x5에 쓸 때는 p22를 배정하고 현재 매핑을 바꾼다. 이미 변환된 I2의 소스 번호는 여전히 p20이다. I3가 실행된다고 I2의 입력이 p22로 바뀌지 않는다.

이제 I3는 p12만 준비되어 있다면 I1보다 먼저 계산을 끝낼 수 있다. 결과는 p22에 들어가므로 아직 도착하지 않은 I1의 p20과 충돌하지 않는다. I1이 나중에 p20을 채우면 I2가 그 값을 사용한다. 예를 들어 load 결과가 40이고 x7이 8이었다면 I2는 41, I3는 10을 만든다. load가 늦게 끝나도 I2가 11을 계산하는 잘못은 일어나지 않는다.

이 예에서 중요한 것은 소스 번호를 정하는 순서다. 여러 명령을 같은 사이클에 변환하더라도 I2는 같은 묶음의 I1이 만든 새 매핑을 봐야 한다. 묶음 시작 때의 x5→p10을 모두에게 복사하면 바로 RAW 관계를 잃는다. BOOM은 이러한 묶음 내부의 map 변경을 뒤의 의존 명령으로 전달해야 한다고 명시한다. [BOOM, The Rename Map Table](https://docs.boom-core.org/en/latest/sections/rename-stage.html#the-rename-map-table)

## 이름이 바뀌어도 실행의 계약은 남는다

새 번호를 배정했다고 값까지 생긴 것은 아니다. I2의 p20은 정확한 생산자를 가리키지만, load가 끝날 때까지 준비되지 않은 상태다. 준비 여부를 추적하고 실행 자원을 배정하는 과정이 따로 필요하다. renaming을 의존성 자체를 없애는 장치라고 이해하면 이 대기 시간을 설명할 수 없다.

또 I3가 먼저 끝났다고 프로그램이 볼 수 있는 최종 상태를 먼저 확정하지는 않는다. 예외나 잘못 예측한 경로를 처리하려면 프로그램 순서에 맞는 상태로 돌아갈 수 있어야 한다. BOOM의 물리 레지스터 파일은 확정된 상태와 추측 중인 상태를 함께 보관하고, 매핑 정보로 어느 값이 어떤 상태에 속하는지 구별한다. 결과 데이터 전부가 별도의 architectural register file에 즉시 복사된다고 생각하면 이 설계와 맞지 않는다. [BOOM, The Explicit Renaming Design](https://docs.boom-core.org/en/latest/sections/rename-stage.html#the-explicit-renaming-design)

물리 레지스터도 무한하지 않다. 이전 값은 더 오래된 명령이나 복구 상태에서 필요할 수 있으므로, 새 매핑을 만들자마자 이전 번호를 재사용할 수 없다. BOOM은 명령이 commit할 때 그 명령이 대체한 이전 목적지 번호를 반환한다. 위 예에서는 I3가 p20을 대체했다는 기록이 있어야 적절한 시점에 p20을 돌려줄 수 있다. [BOOM, Stale Destination Specifiers](https://docs.boom-core.org/en/latest/sections/rename-stage.html#stale-destination-specifiers)

register renaming이 얻는 자유는 명확하다. I3처럼 앞의 계산값을 쓰지 않는 명령이 레지스터 이름의 충돌 때문에 기다리는 일을 줄인다. 동시에 I2처럼 실제로 결과가 필요한 명령은 정확히 그 결과의 물리적 자리를 기다리게 한다. 같은 x5의 여러 시점을 서로 다른 값으로 보관할 수 있을 때, 실행 순서를 바꾸면서도 프로그램이 요구한 결과를 지킬 수 있다.

