VLIW

최장 명령어 워드(Very Long Instruction Word, VLIW)는 병렬로 실행될 명령어를 미리 명시적으로 지정함으로써 명령어 수준 병렬성(ILP)을 활용하도록 설계된 명령어 집합 구조의 한 유형이다.

VLIW 아키텍처는 ILP를 활용하는 가장 지배적인 방식인 슈퍼스칼라 아키텍처와 대조된다. 슈퍼스칼라는 하드웨어가 실행 시간에 동적으로 병렬 실행을 찾아내고 스케줄링하지만, VLIW의 주된 목적은 슈퍼스칼라 설계의 하드웨어 복잡성 없이 더 높은 성능을 달성하는 것이다. 명령어 스트림을 반복적으로 분석하고 실행 시간에 병렬 실행을 스케줄링하는 데 필요한 회로는 칩 면적, 비용, 전력 소비를 증가시키며 잠재적으로 클럭 속도를 저하시킬 수 있다.

VLIW라는 이름은 거의 모든 구현체에서 발견되는 명령어 형식에서 유래되었다. 이 형식에서 컴파일러는 동시에 실행하려는 연산들을 하나의 넓은 명령어 워드(단어)로 묶으며, 이는 하나의 단위로서 실행 장치에 전달된다. 이러한 워드는 매우 넓을 수 있는데, 일부 구현체에서는 1킬로비트 이상의 명령어 워드를 사용하기도 했다. 하지만 이는 VLIW를 구현하는 자연스러운 방식의 부수적인 효과일 뿐이다. VLIW의 결정적인 특징은 정확한 실행 순서와 병렬성이 사전에 발견되고 지정된다는 점이다.

VLIW는 병렬성을 식별하는 부담을 하드웨어에서 컴파일러로 옮긴다. 이는 컴파일러의 복잡성을 실질적으로 증가시키는데, 컴파일러는 정확성을 보장하고 (실행 장치, 레지스터, 메모리 포트에 대한) 자원 충돌을 해결하는 동시에, 더 단순해진 VLIW 하드웨어가 노출하는 더 큰 병렬성을 활용하며 명령어를 스케줄링해야 하기 때문이다.

 역사 

VLIW 아키텍처의 개념과 VLIW라는 용어는 1980년대 초 예일 대학교의 조시 피셔 연구 그룹에서 발명되었다. VLIW를 위한 컴파일 방법으로서 트레이스 스케줄링에 대한 그의 독창적인 연구는 그가 뉴욕 대학교 대학원생이었을 때 개발되었다. VLIW 이전에도 소프트웨어에서 실행 장치와 명령어 수준 병렬성을 미리 스케줄링하는 개념은 수평 마이크로코드 개발 관행에 잘 확립되어 있었다.

피셔의 혁신은 일반적인 프로그래밍 언어로 작성된 프로그램에서 수평 마이크로코드를 대상으로 할 수 있는 컴파일러를 개발한 데 있다. 그는 좋은 성능을 얻고 와이드 이슈 기계(wide-issue machine)를 활용하기 위해서는 일반적으로 기본 블록 내에 존재하는 병렬성을 넘어서는 병렬성을 찾아야 한다는 것을 깨달았다. 그는 또한 기본 블록을 넘어서는 병렬성을 식별하기 위해 영역 스케줄링 방법을 개발했다. 트레이스 스케줄링이 바로 그러한 방법으로, 가장 가능성이 높은 기본 블록 경로를 먼저 스케줄링하고, 투기적 이동을 처리하기 위한 보상 코드를 삽입하며, 두 번째로 가능성이 높은 트레이스를 스케줄링하는 방식을 스케줄이 완료될 때까지 반복한다.

피셔의 두 번째 혁신은 대상 CPU 아키텍처가 컴파일러를 위한 합리적인 대상이 되도록 설계되어야 한다는 개념, 즉 VLIW 프로세서를 위한 컴파일러와 아키텍처가 공동 설계(codesign)되어야 한다는 것이었다. 이는 피셔가 예일 대학교에서 플로팅 포인트 시스템즈의 FPS164와 같은 아키텍처를 위해 컴파일할 때 겪었던 어려움에서 부분적으로 영감을 얻었다. FPS164는 명령어 시작과 결과 저장 명령어가 분리된 복잡 명령어 집합 컴퓨터(CISC) 아키텍처를 가지고 있어 매우 복잡한 스케줄링 알고리즘이 필요했다. 피셔는 셀프 드레이닝 파이프라인, 넓은 다중 포트 레지스터 파일, 메모리 구조 등 적절한 VLIW 설계를 특징짓는 일련의 원칙을 개발했다. 이러한 원칙들은 컴파일러가 빠른 코드를 생성하는 것을 더 쉽게 만들었다.

