15

免責事項:AT&Tスタイルの構文をどれだけ嫌うかを言葉で説明することはできません

レジスターの破損が原因であると思われる問題があります。そうでなければ、私ははるかに大きな問題を抱えています。

私が最初に使用したバージョンは

static unsigned long long rdtscp(void)
{
    unsigned int hi, lo;
    __asm__ __volatile__("rdtscp" : "=a"(lo), "=d"(hi));
    return (unsigned long long)lo | ((unsigned long long)hi << 32);
}

このバージョンには「クラバリング」のものがないことに気づきました。これが問題かどうかはわかりませんが…コンパイラが関数をインライン化するかどうかによると思います。このバージョンを使用すると、常に再現できるとは限らない問題が発生します。

私が見つけた次のバージョンは

static unsigned long long rdtscp(void)
{
    unsigned long long tsc;
    __asm__ __volatile__(
        "rdtscp;"
        "shl $32, %%rdx;"
        "or %%rdx, %%rax"
        : "=a"(tsc)
        :
        : "%rcx", "%rdx");

    return tsc;
}

これは安心して読めない公式な見た目ですが、私が言ったように、私の問題は常に再現可能であるとは限らないので、私は単に私の問題の考えられる原因の1つを除外しようとしています。

最初のバージョンが問題であると私が信じる理由は、以前に関数パラメーターを保持していたレジスターを上書きしているためです。

何が正しいですか...バージョン1、バージョン2、またはその両方?

4

2 に答える 2

23

TSCを返し、補助32ビットを参照パラメーターに格納するC++コードを次に示します。

static inline uint64_t rdtscp( uint32_t & aux )
{
    uint64_t rax,rdx;
    asm volatile ( "rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : );
    return (rdx << 32) + rax;
}

インラインではなく、C ++ステートメントで両方の32ビットの半分をマージすることをお勧めします。これにより、コンパイラは適切と思われる命令をスケジュールできますshiftadd

于 2013-02-09T01:19:17.417 に答える
1

これによると、この操作は EDX と ECX を破壊します。これらのレジスタを clobbered としてマークする必要があります。これは、2 番目のレジスタが行うことです。ところで、これは上記のコードを入手したリンクですか、それとも他の場所で見つけましたか? また、タイミングの他のいくつかのバリエーションも示していますが、これはかなりきちんとしています。

于 2013-02-09T01:10:54.643 に答える