Solution to Problem 4.39
From Figure 4.66, we can see that pipeline register D must be stalled for a load/use hazard:
그림 4.66에서 볼 수 있듯이, load/use 해저드가 발생할 경우 파이프라인 레지스터 D는 스톨되어야 한다.

Pipeline register D : 파이브라인의 D 단계 레지스터
Stalled : 멈추다 / 지연시키다
Load/Use Hazard : 적재-사용 데이터 해저드
Processing ret : ret(return) 명령어를 처리 중인 상황
→ ret 명령어를 처리 중인 상황으로, 반환 주소가 M 단계에서 결정되기 전까지 다음 PC를 알 수 없기 때문에 파이프라인 앞단을 제어해야 하는 상태
Combination : ret 처리 + load/use 해저드가 동시에 발생한 경우
Desired : 실제로 우리가 원하는 이상적인 제어 동작
→ 여러 해저드가 동시에 발생하더라도, 파이프라인의 올바른 실행을 보장하면서 중복을 제거한 최소한의 stall/bubble만 적용한 최종적으로 의도한 제어 동작
? Load/Use Hazard란?
컴퓨터 파이프라인에서 데이터 의존성으로 인해 발생하는 문제로, 메모리에서 데이터를 로드하는 명령어(Load) 바로 다음에 그 데이터를 사용하려는 명령어(Use)가 나올 때 발생한다.
Load명령어 : 메모리에서 데이터를 읽어와 레지스터에 저장한다. 이 데이터는 MEM(Memory Access)단계에서 준비된다.
Use 명령어 : 바로 다음에 오는 명령어가 이전 Load 명령어의 결과를 필요로 한다.
Hazard : 파이프라인 CPU에서 명령어들이 겹쳐서 실행될 때, 정상적인 실행을 방해하는 충돌 상황을 말한다.
? 왜 Hazard가 발생하는가?
파이프라인에서는 여러 명령어가 동시에 다른 단계에서 실행되는데, 이런 경우는 · ·
- 필요한 데이터가 아직 준비되지 않았을 경우
- 필요한 자원이 이미 사용중인 경우
- 다음에 실행할 명령어 주소가 아직 확정되지 않았을 경우
· · · 에 발생한다.
즉, Load/Use Hazard는 Use라는 명령어로 인해, 앞전에 사용한 명령어(Load)의 결과를 필요로 하는데, Load 명령어가 아직 메모리에서 값을 가져오는 중이어서 그 결과를 즉시 사용할 수 없을 때 발생하는 해저드이다.
(쉽게 말해서 아직 필요한 데이터가 준비되지 않아서 발생한다.)
오해할 수 있는 점 : 위 해저드가 발생하는 장소는 M 파이프라인이다.
↑ 이는 잘못된 생각이다.
위 해저드의 원인은 Load의 명령어의 결과가 M 단계에서 생성된다는 점에 있지만,
발생 위치가 M 파이프라인이라는 소리는 아니다.
정확히는 Use가 필요로 하는 Load의 결과값이 준비될 때까지의 시간을 확보하기 위해서
D 파이프라인에서 일시적으로 Stall(정지)를 시키는데,
이때 자연스레 Use가 명령어를 실행하기까지 지연 시간이 발생한다.
이처럼 발생되는 지연 현상을 Load/Use Hazard라고 말할 수 있다.
한줄로 표현하자면,
Load 결과가 준비될 때까지 D 단계에서 기다림으로서 발생하는 지연 현상을 의미한다.