첫 번째 VLIW 컴파일러는 피셔의 지도 하에 존 엘리스의 박사 학위 논문에서 설명되었다. 이 컴파일러의 이름은 예일 대학교의 마스코트를 따서 '불독'(Buldog)이라 명명되었다.

피셔는 1984년 예일을 떠나 공동 창업자인 존 오도넬 및 존 루텐버그와 함께 스타트업 기업인 멀티플로우(Multiflow)를 설립했다. 멀티플로우는 TRACE 시리즈 VLIW 미니슈퍼컴퓨터를 생산하여 1987년에 첫 기계를 출시했다. 멀티플로우의 VLIW는 명령어당 28개의 연산을 병렬로 실행할 수 있었다. TRACE 시스템은 중규모 집적 회로(MSI), 대규모 집적 회로(LSI), 초대규모 집적 회로(VLSI)를 혼합하여 구현되어 캐비닛에 담겼으나, 프로세서의 모든 구성 요소(메모리 제외)를 하나의 칩에 통합하는 것이 비용 효율적으로 변하면서 이 기술은 구식이 되었다.

멀티플로우는 칩 아키텍처가 다중 이슈 CPU를 허용하기 시작한 다음 세대의 흐름을 타기에는 너무 일렀다. 주요 반도체 회사들은 이러한 맥락에서 멀티플로우 기술의 가치를 인정했고, 그 결과 컴파일러와 아키텍처는 이후 대부분의 해당 기업들에 라이선스되었다.

 동기 

모든 명령어를 차례대로 실행하는 프로세서(즉, 명령어 파이프라인이 없는 스칼라 아키텍처)는 프로세서 자원을 비효율적으로 사용하여 성능이 저하될 수 있다. 성능은 순차적 명령어의 서로 다른 하위 단계를 동시에 실행하거나(파이프라이닝), 슈퍼스칼라 아키텍처에서처럼 여러 명령어를 완전히 동시에 실행함으로써 향상될 수 있다. 추가적인 개선은 프로그램에 나타나는 순서와 다른 순서로 명령어를 실행하는 비순차적 명령어 처리를 통해 달성할 수 있다.

이 세 가지 방법 모두 하드웨어 복잡성을 높인다. 어떤 연산을 병렬로 실행하기 전에, 프로세서는 명령어들 사이에 상호 의존성이 없는지 확인해야 한다. 예를 들어, 첫 번째 명령어의 결과가 두 번째 명령어의 입력으로 사용된다면, 이들은 동시에 실행될 수 없으며 두 번째 명령어가 첫 번째 명령어보다 먼저 실행될 수도 없다. 현대의 비순차적 프로세서는 명령어를 스케줄링하고 상호 의존성을 결정하는 하드웨어 자원을 증대시켜 왔다.

반면, VLIW는 프로그램이 컴파일될 때 결정된 고정된 스케줄에 따라 연산을 병렬로 실행한다. (어떤 연산이 동시에 실행될 수 있는지를 포함하여) 연산의 실행 순서를 결정하는 것이 컴파일러에 의해 처리되므로, 프로세서는 위에서 설명한 세 가지 방식이 필요로 하는 스케줄링 하드웨어를 필요로 하지 않는다. 따라서 VLIW CPU는 대부분의 슈퍼스칼라 CPU보다 더 적은 하드웨어 복잡성(단, 더 큰 컴파일러 복잡성)으로 더 많은 계산을 제공한다. 이는 가능한 한 많은 계산을 프로그램 실행 전인 컴파일 타임에 수행해야 한다는 아이디어와도 일맥상통한다.

 설계 

슈퍼스칼라 설계에서 실행 장치의 개수는 명령어 집합에서 보이지 않는다. 각 명령어는 하나의 연산만을 인코딩한다. 대부분의 슈퍼스칼라 설계에서 명령어 너비는 32비트 이하이다.

