Skip to content

Commit

Permalink
Support for register push and pop instructions (FuelLabs#5177)
Browse files Browse the repository at this point in the history
  • Loading branch information
vaivaswatha authored Feb 13, 2024
1 parent e0ae0bd commit ccb129f
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ impl AllocatedAbstractInstructionSet {
)
.0;

fn generate_mask(regs: &[&AllocatedRegister]) -> (VirtualImmediate24, VirtualImmediate24) {
let mask = regs.iter().fold((0, 0), |mut accum, reg| {
let reg_id = reg.to_reg_id().to_u8();
assert!((16..64).contains(&reg_id));
let reg_id = reg_id - 16;
let (mask_ref, bit) = if reg_id < 24 {
(&mut accum.0, reg_id)
} else {
(&mut accum.1, reg_id - 24)
};
// Set bit (from the least significant side) of mask_ref.
*mask_ref |= 1 << bit;
accum
});
(
VirtualImmediate24::new(mask.0, Span::dummy())
.expect("mask should have fit in 24b"),
VirtualImmediate24::new(mask.1, Span::dummy())
.expect("mask should have fit in 24b"),
)
}

// Now replace the PUSHA/POPA instructions with STOREs and LOADs.
self.ops = self.ops.drain(..).fold(Vec::new(), |mut new_ops, op| {
match &op.opcode {
Expand All @@ -94,35 +116,21 @@ impl AllocatedAbstractInstructionSet {
.chain([&AllocatedRegister::Constant(ConstantRegister::LocalsBase)])
.collect::<Vec<_>>();

let stack_use_bytes = regs.len() as u64 * 8;
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::MOVE(
AllocatedRegister::Constant(ConstantRegister::Scratch),
AllocatedRegister::Constant(ConstantRegister::StackPointer),
)),
comment: "save base stack value".into(),
owning_span: None,
});
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::CFEI(
VirtualImmediate24::new(stack_use_bytes, Span::dummy()).unwrap(),
)),
comment: "reserve space for saved registers".into(),
owning_span: None,
});

regs.into_iter().enumerate().for_each(|(idx, reg)| {
let store_op = AllocatedOpcode::SW(
AllocatedRegister::Constant(ConstantRegister::Scratch),
reg.clone(),
VirtualImmediate12::new(idx as u64, Span::dummy()).unwrap(),
);
let (mask_l, mask_h) = generate_mask(&regs);
if mask_l.value != 0 {
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(store_op),
comment: format!("save {reg}"),
opcode: Either::Left(AllocatedOpcode::PSHL(mask_l)),
comment: "Save registers 16..40".into(),
owning_span: None,
});
})
}
if mask_h.value != 0 {
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::PSHH(mask_h)),
comment: "Save registers 40..64".into(),
owning_span: None,
});
}
}

Either::Right(ControlFlowOp::PopAll(label)) => {
Expand All @@ -134,37 +142,21 @@ impl AllocatedAbstractInstructionSet {
.chain([&AllocatedRegister::Constant(ConstantRegister::LocalsBase)])
.collect::<Vec<_>>();

let stack_use_bytes = regs.len() as u64 * 8;
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::SUBI(
AllocatedRegister::Constant(ConstantRegister::Scratch),
AllocatedRegister::Constant(ConstantRegister::StackPointer),
VirtualImmediate12::new(stack_use_bytes, Span::dummy()).unwrap(),
)),
comment: "save base stack value".into(),
owning_span: None,
});

regs.into_iter().enumerate().for_each(|(idx, reg)| {
let load_op = AllocatedOpcode::LW(
reg.clone(),
AllocatedRegister::Constant(ConstantRegister::Scratch),
VirtualImmediate12::new(idx as u64, Span::dummy()).unwrap(),
);
let (mask_l, mask_h) = generate_mask(&regs);
if mask_h.value != 0 {
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::POPH(mask_h)),
comment: "Restore registers 40..64".into(),
owning_span: None,
});
}
if mask_l.value != 0 {
new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(load_op),
comment: format!("restore {reg}"),
opcode: Either::Left(AllocatedOpcode::POPL(mask_l)),
comment: "Restore registers 16..40".into(),
owning_span: None,
});
});

new_ops.push(AllocatedAbstractOp {
opcode: Either::Left(AllocatedOpcode::CFSI(
VirtualImmediate24::new(stack_use_bytes, Span::dummy()).unwrap(),
)),
comment: "recover space from saved registers".into(),
owning_span: None,
});
}
}

_otherwise => new_ops.push(op),
Expand Down
17 changes: 16 additions & 1 deletion sway-core/src/asm_lang/allocated_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl fmt::Display for AllocatedRegister {
}