bool : 참 혹은 거짓을 판단하는 변수 타입
D_stall : D 파이프라인을 멈출(stall) 여부를 나태나는 변수
bool D_stall의 값이 true면, D단계에서 정지 / false면, 정지 불필요
# Conditions for a load/use hazard : load/use hazard를 위한 조건
E_icode : 현재 E 파이프라인 단계에 있는 명령어의 종류
IMRMOVQ : 메모리 주소 결과를 기반으로, 메모리로부터 8바이트의 값을 읽어 레지스터에 저장하는 Load 명령어이다.
IPOPQ : 스택 포인터($rsp)가 가리키는 메모리 위치에서 값을 읽어 레지스터에 저장하고, 동시에 스택 포인터를 증가시키는 Load 계열 명령어이다.
E_dstM : E 단계 Load 명령어가 메모리에서 읽어와서 저장할 목적지 레지스터
d_srcA : D 파이프라인 단계에 있는 명령어가 첫 번째 입력값으로 읽어야하는 소스 레지스터를 나타낸다.
d_srcB : D 파이프라인 단계에 있는 명령어가 두 번째 입력값으로 읽어야하는 소스 레지스터를 나타낸다.
load/use hazard를 위한 조건을 해석해보면, 현재 E 파이프라인 단계에 있는 명령어가 메모리로부터 값을 읽어오는 Load 계열 명령어이며,
D 파이프라인 단계에 있는 명령어 첫 번째 입력값 또는 두 번째 입력값을 필요로 한다면 true를 반환하여 D 파이프라인을 멈춤으로서 명령어의 충돌을 방지한다.
? 왜 이런 문제점이 있어도 Load와 Use를 붙여서 사용하는건가?
Load와 Use는 프로그램 의미상 자연스럽게 연속해서 나타나며,
이를 억지로 분리하는 것보다 하드웨어가 필요로 할 때만 잠깐 Stall하는 것이
전체 성능과 코드 단순성 측면에서 훨씬 효율적이기 때문이다.
? Load/Use Hazard가 일어나는 근본적인 이유
위 해저드가 일어나는 근본적인 이유는 파이프라인의 구조적인 한계 때문이다.
컴파일러는 되도록이면 이를 회피하기 위해 컴파일러가 노력은 하지만 그것 또한 완벽한 것이 아니다.
그렇기에 근본적인 해결책이 없기에 그나마 효율성 측면에서 우수한 해결방안의 결과물이 Load/Use Hazard이다.
Solution to Problem 4.40
From Figure 4.66, we can see that pipeline register E must be set to bubble for a load/use hazard or for a mispredicted branch:
그림 4.66에서 볼 수 있듯이, Load/Use Hazard가 발생했거나 분기 예측이 틀린 경우에는 파이프라인 레지스터 E를 버블(Bubble)로 설정해야 한다.
Set to Bubble : 버블을 삽입한다.(의미 없는 명령어를 넣어 파이프라인을 한 사이클 비워두는 것)
Mispredicted Branch : 분기 예측 실패
? Set to Bubble이란?
E 레지스터를 Bubble로 설정한다는 것은 Use 명령어를 한 사이클 뒤로 밀어내고, 그 자리에 부작용 없는 NOP를 삽입하는 것을 의미한다.
Stall과 Bubble의 차이점
| 구분 | Stall | Bubble |
| 레지스터 값 | 유지 | NOP로 덮어씀 |
| 명령어 흐름 | 정지 | 진행 |
| 목적 | 대기 | 무효화 |
? 왜 Stall이 아닌 Bubble을 사용하는가?
Stall이 아닌 Bubble을 사용하는 근본적인 이유는 Stall와 Bubble의 차이점을 보면 쉽게 알 수 있다.
Stall은 "현재 명령어를 유지"한다. 그런 반면, Bubble은 "현재 명령어를 무효화(NOP)"한다.
즉, Bubble은 "현재 명령어가 실행 됐을 때, 무언가 문제가 발생할 우려가 있을 경우 사용되는 명령어"이다.
? 분기 예측 실패란 무엇인가?
분기 예측 실패란, CPU가 조건문(Branch)의 다음 실행 경로를 미리 추측(예측)하였으나, 실제 실행 결과가 예측과 달라서 잘못된 명령어들이 파이프라인에 들어온 상태를 말한다.
? 무효화 진행 후, 파이프라인은 어떻게 동작하는가?
무효화 이후에는 E 단계에서 계산된 실제 실행 결과를 바탕으로 PC를 결정하고, 해당 PC를 기준으로 Fetch 단계부터 명령어 가져오기가 다시 시작된다.

