2016-04-22 6 views
5

Я работаю над ящиком ржавчины, который меняет режим округления (+ inf, -inf, ближайшее или усекать).Какие пропуска LLVM отвечают за оптимизацию с плавающей запятой?

функции, которые изменяют режим округления записываются с использованием ассемблерные:

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}" 
     ); 
    } 
} 

Когда я компиляции кода в режиме отладки он работает, как задумано, я получаю 0.3333333333337 на одну треть при округлении в сторону положительной бесконечности, но когда я компилирую в режиме выпуска, я получаю тот же результат независимо от того, какой режим округления я устанавливаю. Я предполагаю, что это поведение связано с оптимизациями, которые делает сервер LLVM.

Если бы я знал, какие пропуска LLVM отвечают за эту оптимизацию, я могу отключить их, поскольку на данный момент я не вижу другого обходного пути.

+0

Я боюсь, что эта информация может сильно зависеть от версии LLVM (которая бесплатна для добавления/удаления проходов) и в результате связана с версией 'rustc'. Какую версию 'rustc' вы используете? Не возражаете, если это ломается при обновлении? –

+0

Я использую Rust 1.10 ночной. Я не возражаю, если он сломается. Если я понимаю, что вызывает такое поведение, я могу с небольшой усердием сделать некоторые способы обхода. –

+1

После некоторого чтения я думаю, что есть некоторые прогоны планирования, которые перемещают инструкцию деления перед вызовом функции вверх(). (просто догадка), исправьте меня, если я ошибаюсь. –

ответ

4

В принципе, вы не можете этого сделать. LLVM предполагает, что все операции с плавающей запятой используют режим округления по умолчанию и что регистр управления с плавающей запятой никогда не читается и не изменяется.

Было some discussion of this issue recently on the LLVM-dev mailing list, если вам интересно.

В то же время единственным надежным обходным путем является использование встроенной сборки, например asm!("addsd $0, $1".

Стандартная библиотека Rust также предполагает, что вы не изменяете режим округления (в частности, код для преобразования между плавающей точкой и строками чувствителен к этому).

+0

Если я правильно понимаю, при использовании встроенной сборки режим округления, установленный в регистрах mxcsr или fctrl, учитывается при вычислении в asm! макрос? –

+1

Да. В этот момент вы в основном просто пишете сырую сборку, поэтому семантика Rust или LLVM IR не имеет значения. –

+0

Да, из-за оптимизации LLVM на IR, спасибо. –