모든 이야기

tail 정책: 같은 세 결과 뒤에 다른 다섯 값이 남는 이유

활성 원소 세 개의 덧셈 결과는 맞는데, 벡터 레지스터 전체를 비교한 검증은 실패했다. 나머지 다섯 원소가 어떤 코어에서는 이전 값이고 다른 코어에서는 모두 1인 비트열이었기 때문이다. 이런 가상 실패는 tail 정책을 계산 결과의 일부로 읽지 않았을 때 생길 수 있다. 사용하지 않은 원소도 모두 같은 값이어야 한다는 비교가 항상 옳지는 않다.

계산하는 영역과 남는 영역을 나눈다

RISC-V 벡터의 vl은 이번 명령에서 다루는 원소 수다. VLMAX=8, vl=3, vstart=0인 일반적인 정수 벡터 연산을 생각하자. 인덱스 02는 이번 작업 범위이고 37은 tail이다. mask 없이 실행하면 앞의 세 원소가 활성 원소가 된다.

목적지의 이전 값이 [10,11,12,13,14,15,16,17]이고, 입력 벡터에 [1,2,3,4,5,6,7,8]이 들어 있다고 하자. 입력 각 원소에 100을 더하는 정상 연산에서 활성 결과는 [101,102,103]이다. 설명용 설정과 입력이며, 특정 코어의 시험 결과가 아니다.

나머지 다섯 원소는 덧셈 결과를 저장하는 자리가 아니다. 이 영역을 어떻게 처리할지가 vtype의 tail 정책에 의해 정해진다. RISC-V Vector, Prestart, Active, Inactive, Body, and Tail Element Definitions

tu는 유지하고 ta는 두 선택을 허용한다

tail-undisturbed인 tu에서는 목적지의 tail 값을 유지한다. 예제 결과 전체는 다음과 같다.

tu: [101,102,103,13,14,15,16,17]

tail-agnostic인 ta에서는 일반적인 데이터 목적지의 각 tail 원소가 이전 값을 유지하거나 모든 비트가 1인 값으로 바뀔 수 있다. SEW=32라면 두 번째 선택은 0xFFFFFFFF다. 허용되는 한 결과는 다음과 같다.

ta: [101,102,103,0xFFFFFFFF,14,0xFFFFFFFF,16,17]

각 원소에 두 선택이 섞일 수 있고, 같은 입력으로 실행해도 그 선택 패턴이 반드시 결정적일 필요는 없다. 그렇다고 0이나 임의의 무관한 비트열을 모두 허용한다는 뜻은 아니다. 이 일반 데이터 연산의 규정은 이전 값 또는 모든 비트가 1인 값이다. RISC-V Vector, Vector Tail Agnostic and Vector Mask Agnostic

이 때문에 같은 명령의 기능을 비교할 때 활성 원소에는 정확한 결과를 요구하고, tail에는 해당 정책의 허용 집합을 적용해야 한다. 위 예제의 tail 다섯 개에는 2⁵=32개의 이전 값/모두 1 조합이 있다. 하나의 기준 구현이 택한 조합과 다르다는 이유만으로 다른 구현을 틀렸다고 판단할 수 없다.

왜 이전 값을 버리는 선택을 만들었을까

레지스터 이름을 새 물리 레지스터로 바꾸는 구현에서는 활성 결과를 새 목적지에 쓸 수 있다. 하지만 사용하지 않는 tail까지 이전 값으로 유지해야 한다면 이전 물리 레지스터를 읽어 그 부분을 복사해야 한다. 프로그램이 그 값을 필요로 하지 않는다면 불필요한 데이터 전달이 된다. 원문은 agnostic 정책을 이런 구현 비용과 연결한다.

그렇다고 ta가 항상 tail을 덮어쓰거나 항상 더 빠르다는 보장은 없다. 이전 값을 그대로 두는 간단한 구현도 규약에 맞는다. ta는 프로그램이 값 보존을 요구하지 않는다는 뜻이고, tu는 보존을 요구하는 선택이다.

이 차이는 다음 명령에서 드러날 수 있다. vl을 8로 늘린 뒤 앞의 목적지를 입력으로 쓰면, 인덱스 3~7을 더 이상 ‘안 쓰는 부분’이라고 말할 수 없다. 그 값을 결과로 사용할 계획이라면 먼저 정의된 데이터를 채우거나, 앞 연산에서 필요한 보존 정책을 선택해야 한다. ta 뒤에 tail이 0으로 초기화되었다고 믿는 코드는 두 허용 결과 중 어느 쪽에서도 보장되지 않는다.

빈 작업과 mask 결과에는 별도 경계가 있다

tail 정책만으로 모든 벡터 목적지를 설명할 수는 없다. vstart가 vl 이상이면 작업 범위인 body가 없으므로, 일반 벡터 목적지의 tail도 agnostic 값으로 갱신되지 않는다. vl=0 역시 이 조건에 들어간다. 빈 작업에서 무조건 목적지 전체를 0xFFFFFFFF로 덮는 구현은 이 규칙과 맞지 않는다.

또 mask를 생성하는 명령의 목적지 tail은 vta와 무관하게 tail-agnostic이며, 일반 데이터 결과보다 더 넓은 허용 규정을 가진다. 일부 mask 생성 연산은 더 긴 작업량으로 계산했을 때의 mask 결과를 tail에 쓸 수도 있다. 따라서 이 글의 이전 값/0xFFFFFFFF 예제를 모든 mask 결과 비트에 그대로 적용해서는 안 된다. RISC-V Vector, agnostic policy 및 vstart와 vl의 경계

tail 정책은 계산되지 않은 부분을 소프트웨어가 얼마나 보존하려는지 표현한다. 세 개의 덧셈 결과를 확인하는 검증이라면 먼저 세 원소가 정확한지 보고, 나머지는 tu의 유지 조건이나 ta의 허용 조건으로 따로 판단해야 한다. 이 구분이 있어야 정상적인 구현 차이를 오류로 만들지 않으면서, 실제로 허용되지 않은 tail 변경도 놓치지 않는다.

tail 정책: 같은 세 결과 뒤에 다른 다섯 값이 남는 이유 · ariser