First pass getting loadReagent support into the compiler with optimizations

This commit is contained in:
2025-12-17 17:49:34 -07:00
parent 6c11c0e6e5
commit 0b354d4ec0
8 changed files with 108 additions and 1 deletions

View File

@@ -930,7 +930,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]] [[package]]
name = "slang" name = "slang"
version = "0.3.2" version = "0.3.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",

View File

@@ -208,3 +208,29 @@ fn test_set_slot() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
#[test]
fn test_load_reagent() -> anyhow::Result<()> {
let compiled = compile! {
debug
r#"
device thingy = "d0";
let something = lr(thingy, "Contents", hash("Iron"));
"#
};
assert_eq!(
compiled,
indoc! {
"
j main
main:
lr r15 d0 Contents -666742878
move r8 r15
"
}
);
Ok(())
}

View File

@@ -2296,6 +2296,48 @@ impl<'a> Compiler<'a> {
Ok(None) Ok(None)
} }
System::LoadReagent(device, reagent_mode, reagent_hash) => {
let Spanned {
node: LiteralOrVariable::Variable(device_spanned),
..
} = device
else {
return Err(Error::AgrumentMismatch(
"Arg1 expected to be a variable".into(),
span,
));
};
let (device, device_cleanup) = self.compile_literal_or_variable(
LiteralOrVariable::Variable(device_spanned),
scope,
)?;
let (reagent_mode, reagent_cleanup) = self.compile_literal_or_variable(
LiteralOrVariable::Literal(reagent_mode.node),
scope,
)?;
let (reagent_hash, reagent_hash_cleanup) =
self.compile_operand(*reagent_hash, scope)?;
self.write_instruction(
Instruction::LoadReagent(
Operand::Register(VariableScope::RETURN_REGISTER),
device,
reagent_mode,
reagent_hash,
),
Some(span),
)?;
cleanup!(reagent_cleanup, reagent_hash_cleanup, device_cleanup);
Ok(Some(CompileLocation {
location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
temp_name: None,
}))
}
} }
} }

View File

@@ -10,6 +10,7 @@ macro_rules! with_syscalls {
"loadBatched", "loadBatched",
"loadBatchedNamed", "loadBatchedNamed",
"loadSlot", "loadSlot",
"loadReagent",
"set", "set",
"setBatched", "setBatched",
"setBatchedNamed", "setBatchedNamed",
@@ -35,6 +36,7 @@ macro_rules! with_syscalls {
"lb", "lb",
"lbn", "lbn",
"ls", "ls",
"lr",
"s", "s",
"sb", "sb",
"sbn", "sbn",

View File

@@ -191,6 +191,9 @@ pub enum Instruction<'a> {
/// `sbn deviceHash nameHash type value` - Set Batch Named /// `sbn deviceHash nameHash type value` - Set Batch Named
StoreBatchNamed(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), StoreBatchNamed(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
/// `lr register device reagentMode int`
LoadReagent(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
/// `j label` - Unconditional Jump /// `j label` - Unconditional Jump
Jump(Operand<'a>), Jump(Operand<'a>),
/// `jal label` - Jump and Link (Function Call) /// `jal label` - Jump and Link (Function Call)
@@ -311,6 +314,9 @@ impl<'a> fmt::Display for Instruction<'a> {
Instruction::StoreBatchNamed(d_hash, n_hash, typ, val) => { Instruction::StoreBatchNamed(d_hash, n_hash, typ, val) => {
write!(f, "sbn {} {} {} {}", d_hash, n_hash, typ, val) write!(f, "sbn {} {} {} {}", d_hash, n_hash, typ, val)
} }
Instruction::LoadReagent(reg, device, reagent_mode, reagent_hash) => {
write!(f, "lr {} {} {} {}", reg, device, reagent_mode, reagent_hash)
}
Instruction::Jump(lbl) => write!(f, "j {}", lbl), Instruction::Jump(lbl) => write!(f, "j {}", lbl),
Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl), Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl),
Instruction::JumpRelative(off) => write!(f, "jr {}", off), Instruction::JumpRelative(off) => write!(f, "jr {}", off),

View File

@@ -565,6 +565,7 @@ fn get_destination_reg(instr: &Instruction) -> Option<u8> {
| Instruction::Sqrt(Operand::Register(r), _) | Instruction::Sqrt(Operand::Register(r), _)
| Instruction::Tan(Operand::Register(r), _) | Instruction::Tan(Operand::Register(r), _)
| Instruction::Trunc(Operand::Register(r), _) | Instruction::Trunc(Operand::Register(r), _)
| Instruction::LoadReagent(Operand::Register(r), _, _, _)
| Instruction::Pop(Operand::Register(r)) => Some(*r), | Instruction::Pop(Operand::Register(r)) => Some(*r),
_ => None, _ => None,
} }
@@ -595,6 +596,9 @@ fn set_destination_reg<'a>(instr: &Instruction<'a>, new_reg: u8) -> Option<Instr
c.clone(), c.clone(),
d.clone(), d.clone(),
)), )),
Instruction::LoadReagent(_, b, c, d) => {
Some(Instruction::LoadReagent(r, b.clone(), c.clone(), d.clone()))
}
Instruction::SetEq(_, a, b) => Some(Instruction::SetEq(r, a.clone(), b.clone())), Instruction::SetEq(_, a, b) => Some(Instruction::SetEq(r, a.clone(), b.clone())),
Instruction::SetNe(_, a, b) => Some(Instruction::SetNe(r, a.clone(), b.clone())), Instruction::SetNe(_, a, b) => Some(Instruction::SetNe(r, a.clone(), b.clone())),
Instruction::SetGt(_, a, b) => Some(Instruction::SetGt(r, a.clone(), b.clone())), Instruction::SetGt(_, a, b) => Some(Instruction::SetGt(r, a.clone(), b.clone())),

