Pracuję teraz nad tutorialem LLVM w Rust. Zaimplementowałem już niektóre części Kaleidoscope REPL. Udało mi się to dobrze, ale nagle przestał działać i każda próba obliczenia wartości kończy się teraz w LLVM ERROR: Target does not support MC emission!
. Wygląda na to, że stało się tak po aktualizacji kompilatora Rusta do najnowszego wieczoru (ale nie jestem tego pewien).Co może być przyczyną `LLMM ERROR: Target nie obsługuje emisji MC!`?
Stosuje się odpowiednie fragmenty kodu. Funkcja
Inicjalizacja:
#[allow(non_snake_case)]
pub unsafe fn LLVMInitializeNativeTarget() {
llvm::LLVMInitializeX86TargetInfo();
llvm::LLVMInitializeX86Target();
llvm::LLVMInitializeX86TargetMC();
}
stworzenie modułu:
let module = llvm::LLVMModuleCreateWithNameInContext(module_name.to_c_str().as_ptr(), context);
Wykonanie stworzenie silnika:
let mut exec_engine = 0 as llvm::ExecutionEngineRef;
let mut error = 0 as *const c_char;
LLVMCreateExecutionEngineForModule(&mut exec_engine, module, &mut error);
assert!(exec_engine != 0 as llvm::ExecutionEngineRef);
Kompilacja i uruchamianie funkcji:
pub fn run(value: llvm::ValueRef, context: &Context) -> f64 {
unsafe {
let result = LLVMRunFunction(context.exec_engine,
value,
0,
0 as *const GenericValueRef);
let ty = llvm::LLVMDoubleTypeInContext(context.context);
LLVMGenericValueToFloat(ty, result)
}
}
Funkcje LLVM z prefexem przez llvm :: są importowane przez rustc, te, które nie są wstępnie zaznaczone przez llvm :: są importowane przez mój kod, patrz https://github.com/jauhien/iron-kaleidoscope/blob/master/src/missing_llvm_bindings/mod.rs.
Aby zobaczyć pełną Listing, spojrzeć na https://github.com/jauhien/iron-kaleidoscope/blob/master/src/builder.rs
używam najnowszego nightly rdzy i LLVM 3.5.0.
UPD: Po skomentowaniu połączenia z LLVMInitializeNativeTarget, JIT rozpoczął pracę ponownie. Nadal zastanawiam się, jaki jest powód problemu i jak należy właściwie wykorzystywać JIT.
UPD2: po skomentowaniu linii z inicjalizacją nie wszystko znów zaczęło działać: wywołania funkcji zdefiniowanej w kodzie Rust zawodzą teraz z LLVM ERROR: Tried to execute an unknown external function
.
Funkcja Próbuję zadzwonić (ten pracował wcześniej):
#[no_mangle]
pub extern fn print(x: f64) -> f64 {
println!("> {} <", x);
x
}
Przykład sesji:
[email protected] iron-repl % ./target/iron_kaleidoscope
>extern print(x)
declare double @print(double)
>print(1)
LLVM ERROR: Tried to execute an unknown external function: print
Nie wiem, czy to jest przyczyną twojego problemu, ale 'module_name.to_c_str(). As_ptr()' jest pamięcią niebezpieczną. Nie gwarantujesz, że ciąg C przestanie być wskaźnikiem. Zobacz [docs] (http://doc.rust-lang.org/std/str/trait.StrSlice.html#tymethod.as_ptr). Polecam zamiast tego używać ['with_c_str'] (http://doc.rust-lang.org/std/c_str/trait.ToCStr.html#tymethod.with_c_str). – Dylan
Polecam również unikanie istniejącego API LLVM w Rust. Jest oparty na API LLVM C, który nie jest tak dobrze obsługiwany jak API C++ i jest całkowicie "niebezpieczny". Przekonasz się również, że brakuje niektórych części API. Dla projektu, nad którym pracuję, buduję własne bezpieczne wiązania dla klas/funkcji C++. To nie jest takie trudne, a efekt końcowy jest o wiele łatwiejszy w użyciu. – Dylan
Wiem, ale to jest tutorial. Używam więc tego, co jest już dostępne. Gdyby istniał jakiś bezpieczny interfejs API, użyłbym go. Co z 'with_c_str'? Nie widzę powodu, aby używać go tutaj.Czy ciąg może być deallocated przed funkcją, w której jest przekazywany jako parametr nazywa się? W każdym razie nie ma to nic wspólnego z moim problemem. –