ページへ戻る
印刷
技術系備忘録/C++/最適化小手先テクニック/”エイリアスを使わないと仮定する”の意味
をテンプレートにして作成 ::
シンクリッジ
xpwiki
:技術系備忘録/C++/最適化小手先テクニック/”エイリアスを使わないと仮定する”の意味 をテンプレートにして作成
開始行:
VC++には(それ以外のコンパイラにもきっと)、"エイリアスを...
このオプションは、"サイズ優先"とか"実行速度優先"という最...
まずリスト1に例を挙げます。上段がC++のソースコード。下段...
-List1
--ソース
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
for(int i=0; i<*pSize; i++ ){
pBuffer[i] = 0;
}
}
}}
--出力
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
mov ecx, pSize
xor eax, eax
cmp DWORD PTR [ecx], eax
jle SHORT LABEL2
LABEL1 // ループ戻り先(このラベルは次のmovの下でいい気が...
mov edx,pBuffer // クリアするバッファを取得
and BYTE PTR [eax+edx],0 // 1バイトクリア
inc eax // カウンタをインクリメント
cmp eax, DWORD PTR [ecx] // クリアサイズとカウンタを比...
jl SHORT LABEL1 // まだ途中ならLABEL1に戻って繰り返す
LABEL2
ret
}
}}
このコードは一見してわかるように、指定された領域のメモリ...
出力されたコードをみると、コンパイラはとても素直に最適化...
今回の最適化オプションは、このような繰り返し処理を効率良...
-List2
--ソース
#prettify{{
// "エイリアスを使わないと仮定する"を有効
#pragma optimize ( "a", on )
void MemClear(int *pSize,char *pBuffer)
{
for(int i=0; i<*pSize; i++ ){
pBuffer[i] = 0;
}
}
#pragma optimize ( "", on ) // 元に戻す
}}
--出力
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
mov eax, pSize
mov ecx, DWORD PTR [eax]
test ecx, ecx
jle SHORT LABEL1
mov edx, ecx
push edi
mov edi, pBuffer
xor eax, eax
shr ecx, 2 // クリアサイズ(の1/4。32BITで処理する為)
rep stosd // 一気にクリア
mov ecx, edx
and ecx, 3 // クリアサイズ(の4で割った余り)
rep stosb // 一気にクリア
pop edi
LABEL1
ret
}
}}
リスト1と比べると、繰り返し処理(条件分岐)も無くなってお...
本ネタで重要だと思うのは以下になります。
なぜ、リスト1はリスト2のように最適化されないかというと、
コンパイラは、繰り返しの条件であるクリアサイズ(*pSize)が...
と考えるからです。
リスト2は、"エイリアスを使わないと仮定する"としているの...
ここまでの説明だと、"エイリアスを使わないと仮定する"を常...
むやみやたらに最適化させると、ソースコード的には正しいけ...
僕の個人的意見では、"エイリアスを使わないと仮定する"は無...
例えばリスト3のようにします。
-List3
--ソース
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
int nSize = *pSize; // サイズをローカル変数にコピー
for(int i=0; i<nSize; i++ ){
pBuffer[i] = 0;
}
}
}}
--出力
#prettify{{
(リスト2と同じコードなので割愛)
}}
最初にクリアサイズ(*pSize)をローカル変数にコピーして、そ...
pBufferへの書き込みによってループ条件が変わることはないの...
以上のことから、自分の個人的意見を言わせてもらうと、
"エイリアスを使わないと仮定する"最適化オプションは使わな...
使うことで最適化されるケースがあるのであれば、コードの書...
"エイリアスを使わないと仮定する"最適化オプションの利用法...
無効の場合と有効の場合とで、出力されるアセンブラを比較し...
もし有効にすることで最適化されるようなケースがあったなら...
という判断材料として"エイリアスを使わないと仮定する"を使...
/*
最近のコンパイラは優秀だと改めて思いました。
for文でメモリクリアって、昔は rep stosd とか使ってくれな...
今回の例であるメモリクリアであれば memset とか使うのが常...
なお、かといって memset を使わずに for でメモリクリアを実...
VC++(他のコンパイラは良く知りません)には、組み込み関数...
*/
終了行:
VC++には(それ以外のコンパイラにもきっと)、"エイリアスを...
このオプションは、"サイズ優先"とか"実行速度優先"という最...
まずリスト1に例を挙げます。上段がC++のソースコード。下段...
-List1
--ソース
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
for(int i=0; i<*pSize; i++ ){
pBuffer[i] = 0;
}
}
}}
--出力
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
mov ecx, pSize
xor eax, eax
cmp DWORD PTR [ecx], eax
jle SHORT LABEL2
LABEL1 // ループ戻り先(このラベルは次のmovの下でいい気が...
mov edx,pBuffer // クリアするバッファを取得
and BYTE PTR [eax+edx],0 // 1バイトクリア
inc eax // カウンタをインクリメント
cmp eax, DWORD PTR [ecx] // クリアサイズとカウンタを比...
jl SHORT LABEL1 // まだ途中ならLABEL1に戻って繰り返す
LABEL2
ret
}
}}
このコードは一見してわかるように、指定された領域のメモリ...
出力されたコードをみると、コンパイラはとても素直に最適化...
今回の最適化オプションは、このような繰り返し処理を効率良...
-List2
--ソース
#prettify{{
// "エイリアスを使わないと仮定する"を有効
#pragma optimize ( "a", on )
void MemClear(int *pSize,char *pBuffer)
{
for(int i=0; i<*pSize; i++ ){
pBuffer[i] = 0;
}
}
#pragma optimize ( "", on ) // 元に戻す
}}
--出力
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
mov eax, pSize
mov ecx, DWORD PTR [eax]
test ecx, ecx
jle SHORT LABEL1
mov edx, ecx
push edi
mov edi, pBuffer
xor eax, eax
shr ecx, 2 // クリアサイズ(の1/4。32BITで処理する為)
rep stosd // 一気にクリア
mov ecx, edx
and ecx, 3 // クリアサイズ(の4で割った余り)
rep stosb // 一気にクリア
pop edi
LABEL1
ret
}
}}
リスト1と比べると、繰り返し処理(条件分岐)も無くなってお...
本ネタで重要だと思うのは以下になります。
なぜ、リスト1はリスト2のように最適化されないかというと、
コンパイラは、繰り返しの条件であるクリアサイズ(*pSize)が...
と考えるからです。
リスト2は、"エイリアスを使わないと仮定する"としているの...
ここまでの説明だと、"エイリアスを使わないと仮定する"を常...
むやみやたらに最適化させると、ソースコード的には正しいけ...
僕の個人的意見では、"エイリアスを使わないと仮定する"は無...
例えばリスト3のようにします。
-List3
--ソース
#prettify{{
void MemClear(int *pSize,char *pBuffer)
{
int nSize = *pSize; // サイズをローカル変数にコピー
for(int i=0; i<nSize; i++ ){
pBuffer[i] = 0;
}
}
}}
--出力
#prettify{{
(リスト2と同じコードなので割愛)
}}
最初にクリアサイズ(*pSize)をローカル変数にコピーして、そ...
pBufferへの書き込みによってループ条件が変わることはないの...
以上のことから、自分の個人的意見を言わせてもらうと、
"エイリアスを使わないと仮定する"最適化オプションは使わな...
使うことで最適化されるケースがあるのであれば、コードの書...
"エイリアスを使わないと仮定する"最適化オプションの利用法...
無効の場合と有効の場合とで、出力されるアセンブラを比較し...
もし有効にすることで最適化されるようなケースがあったなら...
という判断材料として"エイリアスを使わないと仮定する"を使...
/*
最近のコンパイラは優秀だと改めて思いました。
for文でメモリクリアって、昔は rep stosd とか使ってくれな...
今回の例であるメモリクリアであれば memset とか使うのが常...
なお、かといって memset を使わずに for でメモリクリアを実...
VC++(他のコンパイラは良く知りません)には、組み込み関数...
*/
ページ名: