FreePascal は正しいです。には 3 つの形式しかありませんMUL
。
MUL r/m8
MUL r/m16
MUL r/m32
第 1 オペランド (デスティネーション オペランド) と第 2 オペランド (ソース オペランド) の符号なし乗算を実行し、結果をデスティネーション オペランドに格納します。デスティネーション オペランドは、レジスタ AL、AX、または EAX (オペランドのサイズに応じて) にある暗黙のオペランドです。ソース オペランドは、汎用レジスタまたはメモリ ロケーションにあります。
つまり、第 1 オペランド (入力と出力の両方に使用される) はAL
/ AX
/EAX
で指定され、第 2 オペランドは汎用レジスタまたはメモリ アドレスとして明示的に指定されます。
したがって、MUL EAX,EDX
実際には無効なアセンブリ命令です。
このコードを Delphi でコンパイルし、デバッガを使用して生成されたアセンブリを確認すると、 の呼び出しMul(10,20)
によって次のアセンブリ コードが生成されることがわかります。
// Mul(10,20)
mov edx,$00000014
mov eax,$0000000a
call Mul
//MUL EAX,EDX
mul edx
ご覧のように、Delphi は実際にソース コードを解析し、最初のオペランドが存在することを確認EAX
してそれを取り除き、正しいアセンブリを生成します。FreePascal はそのステップを行っていません。
回避策は?まず、適切なアセンブリ コードを記述します。コードの再解釈をコンパイラに頼らないでください。
function Mul(A, B: LongWord): LongWord;
asm
MUL EDX
end;
または、アセンブリ コードを直接記述できず、コンパイラに作業を任せることもできます。LongWord
2 つの値を乗算する方法を知っています。
function Mul(A, B: LongWord): LongWord;
begin
Result := A * B;
end;
この場合、 Delphi はIMUL
代わりに ofを使用しますが。MUL
Delphiのドキュメントから:
の値は、とx / y
の型Extended
に関係なく、型です。他の算術演算子の場合、少なくとも 1 つのオペランドが実数の場合、結果は型になります。それ以外の場合、少なくとも 1 つのオペランドが type の場合、結果はtypeです。それ以外の場合、結果の型はです。オペランドの型が整数型の部分範囲である場合、それは整数型であるかのように扱われます。x
y
Extended
Int64
Int64
Integer
また、スタックフレームを無効にして最適化を有効にしない限り、見苦しい肥大化したアセンブリを使用します。Mul()
これらの 2 つのオプションを構成することにより、単一IMUL EDX
の命令 (RET
もちろん、命令も)を生成することができます。プロジェクト全体でオプションを変更したくない場合は、 /および/コンパイラ命令Mul()
を使用するだけでそれらを分離できます。{$STACKFRAMES OFF}
{$W-}
{$OPTIMIZATION ON}
{$O+}
{$IFOPT W+}{$W-}{$DEFINE SF_Was_On}{$ENDIF}
{$IFOPT O-}{$O+}{$DEFINE O_Was_Off}{$ENDIF}
function Mul(A, B: LongWord): LongWord;
begin
Result := A * B;
end;
{$IFDEF SF_Was_On}{W+}{$UNDEF SF_Was_On}{$ENDIF}
{$IFDEF O_Was_Off}{O-}{$UNDEF O_Was_Off}{$ENDIF}
生成:
imul edx
ret