bool : 참 혹은 거짓을 판단하는 변수 타입
E_icode : E 파이프라인을 나태나는 변수
IJXX : 분기 명령어를 나타내는 명령어
e_Cnd : 분기 예측 결과가 참인지 거짓인지 나타내는 변수
bool E_bubble의 값이 true이면, E단계에 bubble을 삽입 / 값이 false이면 정상적인 명령어 전달
# Mispredicted branch : 분기 예측 실패
E_icode : 현재 E 파이프라인 단계에 있는 명령어의 종류
IMRMOVQ : 메모리 주소 결과를 기반으로, 메모리로부터 8바이트의 값을 읽어 레지스터에 저장하는 Load 명령어이다.
IPOPQ : 스택 포인터($rsp)가 가리키는 메모리 위치에서 값을 읽어 레지스터에 저장하고, 동시에 스택 포인터를 증가시키는 Load 계열 명령어이다.
E_dstM : E 단계 Load 명령어가 메모리에서 읽어와서 저장할 목적지 레지스터
d_srcA : D 파이프라인 단계에 있는 명령어가 첫 번째 입력값으로 읽어야하는 소스 레지스터를 나타낸다.
d_srcB : D 파이프라인 단계에 있는 명령어가 두 번째 입력값으로 읽어야하는 소스 레지스터를 나타낸다.
E_icode가 Load 계열(IMRMOVQ, IPOPQ)이거나 분기 명령어(IJXX)일 때, 그 실행 결과가 아직 확정되지 않았는데 다음 명령어가 이를 사용하려 하면 파이프라인 충돌이 발생할 수 있으므로 이를 판단하기 위해 위 변수들이 사용된다.
? 분기 예측 실패의 근본적인 원인
분기 예측 실패는 분기 명령어의 실제 결과가 실행 단계에서야 결정되기 때문에, 그 이전에 이루어진 것은 그저 기존 데이터를 기반으로 예측한 값이기 때문에 항상 예측이 성공할 수 없다는 구조적 한계에서 발생한다.
예측된 미래(결과)가 항상 참인 경우는 현실적으로 존재할 수 없다.
Solution to Problem 4.41
This control requires examining the code of the executing instruction and checking for exceptions further down the pipeline.
이 제어는 실행 중인 명령어의 코드(명령어 종류)를 확인하고, 파이프라인의 더 뒤쪽 단계에서 발생한 예외가 있는지를 검사하는 것을 필요로 한다.
파이프라인 이후 단계 : 현재 기준이 되는 파이프라인 단계보다 시간적으로 더 나중에 실행되는 단계들을 의미한다. 즉, 명령어가 실행되는 E 단계를 기준으로 했을 때, 그 뒤에 위치한 M, W단계가 '파이프라인 이후 단계'에 해당한다.
? 예외가 발생하는 이유와 해결 방안
예외 : 예외란, 명령어 실행 도중 정상적인 실행을 계속할 수 없게 만드는 이벤트이다.
? 왜 예외가 발생하는가?
- 명령어 자체에 문제가 있을 경우
- 메모리 접근에 문제가 발생할 경우
- 실행 중인 계산 결과가 문제일 경우
- 그 외 각종 외부 요인으로 인한 경우
? 왜 파이프라인에서는 예외가 문제가 되는가?
파이프라인에서는 여러 명령어가 동시에 실행되며 서로 밀접하게 연결되어 있기 때문에, 하나의 명령어에서 예외가 발생할 경우 그 영향이 다른 명령어들까지 전파되어 프로그램 상태에 오류를 유발할 위험이 있다.
따라서 파이프라인 구조에서는 예외 처리를 더욱 신중하게 수행해야 한다.
? 예외 처리의 핵심 목표는 무엇인가?
예외가 발생했을 때, 예외 명령어 이전의 명령어는 모두 완료되고, 이후 명령어는 하나도 실행되지 않은 상태를 보장하는 것이 핵심 목표이다.
우리는 이를 정확한 예외 처리(Precise Exception Handling)라고 부른다.
? 파이프라인에서의 해결 방안은 무엇인가?
이후 단계의 예외를 우선적으로 처리한다.
더 뒤에 있는 명령어가 더 먼저 실행된 것이므로 당연히 뒤 단계 예외를 우선적으로 처리해야 한다.
오해할 수 있는 점 : 뒤에 있는 단계면 당연히 나중에 실행되는 것 아닌가?
↑ 이는 잘못된 생각이다.
이런 착각이 생기는 이유는 다음 5단계 파이프라인을 보면 쉽게 이해할 수 있을 것이다.
| 사이클 | F | D | E | M | W |
| 1 | l1 | ||||
| 2 | l2 | l1 | |||
| 3 | l3 | l2 | l1 | ||
| 4 | l4 | l3 | l2 | l1 | |
| 5 | l5 | l4 | l3 | l2 | l1 |
W에 있는 l1이 가장 먼저 실행된 명령어
F에 있는 l5가 갖아 나중에 실행되는 명령어
이처럼 명령어가 병렬로 처리되는 파이프라인은 명령어가 단일로 처리되는 흐름과 다르게 "시간이 겹치는 현상"이 발생한다. 그렇기에 다음과 같이 더 뒤에 있는 단계가 먼저 실행된다.