반면, 하나의 VLIW 명령어는 장치의 각 실행 장치에 대해 최소 하나씩, 여러 연산을 인코딩한다. 예를 들어, VLIW 장치에 5개의 실행 장치가 있다면, 해당 장치를 위한 VLIW 명령어에는 5개의 연산 필드가 있으며, 각 필드는 해당 실행 장치에서 수행해야 할 연산을 지정한다. 이러한 연산 필드들을 수용하기 위해 VLIW 명령어는 대개 최소 64비트 너비이며, 일부 아키텍처에서는 훨씬 더 넓다.

예를 들어, 다음은 SHARC(Super Harvard Architecture Single-Chip Computer)의 명령어이다. 한 사이클에 부동소수점 곱셈, 부동소수점 덧셈, 그리고 두 개의 자동 증감 로드를 수행한다. 이 모든 것이 하나의 48비트 명령어에 들어간다.

f12 = f0 * f4, f8 = f8 + f12, f0 = dm(i0, m3), f4 = pm(i8, m9);

컴퓨터 구조의 초기 시절부터, 일부 CPU는 병렬 실행을 위해 여러 개의 산술 논리 장치(ALU)를 추가해 왔다. 슈퍼스칼라 CPU는 실행 시간에 어떤 연산이 병렬로 실행될 수 있는지 결정하기 위해 하드웨어를 사용하는 반면, VLIW CPU는 소프트웨어(컴파일러)를 사용하여 사전에 결정한다. 명령어 스케줄링의 복잡성이 컴파일러로 옮겨졌기 때문에 하드웨어의 복잡성을 실질적으로 줄일 수 있다.

비슷한 문제는 병렬화 가능한 명령어의 결과가 분기의 입력으로 사용될 때 발생한다. 대부분의 현대식 CPU는 계산이 완료되기도 전에 어느 분기가 선택될지 추측하여 분기 명령어를 로드하거나, (일부 아키텍처에서는) 투기적으로 계산을 시작하기도 한다. CPU가 잘못 추측하면 이러한 모든 명령어와 그 컨텍스트를 플러시하고 올바른 명령어를 로드해야 하므로 시간이 걸린다.

이로 인해 올바르게 추측하려고 시도하는 점점 더 복잡한 명령어 분기 로직이 생겨났고, 원래의 축소 명령어 집합 컴퓨터(RISC) 설계의 단순함은 퇴색되었다. VLIW는 이러한 로직이 없으므로 에너지 사용, 잠재적 설계 결함 및 기타 부정적인 측면이 없다.

VLIW에서 컴파일러는 휴리스틱이나 프로파일 정보를 사용하여 분기 방향을 추측한다. 이를 통해 분기가 실행되기 전에 연산을 투기적으로 이동시키고 사전에 스케줄링하여, 분기를 통해 예상되는 가장 가능성 높은 경로를 우선시할 수 있다. 분기가 예상치 못한 방향으로 진행될 경우, 컴파일러는 프로그램 의미를 보존하기 위해 투기적 결과를 폐기하는 보상 코드를 이미 생성해 둔 상태이다.

벡터 프로세서 코어(벡터라고 불리는 큰 1차원 배열 데이터를 위해 설계됨)는 후지쯔 FR-V 마이크로프로세서와 같이 VLIW 아키텍처와 결합되어 처리량과 속도를 더욱 높일 수 있다.

 구현 

사이드롬(Cydrome)은 비슷한 시기(1980년대 후반)에 이미터-결합 논리(ECL) 집적 회로를 사용하는 VLIW 수치 프로세서를 생산하던 회사였다. 이 회사는 멀티플로우와 마찬가지로 몇 년 후 실패했다.

멀티플로우 기술의 라이선스 보유자 중 하나는 휴렛 팩커드로, 조시 피셔는 멀티플로우가 문을 닫은 후 이곳에 합류했다. 사이드롬의 창업자인 밥 라우 또한 회사가 실패한 후 HP에 합류했다. 이 두 사람은 1990년대 동안 휴렛 팩커드에서 컴퓨터 구조 연구를 이끌게 된다.

위의 시스템들과 더불어, 같은 시기(1989~1990년)에 인텔은 자사 최초의 64비트 마이크로프로세서이자 하나의 칩에 VLIW를 구현한 최초의 프로세서인 인텔 i860에서 VLIW를 구현했다. 이 프로세서는 단순 RISC 모드와 VLIW 모드 모두에서 작동할 수 있었다.
1990년대 초, 인텔은 i860 RISC 마이크로프로세서를 출시했다. 이 단순한 칩은 스칼라 모드와 VLIW 모드라는 두 가지 작동 모드를 가지고 있었다. VLIW 모드에서 프로세서는 항상 두 개의 명령어를 가져왔으며, 하나는 정수 명령어이고 다른 하나는 부동소수점 명령어라고 가정했다.

