137 lines
4.6 KiB
Rust
137 lines
4.6 KiB
Rust
//! Ordered block-local statements for Slonik IR.
|
|
//!
|
|
//! In the lift IR every value-producing operation is a statement anchored in a
|
|
//! block. This ensures memory order is always explicit in the statement stream
|
|
//! rather than floating in a sea of pure expressions.
|
|
|
|
use crate::ir::{BinaryOp, Block, CastOp, FloatCC, IntCC, MemSize, UnaryOp, Value};
|
|
use cranelift_entity::EntityList;
|
|
|
|
/// A compact list of SSA values.
|
|
pub type ValueList = EntityList<Value>;
|
|
|
|
/// A target block together with the SSA arguments passed to that block.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub struct BlockCall {
|
|
/// The destination block.
|
|
pub block: Block,
|
|
|
|
/// The arguments passed to the destination block.
|
|
pub args: ValueList,
|
|
}
|
|
|
|
/// An ordered statement inside a basic block.
|
|
///
|
|
/// Variants that carry a `result` field produce exactly one SSA value.
|
|
/// The `result` value's [`ValueDef`] points back to this statement.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum StmtData {
|
|
// ------------------------------------------------------------------ //
|
|
// Value-producing statements //
|
|
// ------------------------------------------------------------------ //
|
|
|
|
/// Signed integer literal. Result type determines the width.
|
|
IConst { imm: i64, result: Value },
|
|
|
|
/// 32-bit float literal stored as raw IEEE-754 bits.
|
|
F32Const { bits: u32, result: Value },
|
|
|
|
/// 64-bit float literal stored as raw IEEE-754 bits.
|
|
F64Const { bits: u64, result: Value },
|
|
|
|
/// Boolean literal.
|
|
BConst { value: bool, result: Value },
|
|
|
|
/// Unary operation.
|
|
Unary { op: UnaryOp, arg: Value, result: Value },
|
|
|
|
/// Binary operation.
|
|
Binary { op: BinaryOp, lhs: Value, rhs: Value, result: Value },
|
|
|
|
/// Cast or conversion.
|
|
Cast { op: CastOp, arg: Value, result: Value },
|
|
|
|
/// Integer comparison. Result type is always `bool`.
|
|
Icmp { cc: IntCC, lhs: Value, rhs: Value, result: Value },
|
|
|
|
/// Floating-point comparison. Result type is always `bool`.
|
|
Fcmp { cc: FloatCC, lhs: Value, rhs: Value, result: Value },
|
|
|
|
/// Conditional select. `cond` must be `bool`.
|
|
Select {
|
|
cond: Value,
|
|
if_true: Value,
|
|
if_false: Value,
|
|
result: Value,
|
|
},
|
|
|
|
/// Memory load. Anchored in the statement stream to preserve memory order.
|
|
Load { addr: Value, size: MemSize, result: Value },
|
|
|
|
// ------------------------------------------------------------------ //
|
|
// Side-effecting statements (no result value) //
|
|
// ------------------------------------------------------------------ //
|
|
|
|
/// Memory store.
|
|
Store { addr: Value, value: Value, size: MemSize },
|
|
|
|
/// Effectful call.
|
|
Call { callee: Value, args: ValueList },
|
|
|
|
// ------------------------------------------------------------------ //
|
|
// Terminators //
|
|
// ------------------------------------------------------------------ //
|
|
|
|
/// Unconditional jump.
|
|
Jump { dst: BlockCall },
|
|
|
|
/// Conditional branch.
|
|
BrIf {
|
|
cond: Value,
|
|
then_dst: BlockCall,
|
|
else_dst: BlockCall,
|
|
},
|
|
|
|
/// Return from the current body.
|
|
Return { values: ValueList },
|
|
}
|
|
|
|
impl StmtData {
|
|
/// Returns the result value produced by this statement, if any.
|
|
pub const fn result(self) -> Option<Value> {
|
|
match self {
|
|
Self::IConst { result, .. }
|
|
| Self::F32Const { result, .. }
|
|
| Self::F64Const { result, .. }
|
|
| Self::BConst { result, .. }
|
|
| Self::Unary { result, .. }
|
|
| Self::Binary { result, .. }
|
|
| Self::Cast { result, .. }
|
|
| Self::Icmp { result, .. }
|
|
| Self::Fcmp { result, .. }
|
|
| Self::Select { result, .. }
|
|
| Self::Load { result, .. } => Some(result),
|
|
|
|
Self::Store { .. }
|
|
| Self::Call { .. }
|
|
| Self::Jump { .. }
|
|
| Self::BrIf { .. }
|
|
| Self::Return { .. } => None,
|
|
}
|
|
}
|
|
|
|
/// Returns whether this statement is a block terminator.
|
|
pub const fn is_terminator(self) -> bool {
|
|
matches!(self, Self::Jump { .. } | Self::BrIf { .. } | Self::Return { .. })
|
|
}
|
|
|
|
/// Returns whether this statement may read memory.
|
|
pub const fn may_read_memory(self) -> bool {
|
|
matches!(self, Self::Load { .. } | Self::Call { .. })
|
|
}
|
|
|
|
/// Returns whether this statement may write memory.
|
|
pub const fn may_write_memory(self) -> bool {
|
|
matches!(self, Self::Store { .. } | Self::Call { .. })
|
|
}
|
|
}
|