でコンパイルすると、元のコードは次の 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
~7
7
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