1.10. rok::bare::mlir::plugin - 사용자 정의 다이얼렉트 등록
rok::bare::mlir::plugin 은 rok 컴파일러가 외부에서 빌드된 MLIR 다이얼렉트를 동적으로 로드하여 __mlir_op 의 호출 대상으로 추가할 수 있도록 하는 인터페이스를 정의합니다. 도메인 특화 컴파일러 (암호화, 신호 처리, 형식 검증, 새 가속기 ISA 등) 를 rok 위에 얹고 싶은 라이브러리 작성자를 위한 자리입니다.
본 절은 plugin 의 등록 메커니즘과 안전 책임 을 정의합니다. 다이얼렉트 자체의 정의 (op / type / attribute 의 의미와 스키마) 는 MLIR 의 영역 (TableGen / IRDL) 이며 본 사양 범위 밖입니다.
1.10.1. 영역 분리 - 무엇이 spec 안 / 밖인가
| 책임 | 위치 |
|---|---|
| 다이얼렉트 정의 (op 스키마, type 시스템) | spec 밖 - MLIR (TableGen .td / IRDL) |
다이얼렉트 빌드 (.so / .dylib / .dll) | spec 밖 - 사용자 빌드 도구 |
| rok 컴파일러가 plugin 을 로드 / register 하는 인터페이스 | spec 안 (본 절) |
로드된 plugin op 을 __mlir_op 으로 호출 | spec 안 (1.9) |
| plugin op 의 lowering / 패스 | spec 밖 - plugin 자체가 책임 |
이 분리는 rok 이 MLIR 자체의 dialect-definition DSL 진화 (TableGen → IRDL → 차세대 형식) 에 종속되지 않도록 합니다.
1.10.2. plugin 빌드 형태
rokc 는 MLIR 을 내장하며 (0.2.4) plugin 을 자신의 MLIR context 에 로드합니다. plugin 은 MLIR 의 표준 plugin 형태를 따르는 동적 라이브러리입니다.
| 종류 | 진입점 (C ABI) |
|---|---|
| 다이얼렉트 | mlirGetDialectPluginInfo() |
| 패스 (선택) | mlirGetPassPluginInfo() |
다이얼렉트 plugin 의 namespace 가 __mlir_op::<"NS.op_name", ...> 의 NS 자리에 들어갑니다. plugin 은 rokc 에 내장된 LLVM 버전으로 빌드해야 합니다. plugin 은 자기 MLIR 을 따로 갖지 않고 rokc 의 MLIR 을 씁니다: plugin 의 MLIR / LLVM 심볼은 해소하지 않은 채 두고, 로드할 때 rokc 가 export 하는 심볼에 묶입니다. rokc 는 자기가 링크하는 MLIR (refs-lang 8.7.1 과 8.7.5 의 다이얼렉트와 그것들이 쓰는 기반) 와 LLVM 의 support 라이브러리를 export 합니다. plugin 은 그 위에 지을 수 있으며, 그 밖의 것 (예: 다른 upstream 다이얼렉트) 은 스스로 갖춰야 합니다. 자기 MLIR 사본을 링크한 plugin 은 rokc 가 보지 못하는 registry 에 등록됩니다. Windows 에서 rokc.exe 는 toolchain 의 MLIR plugin 개발 파일과 함께 배포되는 import library 로 이 심볼들을 export 합니다. plugin DLL 은 그것에 링크하고, rokc 와 같은 C 런타임 (동적 release CRT) 을 쓰며, 자기 진입점을 export 합니다. DLL 은 rokc.exe 가 export 하는 데이터에 __declspec(dllimport) 를 통해서만 닿을 수 있습니다. plugin 개발 헤더가 MLIR 의 explicit TypeID 에 대해 이것을 갖춰 두며, 그 밖의 그런 데이터는 plugin 이 쓸 수 없습니다. 정확한 빌드 플래그는 구현이 정합니다.
1.10.3. plugin 로드
plugin 을 지정하는 방식은 두 가지입니다. 어느 쪽이든 rokc 가 lowering 전에 로드합니다.
CLI 옵션
rokc build --load-mlir-plugin /path/to/libmydialect.so main.rok
rokc build --load-mlir-plugin mydialect main.rok # 이름으로 탐색
rokc build --load-mlir-pass-plugin mypasses --mlir-pass my-lower main.rok
| 옵션 | 효과 |
|---|---|
--load-mlir-plugin <path|name> | 다이얼렉트 plugin 로드 |
--load-mlir-pass-plugin <path|name> | 패스 plugin 로드 |
--mlir-pass <pass> | LLVM 다이얼렉트로 변환하기 전에 <pass> 실행 |
모두 여러 번 쓸 수 있습니다. 경로가 아닌 이름 name 은 ROK_MLIR_PLUGIN_PATH 의 디렉토리에서 host 의 라이브러리 파일 이름 (macOS 는 lib<name>.dylib 또는 lib<name>.so, Linux 는 lib<name>.so, Windows 는 <name>.dll) 으로 찾습니다 (탐색 세부는 구현 정의). plugin 을 로드하지 못하면 빌드 에러입니다. plugin 파일은 증분 빌드의 fingerprint 에 들어가며 (refs-lang 9.2.16), rok 는 이 옵션들을 rokc 에 그대로 넘깁니다.
패키지 매니페스트 선언
패키지의 매니페스트 (rok.rokon, refs-lang 9.10) 에 plugin 을 선언하면 빌드 시 자동 로드됩니다. 매니페스트 형식은 refs-lang 9.10.3 이 정의합니다. plugin 을 선언하는 필드는 아직 그 형식에 없으며, 정해지면 9.10.3 에 추가됩니다.
1.10.4. plugin op 호출
로드된 plugin 의 op 은 upstream MLIR op 과 동일한 syntax 로 호출됩니다.
use rok::bare::mlir::__mlir_op;
unsafe {
// plugin namespace 가 "crypto" 라고 가정
let cipher: Vector<u8, 16> = __mlir_op::<"crypto.aes_round", _>(
plaintext, key,
attributes = { "round_index": __mlir_attr::<"3 : i32"> },
);
}
1.9 rok::bare::mlir 의 모든 호출 syntax (속성 / region / variadic) 가 그대로 적용됩니다. op 이름과 시그니처의 검증은 plugin 을 로드한 MLIR context 가 합니다.
1.10.5. 안전 책임
plugin 사용자 (라이브러리 작성자 + 그 라이브러리를 쓰는 사용자) 가 부담하는 책임은 다음과 같습니다.
- LLVM 버전 일치: plugin 은
rokc에 내장된 LLVM 버전으로 빌드되어rokc가 export 하는 MLIR / LLVM 심볼에 묶여야 합니다 (1.10.2). 그렇지 않으면 로드가 실패합니다. - op 의미 검증: op 이름과 시그니처는 MLIR 이 확인합니다. op 의 의미 / 부수효과 / GC 안전성은 plugin 작성자 책임입니다.
- GC root 추적: plugin op 이 GC heap 객체를 다룰 때는 그 포인터를 shadow stack frame 슬롯에 두는 root 추적 (refs-lang 7.4.1) 을 plugin lowering 에서 지켜야 하며, 그렇지 않으면 GC cycle 에서 객체가 회수될 수 있습니다.
- target 가용성: plugin 이 특정 target (GPU / FPGA / 양자 hw) 만 지원하는 경우, 해당 target 이 활성화되지 않은 빌드에서 호출하면 lowering 단계에서 에러가 납니다.
1.10.6. ABI 버전 정책
plugin ABI 는 rok 가 정하지 않고 MLIR 의 plugin API (MLIR_PLUGIN_API_VERSION) 를 따릅니다. 호환성 판정은 MLIR 이 하며, 내장 LLVM 버전이 바뀌면 plugin 을 다시 빌드해야 합니다. 이는 rok::bare tier 가 stable 하지 않다는 일반 원칙 (0.5 표준 라이브러리 계층) 과 맞습니다.
1.10.7. 빌드 격리
plugin 으로 등록된 다이얼렉트는 그 빌드에서만 활성화 됩니다. 일반 사용자가 작성하는 rok 코드의 표면 의미는 plugin 유무와 무관합니다.
// crypto plugin 없이 빌드되면 빌드 에러 (MLIR 이 op 을 모름)
unsafe {
__mlir_op::<"crypto.aes_round", _>(...)
}
rokc 는 plugin 의 namespace 를 알 수 없으므로 op 이름 검사는 MLIR 이 하며, 그 진단이 빌드 에러로 보고됩니다.
이 격리는 plugin 다이얼렉트가 rok 언어 자체의 의미에 침투하지 못하도록 하는 장치입니다. 일반 사용자 코드의 의미는 항상 본 사양만으로 결정됩니다.
1.10.8. 다른 언어와의 비교
| 언어 | plugin dialect 메커니즘 | 위치 |
|---|---|---|
| Mojo | 컴파일러 빌드 시점 통합 (외부 plugin 로드 미공식화) | 빌드 |
| MLIR C API | mlirContextLoadAllAvailableDialects 등 | 라이브러리 |
| LLVM | -load=plugin.so (legacy pass manager) | CLI |
| rok | --load-mlir-plugin ... → rokc 의 MLIR 에 로드 | CLI |
rok 은 자체 plugin ABI 를 두지 않고 MLIR 의 plugin 형태를 그대로 씁니다.
1.10.9. 범위 밖
다음은 본 사양 범위 밖입니다.
- rok 소스 코드 안에서 다이얼렉트 / op 정의 (Mojo 도 안 함)
- 동일 namespace 의 plugin 두 개를 같이 로드 (충돌 - MLIR 이 거부)
- 런타임 (실행 시점) 에 다이얼렉트 추가
- plugin 의 LLVM 버전 간 호환 (MLIR plugin API 를 따름)