ここでも、ほとんどの本当のSchemeシステムが若干異なる実装を使用します。例えば、
GET_PAIR
がx
の下位ビットを減算するのではなく、それらをマスクする代わりに、オプティマイザは、参照する構造体メンバのオフセットを加算することでその減算を組み合わせることができます。変更されていないポインタとして使用します。
この減算を正確に達成する方法と、オプティマイザが修正されていないポインタのように速くポインタを修正する方法については、
ここでも、ほとんどの本当のSchemeシステムが若干異なる実装を使用します。例えば、
GET_PAIR
がx
の下位ビットを減算するのではなく、それらをマスクする代わりに、オプティマイザは、参照する構造体メンバのオフセットを加算することでその減算を組み合わせることができます。変更されていないポインタとして使用します。
この減算を正確に達成する方法と、オプティマイザが修正されていないポインタのように速くポインタを修正する方法については、
この記事で紹介されているトリックは、タイプ情報を8バイト整列ポインタの未使用の3つの最下位ビットにエンコードすることです。この情報を使用してタイプを見つけると、ポインタを再度アドレスとして使用する前に、これらの追加のビットをクリアする必要があります。
#define GET_PAIR(x) ((struct pair *) ((int) (x) & ~7))
この時点では、すでにタイプがわかっているので、3つの最下位ビットの値を知っています。それらは常に0b010
(10進数2)になります。したがって、((int) (x) & ~7)
を書く代わりに、著者はむしろ((int) (x) - 2)
と書くことを提案します。アイデアは、あなたがこのようなコード、
if (PAIR_P(x))
{
SCM * thing = GET_PAIR(x)->cdr;
/* Use the thing… */
}
我々はstruct pair
は(下位ビットをクリア後)x
で指さ内cdr
メンバーにアクセスしているので、コンパイラが生成するコードを書く場合は調整するということです適切にポインタ。このようなもの。
SCM * thing = (SCM *) ((char *)((int) (x) - 2)) + offsetof(struct pair, cdr));
おかげ整数加算と減算の連想に、我々は、
(int) (x) - 2 + offsetof(struct pair, cdr)
両方(いずれにせよないマシンコードを生成しない外側のポインタキャストを示していない)括弧の1つのレベルを省略して得ることができ2
とoffsetof(struct pair, cdr)
はコンパイル時の定数で、1つの定数に変換することができます。 car
メンバー(オフセット0)をリクエストした場合、このトリックは助けにはなりませんが、他のすべての時間を助けてもそれほど悪くはありません。
近代的なオプティマイザは、(x & 7) == 2
をテストした後、に相当するx & ~7
と同等であるため、最近はトリックが必要ない可能性があります。あなたはそれに頼る前にこれを測定したいと思います。
詳細な回答ありがとうございます!私は構造のオフセットについて考えていない。今私は理解している。ありがとうございました! –
'&'の代わりに '-'を使用しますか? –
これはCまたはC++に関するものではありません。どちらもビットシフトではありません。タグをスパムしないでください。 – Olaf