Skip to content

Commit

Permalink
Replace __jmpb_ssp with __jmp_mem (#5674)
Browse files Browse the repository at this point in the history
The new intrinsic jumps to an absolute address that is fetched from
`MEM[$hp]`. This is more versatile than the `__jmpb_ssp` that was
previously provided. An immediate advantage being that we can have a
working version of `ldc` even in debug
builds.

The test has been modified too, to demonstrate an LDC use that works. A
working version is at
https://github.com/FuelLabs/ldc-testing/blob/309c79a8f73e26992123fb3ee9777b89dfda9ab1/test-contract/src/main.sw

Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com>
  • Loading branch information
vaivaswatha and sdankel authored Mar 3, 2024
1 parent d5b8cb8 commit 0c03ce0
Show file tree
Hide file tree
Showing 20 changed files with 118 additions and 145 deletions.
8 changes: 3 additions & 5 deletions docs/book/src/reference/compiler_intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,9 @@ __not(op: T) -> T
___

```sway
__jmpb_ssp(offset: u64)
__jmp_mem()
```

**Description:** Jumps to `$ssp - offset`. When the offset is the growth
of `$ssp` after an `ldc` call, this transfers control to the newly loaded
contract.
**Description:** Jumps to `MEM[$hp]`.

**Constraints:** offset must have type `u64`.
**Constraints:** None.
6 changes: 3 additions & 3 deletions sway-ast/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub enum Intrinsic {
PtrSub,
Smo,
Not,
JmpbSsp,
JmpMem,
}

impl fmt::Display for Intrinsic {
Expand Down Expand Up @@ -74,7 +74,7 @@ impl fmt::Display for Intrinsic {
Intrinsic::PtrSub => "ptr_sub",
Intrinsic::Smo => "smo",
Intrinsic::Not => "not",
Intrinsic::JmpbSsp => "jmpb_ssp",
Intrinsic::JmpMem => "jmp_mem",
};
write!(f, "{s}")
}
Expand Down Expand Up @@ -117,7 +117,7 @@ impl Intrinsic {
"__ptr_sub" => PtrSub,
"__smo" => Smo,
"__not" => Not,
"__jmpb_ssp" => JmpbSsp,
"__jmp_mem" => JmpMem,
_ => return None,
})
}
Expand Down
31 changes: 15 additions & 16 deletions sway-core/src/asm_generation/fuel/fuel_asm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
arg2,
arg3,
} => self.compile_wide_modular_op(instr_val, op, result, arg1, arg2, arg3),
FuelVmInstruction::JmpbSsp(offset) => self.compile_jmpb_ssp(instr_val, offset),
FuelVmInstruction::JmpMem => self.compile_jmp_mem(instr_val),
},
InstOp::GetElemPtr {
base,
Expand Down Expand Up @@ -1452,45 +1452,44 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
Ok(())
}