impl AllocatedRegister {
fn to_reg_id(&self) -> fuel_asm::RegId {
pub(crate) fn to_reg_id(&self) -> fuel_asm::RegId {
match self {
AllocatedRegister::Allocated(a) => fuel_asm::RegId::new(a + 16),
AllocatedRegister::Constant(constant) => constant.to_reg_id(),
Expand Down Expand Up @@ -152,6 +152,10 @@ pub(crate) enum AllocatedOpcode {
AllocatedRegister,
AllocatedRegister,
),
PSHH(VirtualImmediate24),
PSHL(VirtualImmediate24),
POPH(VirtualImmediate24),
POPL(VirtualImmediate24),
SB(AllocatedRegister, AllocatedRegister, VirtualImmediate12),
SW(AllocatedRegister, AllocatedRegister, VirtualImmediate12),

Expand Down Expand Up @@ -309,6 +313,9 @@ impl AllocatedOpcode {
MCP(_r1, _r2, _r3) => vec![],
MCPI(_r1, _r2, _imm) => vec![],
MEQ(r1, _r2, _r3, _r4) => vec![r1],
PSHH(_mask) | PSHL(_mask) | POPH(_mask) | POPL(_mask) => {
panic!("Cannot determine defined registers for register PUSH/POP instructions")
}
SB(_r1, _r2, _i) => vec![],
SW(_r1, _r2, _i) => vec![],

Expand Down Expand Up @@ -431,6 +438,10 @@ impl fmt::Display for AllocatedOpcode {
MCP(a, b, c) => write!(fmtr, "mcp {a} {b} {c}"),
MCPI(a, b, c) => write!(fmtr, "mcpi {a} {b} {c}"),
MEQ(a, b, c, d) => write!(fmtr, "meq {a} {b} {c} {d}"),
PSHH(mask) => write!(fmtr, "pshh {mask}"),
PSHL(mask) => write!(fmtr, "pshl {mask}"),
POPH(mask) => write!(fmtr, "poph {mask}"),
POPL(mask) => write!(fmtr, "popl {mask}"),
SB(a, b, c) => write!(fmtr, "sb {a} {b} {c}"),
SW(a, b, c) => write!(fmtr, "sw {a} {b} {c}"),

Expand Down Expand Up @@ -596,6 +607,10 @@ impl AllocatedOp {
MEQ(a, b, c, d) => {
op::MEQ::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.to_reg_id()).into()
}
PSHH(mask) => op::PSHH::new(mask.value.into()).into(),
PSHL(mask) => op::PSHL::new(mask.value.into()).into(),
POPH(mask) => op::POPH::new(mask.value.into()).into(),
POPL(mask) => op::POPL::new(mask.value.into()).into(),
SB(a, b, c) => op::SB::new(a.to_reg_id(), b.to_reg_id(), c.value.into()).into(),
SW(a, b, c) => op::SW::new(a.to_reg_id(), b.to_reg_id(), c.value.into()).into(),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"typeArguments": null
},
"name": "C0",
"offset": 4604
"offset": 4284
},
{
"configurableType": {
Expand All @@ -16,7 +16,7 @@
"typeArguments": null
},
"name": "C1",
"offset": 4620
"offset": 4300
},
{
"configurableType": {
Expand All @@ -25,7 +25,7 @@
"typeArguments": null
},
"name": "C2",
"offset": 4636
"offset": 4316
},
{
"configurableType": {
Expand All @@ -34,7 +34,7 @@
"typeArguments": []
},
"name": "C3",
"offset": 4668
"offset": 4348
},
{
"configurableType": {
Expand All @@ -43,7 +43,7 @@
"typeArguments": []
},
"name": "C4",
"offset": 4684
"offset": 4364
},
{
"configurableType": {
Expand All @@ -52,7 +52,7 @@
"typeArguments": []
},
"name": "C5",
"offset": 4700
"offset": 4380
},
{
"configurableType": {
Expand All @@ -61,7 +61,7 @@
"typeArguments": null
},
"name": "C6",
"offset": 4716
"offset": 4396
},
{
"configurableType": {
Expand All @@ -70,7 +70,7 @@
"typeArguments": null
},
"name": "C7",
"offset": 4732
"offset": 4412
},
{
"configurableType": {
Expand All @@ -79,7 +79,7 @@
"typeArguments": null
},
"name": "C7_2",
"offset": 4796
"offset": 4476
},
{
"configurableType": {
Expand All @@ -88,7 +88,7 @@
"typeArguments": null
},
"name": "C9",
"offset": 4780
"offset": 4460
}
],
"functions": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ script;
use basic_storage_abi::{BasicStorage, Quad};

fn main() -> u64 {
let addr = abi(BasicStorage, 0x1cb4847c0c736d7bc3a904728b3695b6a8e83be195ec6652cf9047bbe94f3b64);
let addr = abi(BasicStorage, 0x7ee9d721777c523e408a966d97605116e1f2bbad1c16403446c6d734d46258a6);
let key = 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
let value = 4242;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ script;
use increment_abi::Incrementor;

fn main() -> bool {
let the_abi = abi(Incrementor, 0xf5de8211162a13e64a6d868735b62aad9d01836fe0de22d69db1128a69e86bfc);
let the_abi = abi(Incrementor, 0xa1aa9555466ef3c61914e5426973e2257cb4dcd8311ffbbe0e8850a9742f312d);
let _ = the_abi.increment(5);
let _ = the_abi.increment(5);
let result = the_abi.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ script;
use storage_enum_abi::*;

fn main() -> u64 {
let contract_id = 0x2c6686f3a059e41298f5680c92a8effdc628cf86ac293b84ea9fc10fa1fd7906;
let contract_id = 0x097ea9a771b69bf349375a0d6db542e9c730194de4bcd27e4e6665ffb107dfaf;
let caller = abi(StorageEnum, contract_id);

let res = caller.read_write_enums();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use storage_access_abi::*;
use std::hash::*;

fn main() -> bool {
let contract_id = 0x9f807040099c184c7784fd61e1c9d200244d3e2130a486a32c6a20a90cf3616f;
let contract_id = 0xcd976bf8d7f3a9b54416c215ee0c732cbae4f9221e281fbc6c6aa8f428f03eb1;
let caller = abi(StorageAccess, contract_id);

caller.set_boolean(true);
Expand Down

0 comments on commit ccb129f

Please sign in to comment.