Pass 인프라 — 변환·최적화의 기본 구조
Pass 인프라 — 변환·최적화의 기본 구조
MLIR에서 변환과 최적화의 기본 단위는 pass예요. 이 페이지는 pass manager의 구조와 pass를 올바르게 작성하는 규칙을 설명하는 문서예요.
모든 pass는 OperationPass에서 파생되고, pass manager는 중첩된 연산 레벨 각각에 대해 pass를 실행해요. 멀티스레드 환경을 염두에 두고 다음 제약을 지켜야 해요:
- 현재 연산의 형제(sibling) 연산 상태를 검사하지 말 것. 병렬로 수정될 수 있어요. 조상/부모 연산 검사는 허용돼요.
- 현재 연산 아래 중첩된 연산 외에는 수정하지 말 것. 예외적으로 현재 연산의 속성(attribute)은 자유롭게 바꿀 수 있어요.
runOnOperation호출 사이에 가변 pass 상태를 유지하지 말 것. 실행 순서가 보장되지 않아요.- 전역 가변 상태(파일 내 static 변수)를 두지 말 것.
- copy-constructible 일 것. 병렬 처리를 위해 여러 인스턴스가 만들어질 수 있어요.
Op-agnostic pass 는 pass manager가 다루는 연산 타입에 무관하게 동작해요. 예를 들어 Canonicalization나 CSE(공통 부분식 제거)가 그렇고, CRTP 기반 PassWrapper와 runOnOperation() 오버라이드를 이용해 작성해요.
필터링을 걸면 실행 대상을 제한할 수 있어요. 특정 연산 타입(예: func::FuncOp)에만 돌게 하거나, 특정 인터페이스(예: FunctionOpInterface)를 구현한 연산에만 돌게 하는 InterfacePass가 있어요. 정적 필터가 걸린 pass를 op-agnostic manager에 넣으면 그 manager 전체가 같은 제약을 물려받는다는 점을 기억해야 해요.
분석(analysis)은 변환 pass와 달리 연산을 수정하지 않고 정보만 계산해요. lazy 하게 필요할 때 계산되고 캐시돼요. 디버깅에는 -mlir-timing 으로 pass별 소요 시간을 보거나, -mlir-print-ir-before / -mlir-print-ir-after 같은 플래그로 각 단계의 IR을 덤프할 수 있어요.