Java GC 관련 링크 정리


Rust에서 LLVM Intrinsics 호출하기

요즘에는 내가 보려는 목적으로 기록을 하는 블로깅이 대부분인 듯 하다. Rust는 LLVM으로 구현되어 있고 LLVM 의 Intrinsics를 함수에 매핑해서 호출할 수 있는 기능이 공식적으로 제공된다. 예제는 아래와 같다.


#![feature(link_llvm_intrinsics)]
extern {
#[link_name = “llvm.sqrt.f32”]
fn sqrt(x: f32) -> f32;
}
fn main(){
unsafe { sqrt(32.0f32); }
}

view raw

intrinsics.rs

hosted with ❤ by GitHub


LLVM을 이용한 JIT 코드 개발 정리

현재 작업 중인 Tokamak (가제) 프로젝트서 사용될 LLVM JIT 코드 몇 가지를 작성해보았다. Rust로 작업하고 있기 때문에 llvm-alt 라는 바인딩 라이브러리를 fork해서 작업을 진행했다. fork 한 이유는 버그와 미구현 API 때문인데 maintenance가 기존에 리포트된 버그도 수정 안되길래 아예 fork 해버렸다.

LLVM은 레퍼런스 문서는 참 훌륭하다. 또한 LLVM IR 자체가 프로그래밍 코드와 비슷해서 Java Bytecode를 보다 훨씬 쉬운 듯 하다. 자체는 쉬운 편인데, 친절한 문서는 별로 없다. 만든 녀석들이 워낙 똑똑한 녀석들이라 나 같은 초보들이 뭘 필요하는지는 잘 모르는 모양인데 이 글에 익힌 몇 가지 정리를 한다. 이 문서의 목적은 내가 보기 위해서기 때문에 체계적이지도 않고 부연설명도 없다.

MJIT vs ORC

  • MCJIT 전에는 JIT 였음, JIT 는 LLVM 3.5에서 제거됨
  • MCJIT는 더 많은 타겟에 대한 네이티브 코드 지원
  • MCJIT는 lazy compilation 지원안함, ORC는 지원함. 다시말해 ORC는 함수 실행 전에 code generation을 하기 때문에 일반적으로 code generation time이 짧음
    • 의문1: ORC는 thread safe 한가? (관련 링크)
    • 의문2: thread safe를 위한 성능 손해는 없는가?
  • 많은 새 프로젝트들은 MCJIT보다는 ORC 선택 중 또는 기존 프로젝트들도 전환 중

IR 코드와 Bitcode (BC)

  • 프로그래밍 언어는 LLVM 거치면 IR로 변환되고 IR은 다시 BC로 변환되어 최종적으로 native 바이너리 형태로 변환된다. IR과 BC는 어디까지나 LLVM을 위한 intermediate representation 코드임
  • IR은 human readable representation 이고 BC는 더 컴팩트한 바이너리 포맷. 로딩은 당연 후자가 빠르므로 런타임 로딩을 위해서는 미리 BC로 빌드를 해놓아야 한다.
  • JIT 코드 작성 시에 IR 코드 생성을 해야 할 필요가 있는데 이는 프로그래밍 언어와 JIT 간에 interoperation 을 위해서이다.
    • 예를 들면 JIT로 작성한 함수가 인자로 받을 구조체는 프로그래밍 언어에서도 가용해야 하는덷 이런 경우 c++ 등으로LLVM JIT에서 사용할 구조체와 함수등을 구현해 놓고 c++ 코드에서는 해당 구현을 사용하고 LLVM JIT에서는 미리 생성된 IR을 사용한다.
  • IR 을 파싱하고 로딩해서 모듈을 생성할 수 있다.
  • 생성된 모듈에서 iterator 를 통해 함수 리스트를 얻을 수 있다.
    • 이때 함수에 attribute를 부여할 수 있는데 예를 들면 AlwaysInline 같은 것..
    • AlwaysInline 속성은 JIT로 작성된 코드 내부에서 호출하는 다른 JIT 함수들은 전부 inlining이 된다. 즉 함수 호출 비용이 줄어든다.
      • LLVM JIT를 굳이 어렵게 쓰는 이유는 interpretation cost를 줄이고 복잡한 로직을 주어진 정보를 통해 단순화 시켜 브렌치를 제거하기 위함인데 inlining은 이 목적에 잘 부합한다.
      • 다른 속성도 살펴봐야..
  • Clang을 통해 emit-llvm 할 경우 extern 으로 감싸야 llvm 으로 함수에 접근 가능하다.
  • Clang을 통해 emit-llvm 할 경우 활용되지 않는 구조체는 컴파일러 레벨 최적화에서 제거 되기 때문에 IR에도 표현되지 않는데 이런 경우를 방지하려면 private dummy 함수를 만들어 인자에 struct들을 다 넣어버리면 IR에 struct를 유지시킬 수 있다.
  • Clang을 통해 emit-llvm 할 경우 같은 구성을 가진 구조체는 서로 구분하지 못한다. 따라서 다른 구조체의 symbol 이름으로 IR이 출력될 수 있다.