i860의 VLIW 모드는 임베디드 시스템의 디지털 신호 처리 장치(DSP) 애플리케이션에서 널리 사용되었다. 애플리케이션 실행과 데이터 세트가 단순하고 잘 정렬되어 있으며 예측 가능했기 때문에 설계자들이 VLIW로 가능해진 병렬 실행의 장점을 완전히 활용할 수 있었기 때문이다. VLIW 모드에서 i860은 20~40 배정밀도 MFLOPS 범위의 부동소수점 성능을 유지할 수 있었는데, 이는 당시의 기준이나 25~50MHz로 작동하는 프로세서로서는 매우 높은 수치였다.

1990년대에 휴렛 팩커드는 자사의 PA-RISC 프로세서 제품군에 대한 지속적인 작업의 부수적 효과로 이 문제를 연구했다. 그들은 CPU에서 복잡한 파견(dispatch) 로직을 제거하고 이를 컴파일러에 배치함으로써 CPU를 크게 단순화할 수 있음을 발견했다. 당시의 컴파일러는 1980년대보다 훨씬 더 복잡했기 때문에 컴파일러에 추가되는 복잡성은 적은 비용으로 간주되었다.

VLIW CPU는 일반적으로 독립적으로 작동하는 여러 개의 RISC 유사 실행 장치로 구성된다. 현대의 VLIW는 보통 4개에서 8개의 주요 실행 장치를 가진다. 컴파일러는 전통적인 CPU와 거의 동일한 방식으로 VLIW CPU를 위한 초기 명령어 시퀀스를 생성하며, RISC 유사 명령어 시퀀스를 만들어낸다. 컴파일러는 이 코드를 분석하여 의존성 관계와 자원 요구 사항을 파악한다. 그런 다음 이러한 제약 조건에 따라 명령어를 스케줄링한다. 이 과정에서 독립적인 명령어들은 병렬로 스케줄링될 수 있다. VLIW는 일반적으로 병렬로 스케줄링된 명령어들을 개별 명령어가 포함된 더 긴 명령어 워드로 나타내기 때문에, 결과적으로 특정 사이클에 무엇이 실행될지를 지정하는 매우 긴 명령 코드(very long)를 갖게 된다.

현대 VLIW CPU의 사례로는 NXP 반도체(구 필립스 반도체)의 TriMedia 미디어 프로세서, 아날로그 디바이스의 SHARC DSP, 조시 피셔의 HP 연구실에서 파올로 파라보스키가 설계한 Lx 아키텍처 기반의 ST200 제품군(STMicroelectronics), 후지쯔의 FR-V, Pixelworks의 BSP15/16, CEVA의 CEVA-X DSP, Improv Systems의 Jazz DSP, Silicon Hive의 HiveFlex 시리즈, 그리고 Kalray의 MPPA 매니코어 제품군이 있다. 텍사스 인스트루먼트의 TMS320 DSP 라인은 이전의 C5000 제품군과 대조적으로 C6000 제품군에서 VLIW와 더 유사하게 발전했다. Qualcomm Hexagon은 오늘날 대부분의 휴대전화에서 하나 이상 발견된다. 이러한 현대적 VLIW CPU들은 주로 가전 기기용 임베디드 미디어 프로세서로서 성공을 거두고 있다.

VLIW 기능은 시스템 온 칩(SoC) 설계를 위한 구성 가능한 프로세서 코어에도 추가되었다. 예를 들어, 텐실리카(Tensilica)의 Xtensa LX2 프로세서는 다중 연산 명령어를 허용하는 FLIX(Flexible Length Instruction eXtensions)라는 기술을 포함하고 있다. Xtensa C/C++ 컴파일러는 16비트 또는 24비트 너비의 Xtensa 프로세서 단일 연산 RISC 명령어와 32비트 또는 64비트 FLIX 명령어를 자유롭게 혼용할 수 있다. 넓은 32비트 또는 64비트 명령어 워드에 여러 연산을 패킹하고 이러한 다중 연산 명령어를 짧은 RISC 명령어와 혼용할 수 있게 함으로써, FLIX는 SoC 설계자가 초기 VLIW 아키텍처의 코드 팽창 문제를 제거하면서 VLIW의 성능상 이점을 실현할 수 있게 한다.
인피니온 Carmel DSP는 SoC를 겨냥한 또 다른 VLIW 프로세서 코어이다. 이는 CLIW(Configurable Long Instruction Word)라고 불리는 유사한 코드 밀도 개선 방법을 사용한다.

임베디드 프로세싱 시장 외에는 인텔의 아이테니엄 IA-64 EPIC 아키텍처(EPIC)와 Elbrus 2000이 널리 사용된 VLIW CPU 아키텍처의 유일한 사례로 꼽힌다. 그러나 EPIC 아키텍처는 완전한 명령어 조건화(predication), 회전 레지스터 파일, 그리고 비병렬 명령어 그룹을 인코딩할 수 있는 매우 긴 명령어 워드를 옹호한다는 점에서 때때로 순수 VLIW 아키텍처와 구별된다. VLIW는 그래픽 처리 장치(GPU) 시장에서도 상당한 소비자 점유율을 확보했었으나, 엔비디아와 AMD 모두 그래픽 이외의 작업 부하에서 성능을 개선하기 위해 이후 RISC 아키텍처로 이동했다.

ATI 테크놀로지스(ATI)와 AMD의 GPU용 테라스케일 마이크로아키텍처는 VLIW 마이크로아키텍처이다.

2015년 12월, 러시아에서 VLIW CPU Elbrus-4s 기반의 PC가 처음으로 출하되었다.

REX Computing의 Neo는 전력 효율을 목표로 하는 VLIW 코어의 2D 메쉬로 구성된 프로세서이다.

Elbrus 2000()과 그 후속 제품들은 모스크바 SPARC 기술 센터(MCST)에서 개발하고 TSMC에서 제조한 러시아의 512비트 너비 VLIW 마이크로프로세서이다.

 하위 호환성 

실리콘 기술의 발전으로 더 넓은 구현체(더 많은 실행 장치)를 구축할 수 있게 되었을 때, 이전 세대를 위해 컴파일된 프로그램은 더 넓은 구현체에서 실행되지 않았다. 이진 명령어의 인코딩이 기계의 실행 장치 개수에 의존했기 때문이다.

트랜스메타는 X86 아키텍처를 구현한 크루소에서 이진 대 이진 소프트웨어 컴파일러 계층(코드 모핑)을 포함시켜 이 문제를 해결했다. 이 메커니즘은 기본적으로 실행 시간에 x86 명령 코드를 CPU 내부 기계어로 재컴파일, 최적화 및 변환하는 것으로 홍보되었다. 따라서 트랜스메타 칩은 내부적으로 VLIW 프로세서이며, 실행하는 x86 CISC 명령어 집합으로부터 효과적으로 분리되어 있다.

인텔의 아이테니엄 아키텍처 등은 보다 일반적인 메커니즘으로 하위 호환성 문제를 해결했다. 여러 명령 코드가 포함된 각 명령어 내에서, 프로그램 명령어 스트림 내의 이전 VLIW 명령어에 대한 의존성을 표시하기 위해 비트 필드가 할당된다. 이 비트들은 컴파일 타임에 설정되므로 하드웨어가 이 의존성 정보를 계산하는 부담을 덜어준다. 명령어 스트림에 이 의존성 정보가 인코딩되어 있으면, 더 넓은 구현체는 사이클당 여러 개의 독립적인 VLIW 명령어를 병렬로 발행할 수 있는 반면, 더 좁은 구현체는 사이클당 더 적은 수의 VLIW 명령어를 발행하게 된다.

VLIW 설계의 또 다른 결함으로 인식되는 점은 하나 이상의 실행 장치가 할 일을 찾지 못해 NOP 명령어를 실행해야 할 때 발생하는 코드 팽창이다. 이는 코드 내에 의존성이 있어 이후의 연산이 진행되기 전에 명령어 파이프라인을 비워야 할 때 발생한다.

칩의 트랜지스터 수가 증가함에 따라 VLIW의 이러한 단점들은 그 중요성이 줄어들었다. VLIW 아키텍처는 특히 시스템 온 칩에서 특정 애플리케이션에 맞게 프로세서를 맞춤화할 수 있는 임베디드 시스템 시장을 중심으로 인기가 높아지고 있다.

 각주 

분류:병렬 컴퓨팅
분류:디지털 신호 처리
분류:명령어 집합 구조
분류:명령어 처리