레지스터 윈도

컴퓨터 공학에서 레지스터 윈도(Register window)는 내부 레지스터의 하위 집합을 고정된, 프로그래머에게 보이는 레지스터로 동적으로 별칭을 지정하여 서브루틴에 레지스터를 전용하는 기능이다. 레지스터 윈도는 함수 호출 및 반환에 필요한 스택 작업 수를 줄여 프로세서의 성능을 향상시키기 위해 구현된다. 버클리 RISC 설계에서 가장 영향력 있는 기능 중 하나인 이 기능은 나중에 AMD Am29000, 인텔 i960, 썬 마이크로시스템즈 SPARC, 인텔 아이태니엄과 같은 명령어 집합 구조에 구현되었다.
일반적인 작동
[편집]프로그램의 여러 부분에 대해 여러 세트의 레지스터가 제공된다. 레지스터는 여러 서브루틴이 프로세서 자원을 공유하도록 강제하기 위해 프로그래머에게 의도적으로 숨겨진다.
레지스터를 보이지 않게 만드는 것은 효율적으로 구현할 수 있다. CPU는 프로시저 호출 중 프로그램의 한 부분에서 다른 부분으로 이동하는 것을 인식한다. 이것은 소수의 명령어(프롤로그) 중 하나로 완료되며 비슷하게 작은 세트(에필로그) 중 하나로 끝난다. 버클리 설계에서 이러한 호출은 새로운 레지스터 세트가 그 시점에 "스왑 인"되거나 호출이 끝날 때 "죽음" (또는 "재사용 가능")으로 표시되도록 한다.
CPU에서의 적용
[편집]버클리 RISC 설계에서는 총 64개의 레지스터 중 8개만 프로그램에 보인다. 완전한 레지스터 세트를 레지스터 파일이라고 하며, 특정 8개 세트를 윈도라고 한다. 파일은 최대 8개의 프로시저 호출이 자체 레지스터 세트를 가질 수 있도록 허용한다. 프로그램이 8개 이상의 호출 체인을 호출하지 않는 한 레지스터는 절대 스필될 필요가 없다. 즉, 레지스터 접근에 비해 느린 메인 메모리 또는 캐시로 저장할 필요가 없다.
이에 비해 썬 마이크로시스템즈 SPARC 아키텍처는 각 8개 레지스터 중 4개 세트에 대한 동시 가시성을 제공한다. 각 8개 레지스터 중 세 세트가 "윈도"되어 있다. 8개 레지스터(i0 ~ i7)는 현재 프로시저 레벨의 입력 레지스터를 형성한다. 8개 레지스터(L0 ~ L7)는 현재 프로시저 레벨에 로컬이며, 8개 레지스터(o0 ~ o7)는 현재 프로시저 레벨에서 다음에 호출되는 레벨로의 출력을 형성한다. 프로시저가 호출되면 레지스터 창이 16개 레지스터만큼 이동하여 이전 입력 레지스터와 이전 로컬 레지스터를 숨기고 이전 출력 레지스터를 새 입력 레지스터로 만든다. 공통 레지스터(이전 출력 레지스터 및 새 입력 레지스터)는 매개변수 전달에 사용된다. 마지막으로 8개 레지스터(g0 ~ g7)는 모든 프로시저 레벨에 전역적으로 보인다.
AMD 29000은 창 크기를 가변적으로 허용하여 설계를 개선했으며, 이는 호출에 8개 미만의 레지스터가 필요한 일반적인 경우에 활용도를 높이는 데 도움이 된다. 또한 레지스터를 64개의 전역 세트와 창을 위한 추가 128개로 분리했다. 마찬가지로 IA-64(아이태니엄) 아키텍처는 32개의 전역 레지스터와 창을 위한 96개의 레지스터로 가변 크기 창을 사용했다.
인피니언 C166 아키텍처에서는 대부분의 레지스터가 내부 RAM의 위치일 뿐이며 레지스터로 접근할 수 있는 추가 속성이 있다. 이 중 16개 범용 레지스터(R0-R15)의 주소는 고정되어 있지 않다. 대신 R0 레지스터는 "컨텍스트 포인터"(CP) 레지스터가 가리키는 주소에 위치하며, 나머지 15개 레지스터는 그 뒤를 순차적으로 따른다.[1]
레지스터 창은 또한 쉬운 업그레이드 경로를 제공한다. 추가 레지스터는 프로그램에 보이지 않으므로 언제든지 추가 창을 추가할 수 있다. 예를 들어 객체 지향 프로그래밍을 사용하면 더 많은 "작은" 호출이 발생하며, 이는 창을 8개에서 16개로 늘리는 등으로 수용할 수 있다. 이는 SPARC에서 사용된 접근 방식이며, 새로운 세대의 아키텍처에 더 많은 레지스터 창을 포함했다. 최종 결과는 레지스터 창 오버플로가 덜 자주 발생하여 느린 레지스터 창 스필 및 채우기 작업이 줄어든다는 것이다.
비판
[편집]레지스터 창의 단점은 컨텍스트 스위치가 많은 수의 레지스터를 메모리에 저장해야 한다는 것이다. SPARC 구현은 레지스터 창을 항상 16개 레지스터씩 전진시키는데, 이는 이럴 때 저장된 레지스터 중 상당수가 유용한 데이터를 포함하지 않을 것임을 의미한다. 일부는 레지스터 창 구현으로 이어진 원래 연구가 프로그램을 격리하여 고려하고 멀티태스킹 워크로드를 무시했다고 비판했다.[2]
레지스터 창만이 레지스터 성능을 개선하는 유일한 방법은 아니다. 스탠퍼드 대학교에서 MIPS를 설계하는 그룹은 버클리 연구를 보고 문제는 레지스터 부족이 아니라 기존 레지스터 활용 부족이라고 판단했다. 대신 컴파일러의 레지스터 할당에 더 많은 시간을 투자하여 MIPS에서 사용할 수 있는 더 큰 세트를 현명하게 사용하도록 했다. 이로 인해 칩의 복잡성이 줄어들고 총 레지스터 수가 절반으로 줄었으며, 단일 프로시저가 더 큰 보이는 레지스터 공간을 사용할 수 있는 경우 잠재적으로 더 높은 성능을 제공했다. 결국 최신 컴파일러를 사용하면 MIPS는 프로시저 호출 중에도 레지스터 공간을 더 잘 활용한다.
각주
[편집]- ↑ “Infineon C166 Family Instruction Set Manual” (PDF). Keil. 2020년 3월 12일에 확인함.
- ↑ Magnusson, Peter (April 1997). “Understanding stacks and registers in the Sparc architecture(s)”. 《CSE 131 - Compiler Construction》. 샌디에이고 대학교. 2024년 10월 24일에 확인함.
The drawback is that upon interactions with the system the registers need to be flushed to the stack, necessitating a long sequence of writes to memory of data that is often mostly garbage. Register windows was a bad idea that was caused by simulation studies that considered only programs in isolation, as opposed to multitasking workloads, and by considering compilers with poor optimization.
- Frantzen, Mike; Shuey, Mike (2001). 〈StackGhost: Hardware Facilitated Stack Protection〉. 《Proceedings of the 10th Usenix Security Symposium》. USENIX. 55–66쪽. 2010년 8월 27일에 확인함.
- Magnusson, Peter (April 1997). “Understanding stacks and registers in the Sparc architecture(s)”. 2012년 12월 24일에 원본 문서에서 보존된 문서. 2010년 8월 27일에 확인함.
- Mueller, Frank. “setjmp/longjmp”. Discussing the complex Sparc implementation due to windowing.