|
| 1 | +# Sandbox IR: A transactional layer over LLVM IR |
| 2 | + |
| 3 | +Sandbox IR is an IR layer on top of LLVM IR that allows you to save/restore its state. |
| 4 | + |
| 5 | +# API |
| 6 | +The Sandbox IR API is designed to feel like LLVM, replicating many common API classes and functions to mirror the LLVM API. |
| 7 | +The class hierarchy is similar (but in the `llvm::sandboxir` namespace). |
| 8 | +For example here is a small part of it: |
| 9 | +``` |
| 10 | +namespace sandboxir { |
| 11 | + Value |
| 12 | + / \ |
| 13 | + User BasicBlock ... |
| 14 | + / \ |
| 15 | + Instruction Constant |
| 16 | + / |
| 17 | + ... |
| 18 | +} |
| 19 | +``` |
| 20 | + |
| 21 | +# Design |
| 22 | + |
| 23 | +## Sandbox IR Value <-> LLVM IR Value Mapping |
| 24 | +Each LLVM IR Value maps to a single Sandbox IR Value. |
| 25 | +The reverse is also true in most cases, except for Sandbox IR Instructions that map to more than one LLVM IR Instruction. |
| 26 | +Such instructions can be defined in extensions of the base Sandbox IR. |
| 27 | + |
| 28 | +- Forward mapping: Sandbox IR Value -> LLVM IR Value |
| 29 | +Each Sandbox IR Value contains an `llvm::Value *Val` member variable that points to the corresponding LLVM IR Value. |
| 30 | + |
| 31 | +- Reverse mapping: LLVM IR Value -> Sandbox IR Value |
| 32 | +This mapping is stored in `sandboxir::Context::LLVMValueToValue`. |
| 33 | + |
| 34 | +For example `sandboxir::User::getOperand(OpIdx)` for a `sandboxir::User *U` works as follows: |
| 35 | +- First we find the LLVM User: `llvm::User *LLVMU = U->Val`. |
| 36 | +- Next we get the LLVM Value operand: `llvm::Value *LLVMOp = LLVMU->getOperand(OpIdx)` |
| 37 | +- Finally we get the Sandbox IR operand that corresponds to `LLVMOp` by querying the map in the Sandbox IR context: `retrun Ctx.getValue(LLVMOp)`. |
| 38 | + |
| 39 | +## Sandbox IR is Write-Through |
| 40 | +Sandbox IR is designed to rely on LLVM IR for its state. |
| 41 | +So any change made to Sandbox IR objects directly updates the corresponding LLVM IR. |
| 42 | + |
| 43 | +This has the following benefits: |
| 44 | +- It minimizes the replication of state, and |
| 45 | +- It makes sure that Sandbox IR and LLVM IR are always in sync, which helps avoid bugs and removes the need for a lowering step. |
| 46 | +- No need for serialization/de-serialization infrastructure as we can rely on LLVM IR for it. |
| 47 | +- One can pass actual `llvm::Instruction`s to cost modeling APIs. |
| 48 | + |
| 49 | +Sandbox IR API functions that modify the IR state call the corresponding LLVM IR function that modifies the LLVM IR's state. |
| 50 | +For example, for `sandboxir::User::setOperand(OpIdx, sandboxir::Value *Op)`: |
| 51 | +- We get the corresponding LLVM User: `llvm::User *LLVMU = cast<llvm::User>(Val)` |
| 52 | +- Next we get the corresponding LLVM Operand: `llvm::Value *LLVMOp = Op->Val` |
| 53 | +- Finally we modify `LLVMU`'s operand: `LLVMU->setOperand(OpIdx, LLVMOp) |
0 commit comments