1

要件は次のようなものです。

/* length must be >= 18 */

int calcActualLength(int length) {
    int remainder = (length - 18) % 8;
    if (remainder == 0)
        return length;
    return length + 8 - remainder;
}

ビット単位の演算子を使用して、最初の行をリファクタリングできました

int remainder = (length - 2) & 7;

さらに最適化できますか?

4

2 に答える 2

2

((length+5)&~7)+2

int calcActualLength(int length) {
    int remainder = (length - 18) % 8;
    if (remainder == 0)
        return length;
    return length + 8 - remainder;
}
==>
int HELPER_calcActualLength(int length) {
    int remainder = length % 8;
    if (remainder == 0)
        return length;
    return length + 8 - remainder;
}
int calcActualLength(int length) {
    return 18 + HELPER_calcActualLength(length - 18);
}

引数 >= 0 の場合、セマンティクスでHELPER_calcActualLength()等しいROUNDUP_8()

そして、より単純な ROUNDUP_8() は次のようになります。

#define ROUNDUP_8(x) (((x)+7)&~7)

int calcActualLength(int length) {
    return 18 + ROUNDUP_8(length - 18);
}
==>    2 + ROUNDUP_8(length - 18 + 16);
==>    2 + ROUNDUP_8(length - 2);
==>    2 + (((length - 2)+7)&~7)
==>    ((length+5)&~7)+2
于 2012-07-27T09:18:36.280 に答える
2

でコンパイルすると、元のコードは次の 64 ビット アセンブリを生成しますgcc -O3

        movl    %edi, %eax
        leal    -18(%rax), %ecx
        movl    %ecx, %edx
        sarl    $31, %edx
        shrl    $29, %edx
        addl    %edx, %ecx
        andl    $7, %ecx
        subl    %edx, %ecx
        je      .L2
        addl    $8, %eax
        subl    %ecx, %eax
.L2:
        rep

質問へのコメントで示唆されているように、引数を に変更すると、unsigned int最適化が向上し、次のアセンブリになります。

        leal    -18(%rdi), %edx
        movl    %edi, %eax
        andl    $7, %edx
        je      .L3
        leal    8(%rdi), %eax
        subl    %edx, %eax
.L3:
        rep

の倍数への切り上げは、を追加して でマスキングする8ことで実行できます。次のように動作します: 最後の 3 ビットがすべてゼロでない場合、4 番目のビットにキャリーが追加されます。それ以外の場合、キャリーは発生しません。したがって、関数は次のように単純化できます。7~77

return (((length - 18) + 7) & ~7) + 18;

またはより簡単:

return ((length - 11) & ~7) + 18;

GCC は最後の行を次のように単純にコンパイルします。

        leal    -11(%rdi), %eax
        andl    $-8, %eax
        addl    $18, %eax

lea(実効アドレスのロード) 命令は、多くの場合、次のような単純な線形結合を計算する機能のために「悪用」されることに注意してください。reg1 + size*reg2 + offset

于 2012-07-27T10:34:55.363 に答える