オーバーフローのチェックで整数演算を行う場合、計算ではしばしば複数の算術演算を構成する必要があります。Rustでチェックされた算術演算を連鎖する
fn calculate_size(elem_size: usize,
length: usize,
offset: usize)
-> Option<usize> {
elem_size.checked_mul(length)
.and_then(|acc| acc.checked_add(offset))
}
はしかし、これは各基本操作あたりの枝を生成するようにコンパイラーに指示します:錆でチェック算術連鎖の簡単な方法は、checked_*
方法とOption
チェーンを使用しています。 overflowing_*
の実装ことを条件とする
fn calculate_size(elem_size: usize,
length: usize,
offset: usize)
-> Option<usize> {
let (acc, oflo1) = elem_size.overflowing_mul(length);
let (acc, oflo2) = acc.overflowing_add(offset);
if oflo1 | oflo2 {
None
} else {
Some(acc)
}
}
に関係なくオーバーフローの計算を続けるとビット単位でオーバーフローフラグを凝集または、多くても1つの分岐全体評価で行われることを確実にする(:私はoverflowing_*
方法を使用して、より広げられたアプローチに遭遇しましたブランチレスコードを生成する)。この最適化に適したアプローチはより煩雑であり、中間値を扱う際には注意が必要です。
Rustコンパイラが上記のいずれかのパターンをさまざまなCPUアーキテクチャで最適化する方法を経験している人はいますか?明示的なアンロールが価値があるかどうか、特により複雑な表現について教えてください。
あなたの質問はあまり明確ではありません。理想的な答えには何が含まれますか? – Shepmaster
私は、アンロールされたアプローチが人間工学に基づいたコードよりもはるかに優れている場合、一貫したコンパイラの動作の逸話や、より良い観察を思いつきたいと思います。 – mzabaluev