2016-04-22 31 views
5

Pracuję nad skrzynią Rust, która zmienia tryb zaokrąglania (+ inf, -inf, nearest lub truncate).Który z LLVM odpowiada za optymalizacje zmiennoprzecinkowe?

Funkcje, które zmieniają tryb zaokrąglania są napisane przy użyciu zestawu inline:

fn upward() { 
    let cw: u32 = 0; 
    unsafe { 
    asm!("stmxcsr $0; 
      mov $0, %eax; 
      or $$0x4000, %eax; 
      mov %eax, $0; 
      ldmxcsr $0;" 
      : "=*m"(&cw) 
      : "*m"(&cw) 
      : "{eax}" 
     ); 
    } 
} 

Kiedy skompilować kod w trybie debugowania, że ​​działa zgodnie z przeznaczeniem, dostaję 0.3333333333337 jedną trzecią gdy zaokrąglenie w kierunku dodatnim nieskończoności, ale gdy kompiluję w trybie zwolnienia, otrzymuję ten sam wynik niezależnie od ustawionego trybu zaokrąglania. Sądzę, że to zachowanie wynika z optymalizacji, które wykonuje backend LLVM.

Jeśli wiedziałem, które przepustki LLVM są odpowiedzialne za tę optymalizację, mogę je wyłączyć, ponieważ nie widzę obecnie żadnego innego obejścia.

+0

Obawiam się, że informacje te mogą w dużym stopniu zależeć od wersji LLVM (która jest bezpłatna do dodawania/usuwania karnetów), a w związku z tym jest związana z wersją 'rustc'. Którą wersję 'rustc' używasz? Czy przeszkadza Ci to, gdy ulegnie uszkodzeniu podczas aktualizacji? –

+0

Używam Rust 1.10 co wieczór. Nie mam nic przeciwko, jeśli się zepsuje. Jeśli rozumiem, co powoduje takie zachowanie, mogę z odrobiną ciężkiej pracy zrobić pewne obejście. –

+1

Po pewnym odczycie uważam, że istnieją pewne podania do harmonogramu, które przesuwają instrukcję dzielenia przed wywołaniem funkcji upward(). (tylko przypuszczenie), popraw mnie, jeśli się mylę. –

Odpowiedz

4

Zasadniczo nie można tego zrobić. LLVM zakłada, że ​​wszystkie operacje zmiennoprzecinkowe używają domyślnego trybu zaokrąglania i że rejestr sterujący zmiennoprzecinkowy nie jest nigdy czytany ani modyfikowany.

Byłem some discussion of this issue recently on the LLVM-dev mailing list, jeśli jesteś zainteresowany.

W tym czasie jedynym niezawodnym rozwiązaniem jest użycie wbudowanego zestawu, takiego jak asm!("addsd $0, $1".

Standardowa biblioteka Rusta zakłada również, że nie modyfikuje się trybu zaokrąglania (w szczególności, kod przekształcenia między zmiennoprzecinkowy i łańcuchy jest z tym wrażliwy).

+0

Jeśli dobrze rozumiem, podczas korzystania z zespołu wbudowanego, tryb zaokrąglania ustawiony w rejestrach mxcsr lub fctrl jest brany pod uwagę przez obliczenia w asm! makro? –

+1

Tak. W tym momencie po prostu piszesz surowy montaż, więc semantyka Rust lub LLVM IR nie ma znaczenia. –

+0

Tak, ofc, optymalizacja LLVM są dokonywane na IR, dziękuję. –