2

このコードをX86でテストしました。

void func()
{
  int a, b;
  unsigned int c, d;
  int ret;

  ret = a / b;  // This line use idivl, expected
  ret = c / d;  // this line use idivl, expected
  ret = a / c;  // this line use divl..., surprised 
  ret = c / a;  // this line use divl..., supriised
  ret = a * c;  // this line use imull, expected
}

ここにアセンブリコードを貼り付けます:

func:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $36, %esp
    movl    -4(%ebp), %eax
    movl    %eax, %edx
    sarl    $31, %edx
    idivl   -8(%ebp)
    movl    %eax, -20(%ebp)
    movl    -12(%ebp), %eax
    movl    $0, %edx
    divl    -16(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    movl    $0, %edx
    divl    -12(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    movl    %eax, -36(%ebp)
    movl    -12(%ebp), %eax
    movl    $0, %edx
    divl    -36(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    imull   -12(%ebp), %eax
    movl    %eax, -20(%ebp)
    leave
    ret

なぜidivlの代わりにdivlを使用してintとunsignedintを分割するのか教えてください。

4

1 に答える 1

6

とのタイプは同じ変換ランクaを持ちますが、符号付きと符号なしであるため、との両方で、除算の前に変換されます。cacaunsigned inta / cc / a

したがって、コンパイラは、divこれらの場合(およびc / d、両方のオペランドが符号なしの場合)に符号なし除算命令を発行します。

乗算a * cも符号なし乗算です。この場合、コンパイラは符号付き乗算命令の使用を回避できます。これは、切り捨てられた結果が使用されているかどうかimullに関係なく同一であるためです。フラグのみが異なり、生成されたコードはそれらをテストしません。mullimull

于 2012-11-18T12:32:32.450 に答える