## Should the condition codes be updated? : 조건 코드(CC)를 업데이트 해도 되는가?
bool : 참 혹은 거짓을 판단하는 변수 타입
set_cc : 조건 코드(CC)를 타나내는 변수
bool set_cc의 값이 true이면, 조건 코드 업데이트 / false이면, 현재 상태를 유지
E_icode == IOPQ : 현재 E 단계의 명령어가 산술/논리 연산 명령어인가?
# State changes only during normal operation : 프로그램 상태는 파이프라인이 정상적으로 실행되고 있는 경우에만 변경되어야 한다.
m_stat in { SADR, SINS, SHLT } : M 단계가 현재 상태가 정상인가?
- SADR : 정상 주소
- SINS : 정상 명령어
- SHLT : 정상 종료
W_stat in { SADR, SINS, SHLT } : W 단계가 현재 상태가 정상인가?
↑ 즉, M, W 단계에서 예외가 발생하지 않았는지를 확인한다.
E 단계의 명령어가 산술/논리 연산(IOPQ)이고, 파이프라인의 뒤 단계(M, W)에서 어떤 예외도 발생하지 않은 경우에만 조건 코드를 갱신한다.
? 조건 코드(CC)란 무엇인가?
조건 코드(Condition Codes, CC)는 최근에 수행된 연산의 결과 상태를 요약해서 저장해 두는 CPU의 상태 비트들이다.
즉, "방금 계산한 결과가 어떤 상태였는가?"를 기록해 두는 플래그다.
Y86-64 / x86 계열의 대표적인 조건 코드
- ZF (Zero Flag)
- 연산 결과가 0이면 1
- 아니면 0
- SF (Sign Flag)
- 연산 결과가 음수이면 1
- 아니면 0
- OF (Overflow Flag)
- 부호 있는 연산에서 오버플로가 발생하면 1
- 아니면 0
? 조건 코드(CC)를 사용하는 이유는 무엇인가?
조건 코드를 사용하는 근본적인 이유는, CPU가 고급 언어에서처럼 별도의 비교 연산을 수행하지 않기 때문이다.
CPU는 단순히 연산을 수행하고, 그 결과의 ‘상태’만을 이용해 프로그램의 흐름을 제어한다.
이를 위해 CPU는 연산 결과의 상태를 간단한 플래그 형태로 요약한 조건 코드(Condition Codes)를 사용하며, 이를 통해 별도의 비교 결과를 생성하지 않고도 분기 명령어와 자연스럽게 연결할 수 있다.
결과의 상태 : 연산이 끝난 뒤, '결과 값 그 자체'가 아닌 그 결과가 어떤 성질을 가지고 있는지를 요약한 데이터이다.
Solution to Problem 4.42
Injecting a bubble into the memory stage on the next cycle involves checking for an exception in either the memory or the write-back stage during the current cycle.
다음 사이클에서 메모리 단계에 버블을 삽입하는 것은, 현재 사이클 동안 메모리(M) 단계나 쓰기(W) 단계 중 어느 한쪽에서라도 예외가 발생했는지를 확인하는 과정을 포함한다.
| 사이클 | F | D | E | M | W |
| 1 | l1 | ||||
| 2 | l2 | l1 | |||
| 3 | l3 | l2 | l1 | ||
| 4 | l4 | l3 | l2 | l1 | |
| 5 | l5 | l4 | l3 | l2(예외 발생) | l1 |
| 6 | l6 | l5 | l4 | NOP ← 삽입 | l2 |
| 7 | 예외 처리 주소 | NOP | NOP | NOP | NOP |
| ... | ... | ... | ... | ... | ... |
| 7+N | l1 |
예외 처리 이후의 실행은 이전 파이프라인 흐름과 논리적으로 이어지지 않으며, 새로운 파이프라인 실행이 시작된다.
? 왜 M 단계에 Bubble을 넣는가?
M 단계는 메모리 읽기/쓰기 단계이기에 프로그램 상태에 직접적인 영향을 끼칠 수 있다.
? 왜 W 단계는 계속해서 진행되는가?
W 단계의 l1, l2는 이미 실행된 명령어이다.
정확한 예외 처리 조건상 예외 이전 명령어는 완료되어야 하는 상태여야 한다. 따라서 W는 그대로 정상 진행된다.

