2016-03-20 15 views
4

オーバーフローのチェックで整数演算を行う場合、計算ではしばしば複数の算術演算を構成する必要があります。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アーキテクチャで最適化する方法を経験している人はいますか?明示的なアンロールが価値があるかどうか、特により複雑な表現について教えてください。

+2

あなたの質問はあまり明確ではありません。理想的な答えには何が含まれますか? – Shepmaster

+0

私は、アンロールされたアプローチが人間工学に基づいたコードよりもはるかに優れている場合、一貫したコンパイラの動作の逸話や、より良い観察を思いつきたいと思います。 – mzabaluev

答えて

3

Rustコンパイラが上記のいずれかのパターンをさまざまなCPUアーキテクチャで最適化する方法を経験したことがある人は、明示的なアンロールが価値があるかどうか、特により複雑な表現について教えてください。

playgroundを使用すると、LLVMの最適化方法を確認できます。「実行」ではなく「LLVM IR」または「ASM」をクリックしてください。チェックする関数に#[inline(never)]を貼り付け、定数の折り畳みを避けるためにランタイム引数を渡すように注意してください。 hereのように:

use std::env; 

#[inline(never)] 
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) 
    } 
} 

fn main() { 
    let vec: Vec<usize> = env::args().map(|s| s.parse().unwrap()).collect(); 
    let result = calculate_size(vec[0], vec[1], vec[2]); 
    println!("{:?}",result); 
} 

あなたが買ってあげるの答えは、しかし、錆やLLVMのオーバフロー組み込み関数は、残念ながら、利便性ではなく、パフォーマンスのために符号化されたされていること。これは、明示的なアンロールがうまく最適化されますが、チェックされたコードを最適化するためにLLVMでカウントすることは現実的ではないことを意味します。

通常これは問題ではありません。パフォーマンスホットスポットの場合は、手動でアンロールすることができます。

注:このパフォーマンスの欠如は、リリースモードではデフォルトでオーバーフローチェックが無効になっている理由です。

+1

遊び場のヒントありがとう! x86-64では、オプティマイザは両方の例と非常によく似たコードを生成しますが、これは 'oflo1 | oflo2 | ... 'を一連のテストとブランチに変換します。結局それが本当に問題ではない場合、慣用コードは手の最適化のために主題になることはないかもしれません。ブランチは、典型的な計算(オーバーフローは例外的であるか、誤使用によるもの)ではうまく予測される傾向がありますが、特にコードが一般的な場合は、予測変数への排出圧力を増大させる可能性があります。 – mzabaluev

+1

私はhttps://github.com/rust-lang/rust/issues/32414として私の所見を提出しました。 – mzabaluev

関連する問題