amd64 の GCC で使用可能な 128 ビット操作を取得しようとして、いくつかのインライン関数を実装しました。add_128_128_128 のように。最大限の柔軟性を得るために、どのレジスタを入力および出力として使用するかをコンパイラに決定させたいと考えました。そこで、複数の代替制約を使用しました。
inline __uint128_t add_128_128_128(__uint128_t a, __uint128_t b) {
uint64_t a_hi = a >> 64;
uint64_t a_lo = a;
uint64_t b_hi = b >> 64;
uint64_t b_lo = b;
uint64_t retval_hi;
uint64_t retval_lo;
asm (
"\n"
" add %2, %0\n"
" adc %3, %1\n"
: "=r,r,r,r" (retval_lo)
, "=r,r,r,r" (retval_hi)
: "r,0,r,0" (a_lo)
, "0,r,0,r" (b_lo)
, "r,1,1,r" (a_hi)
, "1,r,r,1" (b_hi)
);
return ((__uint128_t)retval_hi) << 64 | retval_lo;
}
これで、生成されたアセンブラー出力は次のようになります。
_Z11add_128_128oo:
movq %rdx, %rax
movq %rcx, %rdx
add %rdi, %rax
adc %rax, %rdx
ret
私が困惑しているのは、ADC 命令を修正する方法です。これについて考えた結果、一致する制約でさえ「新しい」数値を取得するという一時的な結論に達しました。これにより、%rax が %3 == %0 == %rax であることが説明されます。それで、GCCに「r」制約のみをカウントするように指示する方法はありますか? (複数の代替制約をあきらめるだけで、このインライン アセンブリを機能させることができることはわかっています。)
ところで: GCC のインライン アセンブリに関する有用なドキュメントはありますか? 興味深いものに関しては、例がまったくない公式マニュアルは、このコンテキストでは役に立ちません。Google で検索しても何も見つかりませんでした。すべてのハウツーやものは、些細な基本的なことについて話しているだけで、複数の代替制約などのより高度なものは完全に省略されています。