# Start injecting bubbles as soon as exception passes through memory stage : 예외가 메모리 단계를 통과하는 순간부터 메모리 단계에는 더 이상 정상 명령어를 넣지 말고 버블을 주입하기 시작해라.
M_bubble의 값이 true이면, M 단계에서 bubble 삽입 / false이면, 정상적으로 명령어 진행
m_stat in : 현재 M 단계 명령어 상태
W_stat in : 현재 W 단계 명령어 상태
m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT } : M 단계 또는 W 단계 중 어느 한쪽이라도 예외 상태가 감지죄면, 다음 사이클부터 메모리 단계에 버블을 삽입한다.
Practice Problem 4.43
Suppose we use a branch prediction strategy that achieves a success rate of 65%, such as backward taken, forward not taken (BTFNT), as described in Section 4.5.4. What would be the impact on CPI, assuming all of the other frequencies are not affected?
4.5.4절에서 설명한 BTFNT(뒤로 가는 분기는 taken, 앞으로 가는 분기는 not taken)와 같이 분기 예측 성공률이 65%인 분기 예측 전략을 사용한다고 가정하자.
다른 빈도들은 모두 변하지 않는다고 할 때, CPI에는 어떤 영향이 있겠는가?
Solution to Problem 4.43
We would then have a misprediction frequency of 0.35, giving mp = 0.20 × 0.35 × 2 = 0.14, giving an overall CPI of 1.25. This seems like a fairly marginal gain, but it would be worthwhile if the cost of implementing the new branch prediction strategy were not too high.
그러면 분기 예측 실패 빈도(misprediction frequency)는 0.35가 된다.
이에 따라 분기 예측으로 인한 평균 페널티(mp)는 0.20 × 0.35 × 2 = 0.14가 되고, 전체 CPI는 1.25가 된다.
이는 보기에 큰 개선은 아닌 것처럼 보이지만, 새로운 분기 예측 전략을 구현하는 비용이 크지 않다면 충분히 고려할 만한 개선이다.
? BTFNT란 무엇인가?
BTFNT(Backward Taken, Forward Not Taken)는 분기의 방향(앞/뒤)에 따라 분기 여부를 예측하는 정적 분기 예측 전략이다.
Backward(뒤로 가는 분기) → Taken(분기함)으로 예측
Foreward(앞으로 가는 분기) → Not Taken(분기 안함)으로 예측
? 왜 이런 전략을 쓰는가?
프로그램의 경험적 특성 때문
- Backward
→ 보통 루프
- 루프는 대부분 여러 번 반복함
→ 분기함(Taken)일 확률 높음
- Foreward
→ if문 종료, 예외처리
→ 분기 안함일 확률 높음
? CPI란 무엇인가?
CPI(Cycles Per Instruction)는 명령어 하나를 실행하는 데 평균적으로 몇 사이클이 걸리는지를 나타내는 지표이다.
즉, CPI가 낮을 수록 성능이 좋은 CPU이다.
Practice Problem 4.44
Let us analyze the relative performance of using conditional data transfers versus conditional control transfers for the programs you wrote for Problems 4.5 and 4.6. Assume that we are using these programs to compute the sum of the absolute values of a very long array, and so the overall performance is determined largely by the number of cycles required by the inner loop. Assume that our jump instructions are predicted as being taken, and that around 50% of the array values are positive.
문제 4.5와 4.6에서 작성한 프로그램들을 대상으로, 조건부 데이터 전송(conditional data transfer)과 조건부 제어 전송(conditional control transfer)을 사용하는 경우의 상대적인 성능을 분석해보자.
이 프로그램들이 매우 긴 배열에 대해 절댓값들의 합을 계산하는 데 사용된다고 가정하자.
따라서 전체 성능은 주로 내부 루프(inner loop)를 실행하는 데 필요한 사이클 수에 의해 결정된다.
또한 점프 명령어는 항상 분기됨(taken)으로 예측되며, 배열 원소 중 약 50%가 양수라고 가정한다.
A. On average, how many instructions are executed in the inner loops of the two programs?
A. 평균적으로, 두 프로그램의 내부 루프에서 각각 몇 개의 명령어가 실행되는가?
B. On average, how many bubbles would be injected into the inner loops of the two programs?
B. 평균적으로, 두 프로그램의 내부 루프에서 각각 몇 개의 버블(bubble)이 삽입되는가?
C. What is the average number of clock cycles required per array element for the two programs?
C. 두 프로그램에서 배열 원소 하나당 평균적으로 몇 개의 클럭 사이클이 필요한가?
Solution to Problem 4.44
This simplified analysis, where we focus on the inner loop, is a useful way to estimate program performance. As long as the array is sufficiently large, the time spent in other parts of the code will be negligible.
이와 같이 내부 루프(inner loop)에만 집중하는 단순화된 분석은 프로그램의 성능을 추정하는 데 유용한 방법이다.
배열의 크기가 충분히 크다면, 코드의 다른 부분에서 소비되는 시간은 전체 실행 시간에 비해 무시할 수 있을 정도로 작아진다.
A. The inner loop of the code using the conditional jump has 11 instructions, all of which are executed when the array element is zero or negative, and 10 of which are executed when the array element is positive. The average is 10.5. The inner loop of the code using the conditional move has 10 instructions, all of which are executed every time.
A. 조건부 점프(conditional jump)를 사용하는 코드의 내부 루프에는 총 11개의 명령어가 있다.
이 중 배열 원소가 0이거나 음수일 때는 11개 전부가 실행되고, 배열 원소가 양수일 때는 10개만 실행된다.
따라서 평균적으로 실행되는 명령어 수는 10.5개이다.
반면, 조건부 이동(conditional move)을 사용하는 코드의 내부 루프에는 10개의 명령어가 있으며, 매번 모두 실행된다.
B. The loop-closing jump will be predicted correctly, except when the loop terminates. For a very long array, this one misprediction will have a negligible effect on the performance. The only other source of bubbles for the jumpbased code is the conditional jump, depending on whether or not the array element is positive. This will cause two bubbles, but it only occurs 50% of the time, so the average is 1.0. There are no bubbles in the conditional move code.
B. 루프를 끝내는 점프(loop-closing jump)는 루프가 종료되는 순간을 제외하면 항상 정확하게 예측된다.
배열이 매우 길다고 가정하면, 이 한 번의 예측 실패는 성능에 거의 영향을 미치지 않는다.
점프 기반 코드에서 발생하는 유일한 추가 버블(bubble)의 원인은 배열 원소가 양수인지 여부에 따라 실행되는 조건부 점프이다.
이 경우 버블이 2개 발생하지만, 배열 원소가 양수일 확률이 50%이므로 평균적으로는 1.0개의 버블이 발생한다.
조건부 이동을 사용하는 코드에서는 버블이 전혀 발생하지 않는다.
C. Our conditional jump code requires an average of 10.5 + 1.0 = 11.5 cycles per array element (11 cycles in the best case and 12 cycles in the worst), while our conditional move code requires 10.0 cycles in all cases. Our pipeline has a branch misprediction penalty of only two cycles—far better than those for the deep pipelines of higher-performance processors. As a result, using conditional moves does not affect program performance very much.
C. 조건부 점프를 사용하는 코드는 배열 원소 하나당 평균적으로 10.5(명령어) + 1.0(버블) = 11.5 사이클이 필요하다. (최선의 경우 11사이클, 최악의 경우 12사이클)
반면, 조건부 이동을 사용하는 코드는 모든 경우에 항상 10.0 사이클이 필요하다.
우리의 파이프라인은 분기 예측 실패 페널티가 단 2사이클로, 고성능 프로세서의 깊은 파이프라인에 비해 매우 작다.
그 결과, 조건부 이동을 사용하더라도 프로그램 성능에는 큰 차이가 나지 않는다.
? 조건부 제어 전송이란 무엇인가?
조건에 따라 프로그램의 제어 흐름(PC)을 바꾸는 방식이다. 즉, 분기(branch) 를 사용한다.
? 조건부 데이터 전송이란 무엇인가?
제어 흐름은 바꾸지 않고, 조건에 따라 "데이터 값"만 선택적으로 갱신하는 방식이다.
1. 개념 비교 표
| 구분 | 조건부 제어 전송 | 조건부 데이터 전송 |
| 기본 개념 | 조건에 따른 실행 흐름(PC) 변경 | 조건에 따라 데이터 값만 변경 |
| 핵심 수단 | 분기(branch) | 조건부 이동(cmov) |
| PC 변경 | 있음 | 없음 |
| 실행 경로 | 조건에 따라 달라짐 | 항상 동일 |
| 조건 사용 | 조건 코드(CC) | 조건 코드(CC) |
2. 파이프라인 관점 비교
| 항목 | 조건부 제어 전송 | 조건부 데이터 전송 |
| 분기 예측 필요 | 필요 | 불필요 |
| 분기 예측 실패 | 가능 | 없음 |
| Bubble 발생 | 있음 | 없음 |
| Flush 필요 | 있음 | 없음 |
| 파이프라인 안정성 | 낮음(예측 의존) | 높음(항상 동일 흐름) |
3. 실행 특성 비교 (성능 관점)
| 항목 | 조건부 제어 전송 | 조건부 데이터 전송 |
| 불필요한 명령 실행 | 없음 | 있을 수 있음 |
| 실행 명령어 수 | 조건에 따라 달라짐 | 항상 동일 |
| 분기 패널티 영향 | 큼 | 없음 |
| 분기 패널티가 클 때 | 불리함 | 유리함 |
| 분기 패널티가 작을 때 | 유맇마 | 차이 작음 |
4. 예시 흐름 비교 표
| 항목 | 조건부 제어 전송 | 조건부 데이터 전송 |
| 조건 | 조건 참 | 조건 참 |
| 실행 흐름 | 분기 → 다른 코드 실행 | 데이터 이동 |
| 조건 | 조건 거짓 | 조건 거짓 |
| 실행 흐름 | 분기 안함 → 다음 코드 | 아무 변화 없음 |
5. 문제 4.44와 연결되는 핵심 요약 표
| 항목 | 조건부 점프 코드 | 조건부 이동 코드 |
| 평균 명령어 수 | 10.5 | 10 |
| 평균 bubble 수 | 1.0 | 0 |
| 평균 사이클 수 | 11.5 | 10.0 |
| 성능 안정성 | 에측 의존 | 매우 안정 |
'컴퓨터과학(CS) > CS문제 풀이' 카테고리의 다른 글
| Solution to Problem 5.9 (0) | 2026.01.18 |
|---|---|
| Solution to Problem 5.8 (0) | 2026.01.18 |
| Solution to Problem 5.7 (0) | 2026.01.18 |
| 어셈블리 명령어 단계별 실행 분석 – Problem 4.14 (0) | 2025.12.28 |
| [CS 문제 풀이] 어셈블리 코드 분석 및 C 코드 동작 해석 (0) | 2025.12.26 |
