Files
hakorune/src/mir/query.rs
tomoaki 41d28330e9 feat(select): Task 2-E complete - VM/LLVM backend support for Select instruction
Phase 256 P1.5: Implement Select instruction (ternary conditional) across entire MIR pipeline

Task 2-E Implementation:
- Added Select ValueId entry to effects() in instruction/methods.rs (pure operation)
- Added Select case to dst_value() for definition tracking
- Added Select case to used_values() for use-def chains (cond, then_val, else_val)
- Fixed non-exhaustive pattern matches in 5 locations:
  * src/mir/instruction/methods.rs: 3 match arms (effects, dst_value, used_values)
  * src/mir/printer_helpers.rs: format_instruction display
  * src/mir/query.rs: reads_of and writes_of MirQuery trait

- Created VM backend: src/llvm_py/instructions/select.py
  * lower_select() implements ternary: dst = cond ? then_val : else_val
  * Converts cond to i1 for boolean test
  * Uses llvmlite builder.select() for LLVM IR generation

- Integrated Select dispatch in instruction_lower.py
  * Imported lower_select module
  * Added select case to instruction dispatch (after barrier, before while)
  * Passes resolver, ValueIds, and CFG context

Compilation Status:  0 errors (cargo build --release succeeded)
MIR Output:  Select instructions present in generated MIR
Next: Investigate SSA undefined value issue in Pattern7 loop_step

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-20 03:20:55 +09:00

174 lines
6.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! MirQuery - Read/Write/CFGビューを提供する共通窓口
//!
//! Box理論: MIR 全体の構造は MirQueryBox が保持し、他の箱ExitLiveness など)は
//! 「見せる窓」である MirQuery トレイト越しにしか触らないようにする。
//! これにより MIR 構造への依存を最小化し、テスタビリティと疎結合を保つ。
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
/// MIR への読み取り専用ビュー
pub trait MirQuery {
/// ブロック内の命令列PHI を含む)を順序付きで返す
fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction];
/// ブロックの後続succsを決定的順序で返す
fn succs(&self, bb: BasicBlockId) -> Vec<BasicBlockId>;
/// 命令が読むuse するValueId のリスト
fn reads_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
/// 命令が書くdef するValueId のリスト
fn writes_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
}
/// MirQuery の標準実装MirFunction 全体を抱えつつビューを提供
pub struct MirQueryBox<'m> {
mir: &'m MirFunction,
}
impl<'m> MirQueryBox<'m> {
pub fn new(mir: &'m MirFunction) -> Self {
Self { mir }
}
}
impl<'m> MirQuery for MirQueryBox<'m> {
fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction] {
static EMPTY: &[MirInstruction] = &[];
self.mir
.blocks
.get(&bb)
.map(|bb| bb.instructions.as_slice())
.unwrap_or(EMPTY)
}
fn succs(&self, bb: BasicBlockId) -> Vec<BasicBlockId> {
let mut v: Vec<_> = self
.mir
.blocks
.get(&bb)
.map(|bb| bb.successors.iter().copied().collect())
.unwrap_or_else(Vec::new);
v.sort_by_key(|b| b.0);
v
}
fn reads_of(&self, inst: &MirInstruction) -> Vec<ValueId> {
use MirInstruction::*;
match inst {
Const { .. } | Nop => Vec::new(),
Copy { src, .. } => vec![*src],
UnaryOp { operand, .. } => vec![*operand],
BinOp { lhs, rhs, .. } | Compare { lhs, rhs, .. } => {
vec![*lhs, *rhs]
}
TypeOp { value, .. } | TypeCheck { value, .. } | Cast { value, .. } => {
vec![*value]
}
Load { ptr, .. } => vec![*ptr],
Store { ptr, value } => vec![*ptr, *value],
ArrayGet { array, index, .. } => vec![*array, *index],
ArraySet {
array,
index,
value,
..
} => vec![*array, *index, *value],
Call { args, .. }
| BoxCall { args, .. }
| PluginInvoke { args, .. }
| ExternCall { args, .. } => args.clone(),
Return { value } => value.iter().copied().collect(),
Branch { condition, .. } => vec![*condition],
Jump { .. } => Vec::new(),
Phi { inputs, .. } => inputs.iter().map(|(_, v)| *v).collect(),
NewBox { args, .. } => args.clone(),
Debug { value, .. } | Print { value, .. } => vec![*value],
DebugLog { values, .. } => values.clone(),
Throw { exception, .. } => vec![*exception],
Catch { .. } => Vec::new(),
NewClosure { captures, me, .. } => {
let mut v: Vec<ValueId> = captures.iter().map(|(_, v)| *v).collect();
if let Some(m) = me {
v.push(*m);
}
v
}
RefNew { box_val, .. } => vec![*box_val],
RefGet { reference, .. } => vec![*reference],
RefSet {
reference, value, ..
} => vec![*reference, *value],
WeakNew { box_val, .. } => vec![*box_val],
WeakLoad { weak_ref, .. } => vec![*weak_ref],
WeakRef { value, .. } => vec![*value],
BarrierRead { ptr } | BarrierWrite { ptr } | Barrier { ptr, .. } => {
vec![*ptr]
}
FutureNew { value, .. } => vec![*value],
FutureSet { future, value } => vec![*future, *value],
Await { future, .. } => vec![*future],
Safepoint => Vec::new(),
// Phase 256 P1.5: Select instruction reads cond, then_val, else_val
Select {
cond,
then_val,
else_val,
..
} => vec![*cond, *then_val, *else_val],
}
}
fn writes_of(&self, inst: &MirInstruction) -> Vec<ValueId> {
use MirInstruction::*;
match inst {
Const { dst, .. }
| UnaryOp { dst, .. }
| BinOp { dst, .. }
| Compare { dst, .. }
| TypeOp { dst, .. }
| Cast { dst, .. }
| Load { dst, .. }
| ArrayGet { dst, .. }
| Call { dst: Some(dst), .. }
| BoxCall { dst: Some(dst), .. }
| PluginInvoke { dst: Some(dst), .. }
| ExternCall { dst: Some(dst), .. }
| Phi { dst, .. }
| NewBox { dst, .. }
| RefNew { dst, .. }
| RefGet { dst, .. }
| WeakNew { dst, .. }
| WeakLoad { dst, .. }
| WeakRef { dst, .. }
| FutureNew { dst, .. }
| NewClosure { dst, .. }
| Await { dst, .. }
| Copy { dst, .. }
| Select { dst, .. } => vec![*dst], // Copy writes to dst, Select writes to dst
// No writes
Nop
| Store { .. }
| ArraySet { .. }
| Call { dst: None, .. }
| BoxCall { dst: None, .. }
| PluginInvoke { dst: None, .. }
| ExternCall { dst: None, .. }
| Return { .. }
| Branch { .. }
| Jump { .. }
| Debug { .. }
| DebugLog { .. }
| Print { .. }
| Throw { .. }
| Catch { .. }
| BarrierRead { .. }
| BarrierWrite { .. }
| Barrier { .. }
| FutureSet { .. }
| Safepoint => Vec::new(),
_ => Vec::new(),
}
}
}