모든 이야기

fetch packet mask: 분기 뒤에 가져온 명령은 어디까지 살아 있을까

CPU가 한 번에 명령 네 개를 가져왔다. 두 번째 명령이 taken 분기라면, 같은 묶음의 세 번째와 네 번째 명령은 메모리에서 읽혔다는 이유만으로 실행해도 될까? 그 명령들은 현재 예측 경로에서 분기 뒤에 남은 바이트일 뿐이다. fetch packet mask는 가져온 묶음 중 어디까지 후속 파이프라인에 보낼지를 표시한다.

이 mask가 없거나 위치가 한 칸 틀리면, 목적지 PC를 정확하게 예측하고도 잘못된 명령을 함께 보낼 수 있다. 프런트엔드의 정확성은 다음 주소를 고르는 일과 지금 묶음의 유효한 부분을 고르는 일이 함께 맞아야 성립한다.

taken 분기까지는 남기고 뒤는 잘라낸다

계산을 분명하게 하기 위해 32비트 명령만 있는 가상의 네 슬롯을 쓰자. 주소는 순서대로 0x100, 0x104, 0x108, 0x10C다. 슬롯 0이 비트 0이며, 표시한 비트열의 오른쪽 끝이 슬롯 0이라고 정의한다. 모든 슬롯이 유효하면 mask는 1111이다.

0x104의 분기를 taken으로 예측했다면 0x100의 명령과 분기 명령 자체는 남긴다. 그 뒤 0x108과 0x10C는 이 경로에서 제외한다. mask는 0011이다. 분기 명령까지 지워 버리면 나중에 실제 조건과 목적지를 확인할 명령을 잃는다. 반대로 0111이면 분기 뒤의 한 명령을 추가로 허용한다.

이 간단한 모델에서 taken으로 선택된 슬롯 번호가 b이면 하위 b+1개 비트를 1로 만드는 mask를 쓸 수 있다. b=0,1,2,3에 대해 0001,0011,0111,1111이다. 분기가 묶음의 마지막 슬롯에 있으면 그 묶음 안에서 지울 명령은 없지만, 다음 fetch 주소는 여전히 바뀐다.

BOOM의 NLP 문서는 bidx가 fetch 묶음에서 제어 흐름을 바꾸는 명령의 위치를 나타내며, taken 분기 뒤의 다른 명령들을 mask하는 데 필요하다고 설명한다. 목적지 주소 하나와 분기 위치 하나가 서로 다른 역할을 맡는 것이다. BOOM NLP, NLP Predictions

어느 분기가 먼저 경로를 바꾸는가

같은 묶음에 분기가 여러 개 있을 수 있다. 0x104와 0x108이 모두 분기라고 하자. 앞의 0x104를 taken으로 선택했다면 뒤의 0x108 분기도 그 경로에서는 도달하지 않으므로 이번 묶음의 redirect를 결정하지 않는다. 앞 분기는 not-taken, 뒤 분기는 taken이라면 mask는 0111이고 목적지는 뒤 분기의 것이 된다.

따라서 방향 비트들을 받았다고 아무 taken 하나나 고를 수 없다. 명령 순서와 실제 명령 시작 위치를 사용해 도달 가능한 첫 경로 변경을 골라야 한다. 가상의 네 슬롯 예에서는 각 슬롯이 하나의 완전한 명령이지만, 16비트와 32비트 명령이 섞이면 슬롯의 의미부터 정렬·해독 결과에 맞춰야 한다. 32비트 명령의 뒤 절반을 별도 분기 후보로 해석하면 mask도 잘못 만들어진다.

처음 들어온 묶음에 이미 invalid 슬롯이 있다면 분기 mask만으로 그것들을 다시 유효하게 만들 수 없다. 기본 valid 정보와 명령 경계, 선택된 분기 위치로 만든 유효 범위를 함께 적용해야 한다. redirect로 묶음 중간 주소부터 시작하는 경우도 앞쪽 슬롯들이 자동으로 실행 대상이 되지는 않는다.

지운 명령이 틀린 예측 뒤에서 다시 필요해진다

0x104를 taken으로 예측하여 0x108과 0x10C를 보내지 않았는데, 실제 분기가 not-taken이라고 나중에 밝혀질 수 있다. 이 경우 그 명령들은 실제 경로에서 다시 필요하다. 프런트엔드는 올바른 주소로 돌아가 필요한 명령을 가져오거나, 구현에서 허용한 복구 경로로 다시 제공해야 한다. mask는 투기적인 유효 범위를 결정한 것이며, 프로그램의 최종 실행 경로를 확정한 것이 아니다.

반대 상황도 있다. 앞 분기를 not-taken으로 보아 뒤 명령들이 이미 넘어갔는데 실제로는 taken이었다면, 그 분기에 의존하여 진행한 뒤쪽 명령들을 취소해야 한다. fetch 묶음의 mask와 실행 중인 명령들의 투기 의존성 관리는 같은 비트열일 필요가 없다. 서로 다른 시점의 유효성을 나타내므로 각각의 수명과 의미를 구분한다.

BOOM의 fetch 문서는 묶음에 valid mask와 예측 정보를 실어 보내고, fetch buffer가 유효하지 않은 명령 등을 압축하여 저장하는 과정을 설명한다. 읽어 온 슬롯 수가 그대로 실행할 명령 수가 되지 않는 구조다. BOOM Instruction Fetch, Front-end 및 Fetch Buffer

넓게 가져올수록 함께 맞춰야 할 정보

넓은 fetch는 한 번에 많은 명령을 공급할 기회를 만든다. 하지만 묶음 안에서 분기가 일찍 나타나면 실제 공급 가능한 명령은 적다. 네 슬롯을 읽고 두 슬롯만 보냈다면 이 묶음의 유효 활용은 절반이다. 이것을 모든 프로그램의 평균 fetch 효율로 일반화할 수는 없지만, 바이트 대역폭과 유효 명령 공급을 구분하는 예다.

검증에서는 분기를 각 슬롯에 하나씩 옮겨 보는 작은 테스트가 유용하다. 이어 여러 분기, 앞쪽 invalid 슬롯, 출력 대기와 오예측 복구를 함께 넣고 명령 PC와 mask가 같은 묶음에 붙어 있는지 확인한다. 목적지 주소만 비교하는 테스트로는 분기 뒤의 명령이 잘못 통과하는 경우를 놓칠 수 있다.

fetch packet mask는 가져온 명령을 지우기 위한 부수 신호가 아니다. 현재 경로에서 어떤 명령을 다음 단계로 넘겼는지 정하는 정보다. 다음 fetch를 올바른 목적지로 돌리면서 현재 묶음도 올바른 분기 위치에서 끊어야, 넓은 명령 공급이 올바른 실행으로 연결된다.