fn compile_jmpb_ssp(&mut self, instr_val: &Value, offset: &Value) -> Result<(), CompileError> {
fn compile_jmp_mem(&mut self, instr_val: &Value) -> Result<(), CompileError> {
let owning_span = self.md_mgr.val_to_span(self.context, *instr_val);
let offset_reg = self.value_to_register(offset)?;
let is_offset_reg = self.reg_seqr.next();
let prev_ssp_reg = self.reg_seqr.next();
let target_reg = self.reg_seqr.next();
let is_target_reg = self.reg_seqr.next();
let by4_reg = self.reg_seqr.next();

self.cur_bytecode.push(Op {
owning_span: owning_span.clone(),
opcode: Either::Left(VirtualOp::SUB(
prev_ssp_reg.clone(),
VirtualRegister::Constant(ConstantRegister::StackStartPointer),
offset_reg,
opcode: Either::Left(VirtualOp::LW(
target_reg.clone(),
VirtualRegister::Constant(ConstantRegister::HeapPointer),
VirtualImmediate12::new(0, Span::dummy()).unwrap(),
)),
comment: "jmpb_ssp: Compute $ssp - offset".into(),
comment: "jmp_mem: Load MEM[$hp]".into(),
});
self.cur_bytecode.push(Op {
owning_span: owning_span.clone(),
opcode: Either::Left(VirtualOp::SUB(
is_offset_reg.clone(),
prev_ssp_reg,
is_target_reg.clone(),
target_reg,
VirtualRegister::Constant(ConstantRegister::InstructionStart),
)),
comment: "jmpb_ssp: Subtract $is since $jmp adds it back.".into(),
comment: "jmp_mem: Subtract $is since Jmp adds it back.".into(),
});
self.cur_bytecode.push(Op {
owning_span: owning_span.clone(),
opcode: Either::Left(VirtualOp::DIVI(
by4_reg.clone(),
is_offset_reg.clone(),
is_target_reg.clone(),
VirtualImmediate12::new(4, Span::dummy()).unwrap(),
)),
comment: "jmpb_ssp: Divide by 4 since Jmp multiplies by 4.".into(),
comment: "jmp_mem: Divide by 4 since Jmp multiplies by 4.".into(),
});

self.cur_bytecode.push(Op {
owning_span,
opcode: Either::Left(VirtualOp::JMP(by4_reg)),
comment: "jmpb_ssp: Jump to computed value".into(),
comment: "jmp_mem: Jump to computed value".into(),
});

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/asm_generation/fuel/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {

// Free our stack allocated locals. This is unneeded for entries since they will have
// actually returned to the calling context via a VM RET.
self.drop_locals(function);
self.drop_locals();

// Restore $reta.
self.cur_bytecode.push(Op::register_move(
Expand Down Expand Up @@ -946,7 +946,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
.push((locals_size_bytes, locals_base_reg, max_num_extra_args));
}

fn drop_locals(&mut self, _function: Function) {
pub(super) fn drop_locals(&mut self) {
let (locals_size_bytes, max_num_extra_args) =
(self.locals_size_bytes(), self.max_num_extra_args());
if locals_size_bytes > compiler_constants::TWENTY_FOUR_BITS {
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ fn const_eval_intrinsic(
| Intrinsic::StateStoreQuad
| Intrinsic::Log
| Intrinsic::Revert
| Intrinsic::JmpbSsp
| Intrinsic::JmpMem
| Intrinsic::Smo => Err(ConstEvalError::CannotBeEvaluatedToConst {
span: intrinsic.span.clone(),
}),
Expand Down
8 changes: 2 additions & 6 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,16 +1095,12 @@ impl<'eng> FnCompiler<'eng> {
.add_metadatum(context, span_md_idx);
Ok(TerminatorValue::new(val, context))
}
Intrinsic::JmpbSsp => {
let offset_val = return_on_termination_or_extract!(
self.compile_expression_to_value(context, md_mgr, &arguments[0])?
);

Intrinsic::JmpMem => {
let span_md_idx = md_mgr.span_to_md(context, &span);
let val = self
.current_block
.append(context)
.jmpb_ssp(offset_val)
.jmp_mem()
.add_metadatum(context, span_md_idx);
Ok(TerminatorValue::new(val, context))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ impl ty::TyIntrinsicFunctionKind {
}
Intrinsic::Smo => type_check_smo(handler, ctx, kind, arguments, type_arguments, span),
Intrinsic::Not => type_check_not(handler, ctx, kind, arguments, type_arguments, span),
Intrinsic::JmpbSsp => {
type_check_jmpb_ssp(handler, ctx, kind, arguments, type_arguments, span)
Intrinsic::JmpMem => {
type_check_jmp_mem(handler, ctx, kind, arguments, type_arguments, span)
}
}
}
Expand Down Expand Up @@ -1173,12 +1173,11 @@ fn type_check_revert(
))
}

/// Signature: `__jmpb_ssp(offset: u64) -> !`
/// Description: Jumps to `$ssp - offset`.
/// Constraints: offset has type `u64`.
fn type_check_jmpb_ssp(
/// Signature: `__jmp_mem() -> !`
/// Description: Jumps to `MEM[$hp]`.
fn type_check_jmp_mem(
handler: &Handler,
mut ctx: TypeCheckContext,
ctx: TypeCheckContext,
kind: sway_ast::Intrinsic,
arguments: Vec<Expression>,
type_arguments: Vec<TypeArgument>,
Expand All @@ -1187,7 +1186,7 @@ fn type_check_jmpb_ssp(
let type_engine = ctx.engines.te();
let engines = ctx.engines();

if arguments.len() != 1 {
if !arguments.is_empty() {
return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs {
name: kind.to_string(),
expected: 0,
Expand All @@ -1203,18 +1202,10 @@ fn type_check_jmpb_ssp(
}));
}

// Type check the argument which is the jmpb_ssp offset
let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert(
engines,
TypeInfo::UnsignedInteger(IntegerBits::SixtyFour),
None,
));
let offset = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?;

Ok((
ty::TyIntrinsicFunctionKind {
kind,
arguments: vec![offset],
arguments: vec![],
type_arguments: vec![],
span,
},
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/semantic_analysis/cei_pattern_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ fn effects_of_intrinsic(intr: &sway_ast::Intrinsic) -> HashSet<Effect> {
StateClear | StateStoreWord | StateStoreQuad => HashSet::from([Effect::StorageWrite]),
StateLoadWord | StateLoadQuad => HashSet::from([Effect::StorageRead]),
Smo => HashSet::from([Effect::OutputMessage]),
Revert | JmpbSsp | IsReferenceType | IsStrArray | SizeOfType | SizeOfVal | SizeOfStr
Revert | JmpMem | IsReferenceType | IsStrArray | SizeOfType | SizeOfVal | SizeOfStr
| AssertIsStrArray | ToStrArray | Eq | Gt | Lt | Gtf | AddrOf | Log | Add | Sub | Mul
| Div | And | Or | Xor | Mod | Rsh | Lsh | PtrAdd | PtrSub | Not => HashSet::new(),
}
Expand Down
4 changes: 2 additions & 2 deletions sway-ir/src/analysis/memory_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ pub fn get_loaded_ptr_values(context: &Context, val: Value) -> Vec<Value> {
InstOp::Store { dst_val_ptr: _, .. } => vec![],
InstOp::FuelVm(FuelVmInstruction::Gtf { .. })
| InstOp::FuelVm(FuelVmInstruction::ReadRegister(_))
| InstOp::FuelVm(FuelVmInstruction::Revert(_) | FuelVmInstruction::JmpbSsp(_)) => vec![],
| InstOp::FuelVm(FuelVmInstruction::Revert(_) | FuelVmInstruction::JmpMem) => vec![],
InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { arg, .. }) => vec![*arg],
InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { arg1, arg2, .. })
| InstOp::FuelVm(FuelVmInstruction::WideCmpOp { arg1, arg2, .. }) => {
Expand Down Expand Up @@ -252,7 +252,7 @@ pub fn get_stored_ptr_values(context: &Context, val: Value) -> Vec<Value> {
| FuelVmInstruction::Log { .. }
| FuelVmInstruction::ReadRegister(_)
| FuelVmInstruction::Revert(_)
| FuelVmInstruction::JmpbSsp(_)
| FuelVmInstruction::JmpMem
| FuelVmInstruction::Smo { .. }
| FuelVmInstruction::StateClear { .. } => vec![],
FuelVmInstruction::StateLoadQuadWord { load_val, .. } => vec![*load_val],
Expand Down
4 changes: 1 addition & 3 deletions sway-ir/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,7 @@ impl Block {
i,
Instruction {
op: InstOp::Ret(..)
| InstOp::FuelVm(
FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpbSsp(..)
),
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpMem),
..
}
)
Expand Down
17 changes: 9 additions & 8 deletions sway-ir/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ pub enum FuelVmInstruction {
arg1: Value,
arg2: Value,
},
JmpbSsp(Value),
JmpMem,
}

/// Comparison operations.
Expand Down Expand Up @@ -299,7 +299,7 @@ impl InstOp {
// These are all terminators which don't return, essentially. No type.
InstOp::Branch(_)
| InstOp::ConditionalBranch { .. }
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpbSsp(..))
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpMem)
| InstOp::Ret(..) => None,

// No-op is also no-type.
Expand Down Expand Up @@ -408,7 +408,8 @@ impl InstOp {
log_val, log_id, ..
} => vec![*log_val, *log_id],
FuelVmInstruction::ReadRegister(_) => vec![],
FuelVmInstruction::Revert(v) | FuelVmInstruction::JmpbSsp(v) => vec![*v],
FuelVmInstruction::Revert(v) => vec![*v],
FuelVmInstruction::JmpMem => vec![],
FuelVmInstruction::Smo {
recipient,
message,
Expand Down Expand Up @@ -545,7 +546,7 @@ impl InstOp {
}
FuelVmInstruction::ReadRegister { .. } => (),
FuelVmInstruction::Revert(revert_val) => replace(revert_val),
FuelVmInstruction::JmpbSsp(contr_id) => replace(contr_id),
FuelVmInstruction::JmpMem => (),
FuelVmInstruction::Smo {
recipient,
message,
Expand Down Expand Up @@ -631,7 +632,7 @@ impl InstOp {
| InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. })
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpbSsp(..))
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpMem)
| InstOp::MemCopyBytes { .. }
| InstOp::MemCopyVal { .. }
| InstOp::Store { .. }
Expand Down Expand Up @@ -666,7 +667,7 @@ impl InstOp {
InstOp::Branch(_)
| InstOp::ConditionalBranch { .. }
| InstOp::Ret(..)
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpbSsp(..))
| InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpMem)
)
}
}
Expand Down Expand Up @@ -1074,11 +1075,11 @@ impl<'a, 'eng> InstructionInserter<'a, 'eng> {
revert_val
}

pub fn jmpb_ssp(self, offset: Value) -> Value {
pub fn jmp_mem(self) -> Value {
let ldc_exec = Value::new_instruction(
self.context,
self.block,
InstOp::FuelVm(FuelVmInstruction::JmpbSsp(offset)),
InstOp::FuelVm(FuelVmInstruction::JmpMem),
);
self.context.blocks[self.block.0]
.instructions
Expand Down
2 changes: 1 addition & 1 deletion sway-ir/src/optimize/fn_dedup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ fn hash_fn(context: &Context, function: Function, eq_class: &mut EqClass) -> u64
crate::FuelVmInstruction::Log { log_ty, .. } => log_ty.hash(state),
crate::FuelVmInstruction::ReadRegister(reg) => reg.hash(state),
crate::FuelVmInstruction::Revert(_)
| crate::FuelVmInstruction::JmpbSsp(_)
| crate::FuelVmInstruction::JmpMem
| crate::FuelVmInstruction::Smo { .. }
| crate::FuelVmInstruction::StateClear { .. }
| crate::FuelVmInstruction::StateLoadQuadWord { .. }
Expand Down
4 changes: 1 addition & 3 deletions sway-ir/src/optimize/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,9 +535,7 @@ fn inline_instruction(
new_block.append(context).read_register(reg)
}
FuelVmInstruction::Revert(val) => new_block.append(context).revert(map_value(val)),
FuelVmInstruction::JmpbSsp(offset) => {
new_block.append(context).jmpb_ssp(map_value(offset))
}
FuelVmInstruction::JmpMem => new_block.append(context).jmp_mem(),
FuelVmInstruction::Smo {
recipient,
message,
Expand Down
14 changes: 7 additions & 7 deletions sway-ir/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ mod ir_builder {
/ op_read_register()
/ op_ret()
/ op_revert()
/ op_jmpb_ssp()
/ op_jmp_mem()
/ op_smo()
/ op_state_load_quad_word()
/ op_state_load_word()
Expand Down Expand Up @@ -363,9 +363,9 @@ mod ir_builder {
IrAstOperation::Revert(vn)
}

rule op_jmpb_ssp() -> IrAstOperation
= "jmpb_ssp" _ vn:id() {
IrAstOperation::JmpbSsp(vn)
rule op_jmp_mem() -> IrAstOperation
= "jmp_mem" _ {
IrAstOperation::JmpMem
}

rule op_smo() -> IrAstOperation
Expand Down Expand Up @@ -728,7 +728,7 @@ mod ir_builder {
ReadRegister(String),
Ret(IrAstTy, String),
Revert(String),
JmpbSsp(String),
JmpMem,
Smo(String, String, String, String),
StateClear(String, String),
StateLoadQuadWord(String, String, String),
Expand Down Expand Up @@ -1351,9 +1351,9 @@ mod ir_builder {
.append(context)
.revert(*val_map.get(&ret_val_name).unwrap())
.add_metadatum(context, opt_metadata),
IrAstOperation::JmpbSsp(offset_name) => block
IrAstOperation::JmpMem => block
.append(context)
.jmpb_ssp(*val_map.get(&offset_name).unwrap())
.jmp_mem()
.add_metadatum(context, opt_metadata),
IrAstOperation::Smo(recipient, message, message_size, coins) => block
.append(context)
Expand Down
Loading

0 comments on commit 0c03ce0

Please sign in to comment.