Rust, 더 나은 Calling Convention으로 성능을 잡다!

by DD
3개월 전
조회수 12

Rust는 현재 LLVM의 C Calling Convention을 사용하며, 이는 성능 최적화에 한계가 있음

저자는 `-Zcallconv` 플래그를 통해 새로운 Calling Convention 도입을 제안, x86 아키텍처를 예시로 설명

LLVM의 Poison Semantics를 활용하여 Register 사용 효율을 극대화하는 방법을 제시

함수 시그니처(Function Signature) 분석을 통해 최적화된 ABI 생성 및 컴파일 시간 단축을 목표로 함

Rust Calling Convention의 문제점

현재 Rust는 LLVM의 C Calling Convention을 사용하며, 이는 복잡한 타입(Complex Types) 전달에 비효율적이다. 특히, `[i32; 3]`과 같은 배열이 레지스터가 아닌 포인터로 전달되는 경우가 발생하여 코드 생성(Code Generation)의 성능 저하를 야기한다. 저자는 이러한 문제점을 해결하기 위해 새로운 Calling Convention 설계를 제안하며, 기존 C ABI의 한계를 지적한다.

-Zcallconv 플래그를 이용한 Calling Convention 개선

저자는 `-Zcallconv` 플래그를 도입하여 `extern "Rust"` 함수에 대한 Calling Convention을 선택할 수 있도록 제안한다. `-Zcallconv=legacy`는 기존 방식을 유지하고, `-Zcallconv=fast`는 새로운 Calling Convention을 적용한다. 이를 통해 개발자는 컴파일러 최적화(Compiler Optimization)를 활용하여 성능을 향상시킬 수 있으며, 디버깅(Debugging) 및 LLVM 버그(LLVM Bugs) 발생 가능성을 최소화할 수 있다.

LLVM Poison Semantics를 활용한 레지스터 최적화

저자는 LLVM의 Poison Semantics를 활용하여 레지스터 사용 효율을 높이는 방법을 제시한다. 사용하지 않는 인수를 Poison 값으로 전달함으로써, LLVM이 해당 레지스터를 건드리지 않도록 하여 불필요한 레지스터 이동(Register Traffic)을 줄인다. 이를 통해 개발자는 함수 호출(Function Call) 시 성능 저하를 방지하고, 코드 최적화에 대한 세부적인 제어가 가능하다.

구체적인 구현 방법 및 트레이드오프

저자는 LLVM을 활용하여 Calling Convention을 구현하는 구체적인 방법을 제시한다. 여기에는 레지스터 사용량 최대화, 반환 값 처리, 함수 시그니처 생성, 프롤로그/에필로그 생성 등이 포함된다. 하지만, 이러한 최적화는 컴파일 시간 증가 및 코드 복잡도(Code Complexity) 증가라는 트레이드오프를 수반한다. 또한, 함수 포인터(Function Pointer) 사용 시에는 기존 Calling Convention을 사용해야 하는 제약이 존재한다.

The Rust calling convention we deserve