1. ホーム
  2. c++

carries_dependency]]属性の意味は何ですか?

2023-08-27 02:56:42

質問

誰か凡人にもわかる言葉で説明してください。

どのように解決するのですか?

[[carries_dependency]] は、関数呼び出しに渡って依存関係を持ち運べるようにするために使用されます。このため、コンパイラはより良いコードを生成できる可能性があります。 std::memory_order_consume を使用した場合、コンパイラーはより良いコードを生成できるようになります。

特に、もし memory_order_consume で読み取った値を関数に渡すと、その関数に [[carries_dependency]] がない場合、コンパイラは適切なメモリ順序セマンティクスが維持されることを保証するためにメモリフェンス命令を発行しなければならないかもしれません。パラメータに [[carries_dependency]] でアノテートされている場合、コンパイラは関数本体が正しく依存関係を運ぶと仮定することができ、このフェンスはもはや必要ないかもしれません。

同様に、もし関数が memory_order_consume でロードされた値、またはそのような値から派生した値を返す場合、そのような値なしに [[carries_dependency]] がない場合、コンパイラは適切なメモリ順序セマンティクスが維持されることを保証するためにフェンス命令を挿入することが必要になる場合があります。この場合 [[carries_dependency]] アノテーションを使用すると、呼び出し元が依存関係ツリーを維持する責任があるため、このフェンスはもはや必要ないかもしれません。

など。

void print(int * val)
{
    std::cout<<*val<<std::endl;
}

void print2(int * [[carries_dependency]] val)
{
    std::cout<<*val<<std::endl;
}

std::atomic<int*> p;
int* local=p.load(std::memory_order_consume);
if(local)
    std::cout<<*local<<std::endl; // 1

if(local)
    print(local); // 2

if(local)
    print2(local); // 3

(1)の行では、依存関係が明示されているので、コンパイラは local が再参照されること、そしてPOWER上のフェンスを避けるために依存関係の連鎖が保存されることを保証しなければならないことがわかります。

(2)の行で、定義されている print の定義が不透明であるため (インライン化されていないと仮定して)、 コンパイラがフェンスを発行して *pprint は正しい値を返します。

(3)の行で、コンパイラは print2 も不透明であるため、パラメータから参照される値への依存関係は命令ストリームに保存され、POWERでのフェンスは不要であるとコンパイラは考えることができます。明らかに print2 の定義は実際にこの依存関係を保持する必要があるため、この属性は print2 .