17

私はClangのソースコードを読んでいて、ARM C ++ ABIについて何か面白いものを発見しましたが、その正当性を理解できないようです。ARM ABIドキュメントのオンラインバージョンから:

このABIでは、C1およびC2コンストラクターがこれを返す必要があります(void関数ではなく)。これにより、C3コンストラクターはC1コンストラクターを末尾呼び出しでき、C1コンストラクターはC2を末尾呼び出しできます。

(非仮想デストラクタについても同様です)

C1ここで、、、C2および参照が何であるかはわかりませんC3...このセクションは、汎用(つまりItanium)ABIからの§3.1.5の変更を意味しますが、そのセクション(少なくともこのオンラインバージョンでは)は単に次のように述べています。

コンストラクターはvoidの結果を返します。

とにかく、私はこれの目的が何であるかを本当に理解できません:コンストラクターにこれを返すようにすると、どのように末尾呼び出しの最適化が可能になりますか?

私が知る限り、コンストラクターが同じthis戻り値を持つ別のコンストラクターを末尾呼び出しできるのは、単一の基本クラス、単純なコンストラクター本体、重要なコンストラクターを持つメンバー、仮想のない派生クラスの場合のみです。テーブルポインタ。実際、returnを使用した末尾呼び出しを使用して最適化する方が、実際には簡単であるように思われます。これvoidにより、単一の基本クラスの制限を排除できるためです(複数の基本クラスの場合this、最後に呼び出されたコンストラクターはthis、派生オブジェクトのポインターにはなりません)。

ここで何が欠けていますか?thisリターンを必要とするARM呼び出し規約について何かありますか?

4

1 に答える 1

11

わかりました。@Michaelからの役立つリンクにより、これがすべて明確になりました...、、およびItaniumC1C2C3完全オブジェクトコンストラクタ」、「ベースオブジェクトコンストラクタ」、および「完全オブジェクト割り当てコンストラクタ」の名前マングリングをそれぞれ参照してください。 ABI:

  <ctor-dtor-name> ::= C1   # complete object constructor
                   ::= C2   # base object constructor
                   ::= C3   # complete object allocating constructor
                   ::= D0   # deleting destructor
                   ::= D1   # complete object destructor
                   ::= D2   # base object destructor

/ "完全オブジェクト割り当てコンストラクター"は、パラメーターC3を介して渡された既に割り当てられたストレージを操作するのではなく、内部で(を介して)メモリを割り当ててから、 /"完全オブジェクトコンストラクター"を呼び出すバージョンのコンストラクターです。完全なオブジェクトの場合に使用される通常のコンストラクター。コンストラクターは、新しく割り当てられて構築されたオブジェクトへのポインターを返す必要があるため、末尾呼び出しを使用するには、コンストラクターもポインターを返す必要があります。thisoperator newC1C3thisC1this

/ C2"基本オブジェクトコンストラクター"は、基本クラスサブオブジェクトを作成するときに派生クラスによって呼び出されるコンストラクターです。C1C2コンストラクターのセマンティクスは、virtual継承の場合は異なり、最適化の目的でも異なる方法で実装できます。virtual継承の場合、コンストラクターは、基本クラスコンストラクターへの呼び出しと、それに続くコンストラクターへの末尾呼び出しを使用しC1て実装できます。したがって、前者の場合は後者も返されます。virtualC2this

デストラクタのケースは少し異なりますが、関連しています。ARM ABIによると:

同様に、D2とD1がこれを返す必要があるため、D0はこれを保存して復元する必要がなく D1はD2を末尾呼び出しできます(仮想ベースがない場合)。D0はまだvoid関数です。

D0/ "deleting destructor"は、オブジェクトを削除するときに使用され、/ D1"complete object destructor"を呼び出しoperator deletethis後でポインタを使用して呼び出してメモリを解放します。デストラクタをD1返すthisことにより、D0デストラクタはその戻り値を使用しoperator deleteて、別のレジスタに保存したりメモリにスピルしたりするのではなく、を呼び出すことができます。同様に、D2/"ベースオブジェクトデストラクタ"も返さthisれるはずです。

ARMABIは次も追加します。

これを返すために仮想デストラクタにサンクを要求する必要はありません。このようなサンクは、デストラクタの結果を調整し、デストラクタの末尾呼び出しを防ぎ、可能な保存を無効にする必要があります。

したがって、これを返すために信頼できるのは、D1およびD2デストラクタの非仮想呼び出しのみです。

これを正しく理解していれば、このsave-restore-elision最適化は、静的にD0呼び出す場合にのみ使用できることを意味しますD1(つまり、非virtualデストラクタの場合)。

于 2013-03-16T19:43:36.037 に答える