View File

@@ -1909,6 +1909,20 @@ impl<'a> Parser<'a> {
Box::new(expr), Box::new(expr),
))) )))
} }
"loadReagent" | "lr" => {
let mut args = args!(3);
let next = args.next();
let device = literal_or_variable!(next);
let next = args.next();
let reagent_mode = get_arg!(Literal, literal_or_variable!(next));
let reagent_hash = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::System(System::LoadReagent(
device,
reagent_mode,
Box::new(reagent_hash),
)))
}
// Math SysCalls // Math SysCalls
"acos" => { "acos" => {

View File

@@ -237,6 +237,18 @@ documented! {
Spanned<Literal<'a>>, Spanned<Literal<'a>>,
Spanned<Literal<'a>>, Spanned<Literal<'a>>,
Box<Spanned<Expression<'a>>> Box<Spanned<Expression<'a>>>
),
/// Loads reagent of device's ReagentMode where a hash of the reagent type to check for
///
/// ## IC10
/// `lr r? device(d?|r?|id) reagentMode int`
/// ## Slang
/// `let result = loadReagent(deviceHash, "ReagentMode", reagentHash);`
/// `let result = lr(deviceHash, "ReagentMode", reagentHash);`
LoadReagent(
Spanned<LiteralOrVariable<'a>>,
Spanned<Literal<'a>>,
Box<Spanned<Expression<'a>>>
) )
} }
} }
@@ -261,6 +273,7 @@ impl<'a> std::fmt::Display for System<'a> {
} }
System::LoadSlot(a, b, c) => write!(f, "loadSlot({}, {}, {})", a, b, c), System::LoadSlot(a, b, c) => write!(f, "loadSlot({}, {}, {})", a, b, c),
System::SetSlot(a, b, c, d) => write!(f, "setSlot({}, {}, {}, {})", a, b, c, d), System::SetSlot(a, b, c, d) => write!(f, "setSlot({}, {}, {}, {})", a, b, c, d),
System::LoadReagent(a, b, c) => write!(f, "loadReagent({}, {}, {})", a, b, c),
} }
} }
} }