Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1947,12 +1947,12 @@ fn report_assembly_information(
// https://github.com/FuelLabs/sway/blob/afd6a6709e7cb11c676059a5004012cc466e653b/sway-core/src/asm_generation/fuel/data_section.rs#L147
fn calculate_entry_size(entry: &sway_core::asm_generation::Entry) -> u64 {
match &entry.value {
sway_core::asm_generation::Datum::Byte(value) => std::mem::size_of_val(value) as u64,
sway_core::asm_generation::Datum::U8(value) => std::mem::size_of_val(value) as u64,
sway_core::asm_generation::Datum::U16(value) => std::mem::size_of_val(value) as u64,
sway_core::asm_generation::Datum::U32(value) => std::mem::size_of_val(value) as u64,
sway_core::asm_generation::Datum::U64(value) => std::mem::size_of_val(value) as u64,

sway_core::asm_generation::Datum::Word(value) => std::mem::size_of_val(value) as u64,

sway_core::asm_generation::Datum::ByteArray(bytes)
| sway_core::asm_generation::Datum::Slice(bytes) => {
sway_core::asm_generation::Datum::ByRef(bytes) => {
if bytes.len() % 8 == 0 {
bytes.len() as u64
} else {
Expand Down
6 changes: 3 additions & 3 deletions forc-plugins/forc-client/tests/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ async fn test_simple_deploy() {
node.kill().unwrap();
let expected = vec![DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"b45b5f58ff2f05c3593ffe4241188c14644aaa1e42dc7defae12b8d09cc6a292",
"654c47c7cc216cd33480712fccf5998ba89874e669ee9b07d4f835f3cba85aba",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -421,7 +421,7 @@ async fn test_deploy_submit_only() {
node.kill().unwrap();
let expected = vec![DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"b45b5f58ff2f05c3593ffe4241188c14644aaa1e42dc7defae12b8d09cc6a292",
"654c47c7cc216cd33480712fccf5998ba89874e669ee9b07d4f835f3cba85aba",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -468,7 +468,7 @@ async fn test_deploy_fresh_proxy() {
node.kill().unwrap();
let impl_contract = DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"b45b5f58ff2f05c3593ffe4241188c14644aaa1e42dc7defae12b8d09cc6a292",
"654c47c7cc216cd33480712fccf5998ba89874e669ee9b07d4f835f3cba85aba",
)
.unwrap(),
proxy: Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,12 @@ fn ra(instruction: Instruction) -> Option<String> {
Instruction::XORI(op) => Some(op.ra()),
Instruction::JNEI(op) => Some(op.ra()),
Instruction::LB(op) => Some(op.ra()),
Instruction::LQW(op) => Some(op.ra()),
Instruction::LHW(op) => Some(op.ra()),
Instruction::LW(op) => Some(op.ra()),
Instruction::SB(op) => Some(op.ra()),
Instruction::SQW(op) => Some(op.ra()),
Instruction::SHW(op) => Some(op.ra()),
Instruction::SW(op) => Some(op.ra()),
Instruction::MCPI(op) => Some(op.ra()),
Instruction::GTF(op) => Some(op.ra()),
Expand Down
32 changes: 11 additions & 21 deletions sway-core/src/asm_generation/finalized_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::{
fuel::{checks, data_section::DataSection},
ProgramABI, ProgramKind,
};
use crate::asm_generation::fuel::compiler_constants::EIGHTEEN_BITS;
use crate::asm_generation::fuel::data_section::{Datum, Entry, EntryName};
use crate::asm_lang::allocated_ops::{AllocatedInstruction, AllocatedOp, FuelAsmData};
use crate::decl_engine::DeclRefFunction;
Expand Down Expand Up @@ -180,7 +181,11 @@ fn to_bytecode_mut(
// The -4 is because $pc is added in the *next* instruction.
let pointer_offset_from_current_instr =
offset_to_data_section_in_bytes - offset_from_instr_start + offset_bytes - 4;
data_section.append_pointer(pointer_offset_from_current_instr);

// If the pointer can't be loaded using a simple MOVI op, we need to use the data section
if pointer_offset_from_current_instr > EIGHTEEN_BITS {
data_section.append_pointer(pointer_offset_from_current_instr);
}
}
_ => (),
}
Expand Down Expand Up @@ -314,11 +319,11 @@ fn to_bytecode_mut(
print!("{}{:#010x} ", " ".repeat(indentation), offset);

match &pair.value {
Datum::Byte(w) => println!(".byte i{w}, as hex {w:02X}"),
Datum::Word(w) => {
println!(".word i{w}, as hex be bytes ({:02X?})", w.to_be_bytes())
}
Datum::ByteArray(bs) => {
Datum::U8(v) => println!(".byte i{}, as hex {:02X}", v, v),
Datum::U16(v) => println!(".quarterword i{}, as hex {:02X?}", v, v.to_be_bytes()),
Datum::U32(v) => println!(".halfword i{}, as hex {:02X?}", v, v.to_be_bytes()),
Datum::U64(v) => println!(".word i{}, as hex {:02X?}", v, v.to_be_bytes()),
Datum::ByRef(bs) => {
print!(".bytes as hex ({bs:02X?}), len i{}, as ascii \"", bs.len());

for b in bs {
Expand All @@ -333,21 +338,6 @@ fn to_bytecode_mut(
}
println!("\"");
}
Datum::Slice(bs) => {
print!(".slice as hex ({bs:02X?}), len i{}, as ascii \"", bs.len());

for b in bs {
print!(
"{}",
if *b == b' ' || b.is_ascii_graphic() {
*b as char
} else {
'.'
}
);
}
println!("\"");
}
Datum::Collection(els) => {
println!(".collection");
for e in els {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,21 +607,14 @@ pub(crate) fn compile_jump(
if curr_offset > target_offset {
let delta = curr_offset - target_offset - 1;
return if far {
let data_id = data_section.insert_data_value(Entry::new_word(
delta + 1, // +1 since the load instruction must be skipped as well
EntryName::NonConfigurable,
None,
));

vec![
RealizedOp {
opcode: AllocatedInstruction::LoadDataId(
AllocatedRegister::Constant(ConstantRegister::Scratch),
data_id,
),
owning_span: owning_span.clone(),
comment: "load far jump target address".into(),
},
compile_load_integer_constant(
data_section,
AllocatedRegister::Constant(ConstantRegister::Scratch),
delta + 1, // +1 since the load instruction must be skipped as well
"load far jump target address".into(),
owning_span.clone(),
),
RealizedOp {
opcode: if let Some(cond_nz) = condition_nonzero {
AllocatedInstruction::JNZB(
Expand Down Expand Up @@ -662,21 +655,14 @@ pub(crate) fn compile_jump(
let delta = target_offset - curr_offset - 1;

if far {
let data_id = data_section.insert_data_value(Entry::new_word(
delta - 1,
EntryName::NonConfigurable,
None,
));

vec![
RealizedOp {
opcode: AllocatedInstruction::LoadDataId(
AllocatedRegister::Constant(ConstantRegister::Scratch),
data_id,
),
owning_span: owning_span.clone(),
comment: "load far jump target address".into(),
},
compile_load_integer_constant(
data_section,
AllocatedRegister::Constant(ConstantRegister::Scratch),
delta - 1,
"load far jump target address".into(),
owning_span.clone(),
),
RealizedOp {
opcode: if let Some(cond_nz) = condition_nonzero {
AllocatedInstruction::JNZF(
Expand Down Expand Up @@ -746,54 +732,14 @@ pub(crate) fn compile_call_inner(
// with the PC register. The overflow cannot occur since programs cannot be 2**60 bytes large.
let delta_instr = (delta - 1) * (Instruction::SIZE as u64);

// Attempt MOVI-based approach, that has larger immediate size but doesn't require data section.
if let Ok(imm) = VirtualImmediate18::new(delta_instr, Span::dummy()) {
return vec![
RealizedOp {
opcode: AllocatedInstruction::MOVI(
AllocatedRegister::Constant(ConstantRegister::Scratch),
imm,
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
RealizedOp {
opcode: AllocatedInstruction::ADD(
AllocatedRegister::Constant(ConstantRegister::Scratch),
AllocatedRegister::Constant(ConstantRegister::ProgramCounter),
AllocatedRegister::Constant(ConstantRegister::Scratch),
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
RealizedOp {
opcode: AllocatedInstruction::JAL(
AllocatedRegister::Constant(ConstantRegister::CallReturnAddress),
AllocatedRegister::Constant(ConstantRegister::Scratch),
VirtualImmediate12::new_unchecked(0, "unreachable()"),
),
owning_span,
comment,
},
];
}

// if the offset is too large for MOVI, use data section to store the full offset.
let data_id = data_section.insert_data_value(Entry::new_word(
delta_instr,
EntryName::NonConfigurable,
None,
));

return vec![
RealizedOp {
opcode: AllocatedInstruction::LoadDataId(
AllocatedRegister::Constant(ConstantRegister::Scratch),
data_id,
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
compile_load_integer_constant(
data_section,
AllocatedRegister::Constant(ConstantRegister::Scratch),
delta_instr,
"load call target address".into(),
owning_span.clone(),
),
RealizedOp {
opcode: AllocatedInstruction::ADD(
AllocatedRegister::Constant(ConstantRegister::Scratch),
Expand Down Expand Up @@ -853,54 +799,14 @@ pub(crate) fn compile_call_inner(
// with the PC register. The overflow cannot occur since programs cannot be 2**60 bytes large.
let delta_instr = (delta + 1) * (Instruction::SIZE as u64);

// Attempt MOVI-based approach.
if let Ok(imm) = VirtualImmediate18::new(delta_instr, Span::dummy()) {
return vec![
RealizedOp {
opcode: AllocatedInstruction::MOVI(
AllocatedRegister::Constant(ConstantRegister::Scratch),
imm,
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
RealizedOp {
opcode: AllocatedInstruction::SUB(
AllocatedRegister::Constant(ConstantRegister::Scratch),
AllocatedRegister::Constant(ConstantRegister::ProgramCounter),
AllocatedRegister::Constant(ConstantRegister::Scratch),
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
RealizedOp {
opcode: AllocatedInstruction::JAL(
AllocatedRegister::Constant(ConstantRegister::CallReturnAddress),
AllocatedRegister::Constant(ConstantRegister::Scratch),
VirtualImmediate12::new_unchecked(0, "unreachable()"),
),
owning_span,
comment,
},
];
}

// And lastly, fall back to the data section backed approach.
let data_id = data_section.insert_data_value(Entry::new_word(
delta_instr,
EntryName::NonConfigurable,
None,
));

vec![
RealizedOp {
opcode: AllocatedInstruction::LoadDataId(
AllocatedRegister::Constant(ConstantRegister::Scratch),
data_id,
),
owning_span: owning_span.clone(),
comment: "load call target address".into(),
},
compile_load_integer_constant(
data_section,
AllocatedRegister::Constant(ConstantRegister::Scratch),
delta_instr,
"load call target address".into(),
owning_span.clone(),
),
RealizedOp {
opcode: AllocatedInstruction::SUB(
AllocatedRegister::Constant(ConstantRegister::Scratch),
Expand Down Expand Up @@ -948,3 +854,54 @@ pub(crate) fn compile_call(
}
res
}

/// Compiles loading of an integer constant into a register,
/// possibly using the data section if that's more efficient.
pub(crate) fn compile_load_integer_constant(
data_section: &mut DataSection,
register: AllocatedRegister,
value: u64,
comment: String,
owning_span: Option<Span>,
) -> RealizedOp {
// Attempt MOVI
if let Ok(imm) = VirtualImmediate18::new(value, Span::dummy()) {
return RealizedOp {
opcode: AllocatedInstruction::MOVI(register, imm),
owning_span,
comment,
};
}

// Attempt various tricks for known constants
if value == u64::MAX {
return RealizedOp {
opcode: AllocatedInstruction::NOT(
register,
AllocatedRegister::Constant(ConstantRegister::Zero),
),
owning_span,
comment,
};
}
if value == u64::MAX - 1 {
return RealizedOp {
opcode: AllocatedInstruction::NOT(
register,
AllocatedRegister::Constant(ConstantRegister::One),
),
owning_span,
comment,
};
}

// Fall back to the data section backed approach.
let data_id =
data_section.insert_data_value(Entry::new_min_int(value, EntryName::NonConfigurable, None));

RealizedOp {
opcode: AllocatedInstruction::LoadDataId(register, data_id),
owning_span,
comment,
}
}
Loading
Loading