Sandbox IR: LLVM IR のトランザクションレイヤー¶
Sandbox IR は、LLVM IR の状態を保存/復元できる、LLVM IR の上に構築された IR レイヤーです。
API¶
Sandbox IR API は、LLVM API のように感じられるように設計されており、多くの一般的な API クラスと関数を複製して LLVM API を反映しています。クラス階層も似ています (ただし、llvm::sandboxir
名前空間にあります)。たとえば、その一部を以下に示します。
namespace sandboxir {
Value
/ \
User BasicBlock ...
/ \
Instruction Constant
/
...
}
設計¶
Sandbox IR Value <-> LLVM IR Value マッピング¶
各 LLVM IR Value は、単一の Sandbox IR Value にマップされます。逆もほとんどの場合に当てはまりますが、Sandbox IR 命令の場合は、複数の LLVM IR 命令にマップされる場合を除きます。このような命令は、ベースの Sandbox IR の拡張機能で定義できます。
順方向マッピング: Sandbox IR Value -> LLVM IR Value 各 Sandbox IR Value には、対応する LLVM IR Value を指す
llvm::Value *Val
メンバー変数が含まれています。逆方向マッピング: LLVM IR Value -> Sandbox IR Value このマッピングは、
sandboxir::Context::LLVMValueToValue
に格納されます。
たとえば、sandboxir::User::getOperand(OpIdx)
は、sandboxir::User *U
に対して次のように動作します。
まず、LLVM User を見つけます:
llvm::User *LLVMU = U->Val
。次に、LLVM Value オペランドを取得します:
llvm::Value *LLVMOp = LLVMU->getOperand(OpIdx)
最後に、Sandbox IR コンテキスト内のマップを照会して、
LLVMOp
に対応する Sandbox IR オペランドを取得します:retrun Ctx.getValue(LLVMOp)
。
Sandbox IR はライトスルーです¶
Sandbox IR は、その状態を LLVM IR に依存するように設計されています。そのため、Sandbox IR オブジェクトに加えられた変更は、対応する LLVM IR を直接更新します。
これには次の利点があります。
状態の複製を最小限に抑え、
Sandbox IR と LLVM IR が常に同期していることを保証し、バグを回避し、低レベル化の手順の必要性をなくします。
LLVM IR に依存できるため、シリアル化/デシリアル化インフラストラクチャは不要です。
実際の
llvm::Instruction
をコストモデリング API に渡すことができます。
IR の状態を変更する Sandbox IR API 関数は、LLVM IR の状態を変更する対応する LLVM IR 関数を呼び出します。たとえば、sandboxir::User::setOperand(OpIdx, sandboxir::Value *Op)
の場合
対応する LLVM User を取得します:
llvm::User *LLVMU = cast<llvm::User>(Val)
次に、対応する LLVM オペランドを取得します:
llvm::Value *LLVMOp = Op->Val
最後に、
LLVMU
のオペランドを変更します: `LLVMU->setOperand(OpIdx, LLVMOp)
IR 変更トラッキング¶
Sandbox IR の状態は保存および復元できます。これは、パブリック Sandbox IR API 関数と緊密に結合されたトラッカーコンポーネントの助けを借りて行われます。ネストされた保存/復元は現在サポートされていないことに注意してください。
状態を保存してトラッキングを有効にするには、ユーザーは sandboxir::Context::save()
を呼び出す必要があります。この時点から、Sandbox IR の状態に加えられた変更は、ユーザーの介入なしに、自動的に変更オブジェクトを作成し、トラッカーに登録します。変更はトラッカー内のベクターに累積されます。
保存された状態にロールバックするには、ユーザーは sandboxir::Context::revert()
を呼び出す必要があります。保存された状態に戻すことは、累積されたすべての変更を逆方向にたどり、個々の変更を元に戻すことです。
IR に加えられた変更を受け入れるには、ユーザーは sandboxir::Context::accept()
を呼び出す必要があります。内部的には、変更を調べて、必要な最終処理を実行します。
revert()
または accept()
を呼び出した後、トラッキングは停止することに注意してください。トラッキングを再開するには、ユーザーは save()
を呼び出す必要があります。