Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
40 changes: 28 additions & 12 deletions sway-core/src/asm_generation/finalized_asm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::instruction_set::InstructionSet;
use super::{
fuel::{checks, data_section::DataSection},
fuel::{checks, compiler_constants::TWELVE_BITS, data_section::DataSection},
ProgramABI, ProgramKind,
};
use crate::asm_generation::fuel::data_section::{Datum, Entry, EntryName};
Expand Down Expand Up @@ -120,14 +120,28 @@ fn to_bytecode_mut(
source_engine: &SourceEngine,
build_config: &BuildConfig,
) -> CompiledBytecode {
fn op_size_in_bytes(data_section: &DataSection, item: &AllocatedOp) -> u64 {
// Snapshot before pointer pre-insertion mutates the data section.
let base_data_section_size = data_section.size_in_bytes() as u64;

fn op_size_in_bytes(
data_section: &DataSection,
base_data_section_size: u64,
item: &AllocatedOp,
) -> u64 {
match &item.opcode {
AllocatedInstruction::LoadDataId(_reg, data_label)
if !data_section
AllocatedInstruction::LoadDataId(_reg, data_label) => {
let has_copy_type = data_section
.has_copy_type(data_label)
.expect("data label references non existent data -- internal error") =>
{
8
.expect("data label references non existent data -- internal error");
if has_copy_type {
let offset_bytes = data_section.data_id_to_offset(data_label) as u64;
let is_byte = data_section.is_byte(data_label).unwrap();
let imm_value = if is_byte { offset_bytes } else { offset_bytes / 8 };
if imm_value > TWELVE_BITS { 12 } else { 4 }
Comment thread
Dnreikronos marked this conversation as resolved.
} else {
let pointer_offset_words = base_data_section_size / 8;
if pointer_offset_words > TWELVE_BITS { 16 } else { 8 }
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
}
Comment thread
Dnreikronos marked this conversation as resolved.
}
AllocatedInstruction::AddrDataId(_, _data_id) => 8,
AllocatedInstruction::ConfigurablesOffsetPlaceholder => 8,
Expand All @@ -140,9 +154,9 @@ fn to_bytecode_mut(

// Some instructions may be omitted or expanded into multiple instructions, so we compute,
// using `op_size_in_bytes`, exactly how many ops will be generated to calculate the offset.
let mut offset_to_data_section_in_bytes = ops
.iter()
.fold(0, |acc, item| acc + op_size_in_bytes(data_section, item));
let mut offset_to_data_section_in_bytes = ops.iter().fold(0, |acc, item| {
acc + op_size_in_bytes(data_section, base_data_section_size, item)
});

// A noop is inserted in ASM generation if required, to word-align the data section.
let mut ops_padded = Vec::new();
Expand Down Expand Up @@ -180,7 +194,8 @@ fn to_bytecode_mut(
}
_ => (),
}
offset_from_instr_start += op_size_in_bytes(data_section, op);
offset_from_instr_start +=
Comment thread
cursor[bot] marked this conversation as resolved.
op_size_in_bytes(data_section, base_data_section_size, op);
}

let mut bytecode = Vec::with_capacity(offset_to_data_section_in_bytes as usize);
Expand All @@ -205,7 +220,8 @@ fn to_bytecode_mut(
offset_from_instr_start,
data_section,
);
offset_from_instr_start += op_size_in_bytes(data_section, op);
offset_from_instr_start +=
op_size_in_bytes(data_section, base_data_section_size, op);

match fuel_op {
FuelAsmData::DatasectionOffset(data) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,24 +435,28 @@ impl AllocatedAbstractInstructionSet {
}
}

// Actual size of an instruction.
// Note that this return incorrect values for far jumps, they must be handled separately.
// The return value is in concrete instructions, i.e. units of 4 bytes.
// Actual size of an instruction (units of 4 bytes).
// Incorrect for far jumps — those are handled separately.
// Must be called before pointer pre-insertion in to_bytecode_mut;
// non-copy size estimates depend on data_section.size_in_bytes() being pointer-free.
fn instruction_size_not_far_jump(op: &AllocatedAbstractOp, data_section: &DataSection) -> u64 {
use ControlFlowOp::*;
match op.opcode {
Either::Right(Label(_)) => 0,

// A special case for LoadDataId which may be 1 or 2 ops, depending on the source size.
Either::Left(AllocatedInstruction::LoadDataId(_, ref data_id)) => {
let has_copy_type = data_section.has_copy_type(data_id).expect(
"Internal miscalculation in data section -- \
data id did not match up to any actual data",
);
if has_copy_type {
1
let offset_bytes = data_section.data_id_to_offset(data_id) as u64;
let is_byte = data_section.is_byte(data_id).unwrap();
let imm_value = if is_byte { offset_bytes } else { offset_bytes / 8 };
if imm_value > consts::TWELVE_BITS { 3 } else { 1 }
} else {
2
let pointer_offset_words = data_section.size_in_bytes() as u64 / 8;
if pointer_offset_words > consts::TWELVE_BITS { 4 } else { 2 }
}
}

Expand Down
4 changes: 4 additions & 0 deletions sway-core/src/asm_generation/fuel/data_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ impl DataSection {
})
}

pub(crate) fn size_in_bytes(&self) -> usize {
self.absolute_idx_to_offset(self.num_entries())
}

pub(crate) fn serialize_to_bytes(&self) -> Vec<u8> {
// not the exact right capacity but serves as a lower bound
let mut buf = Vec::with_capacity(self.num_entries());
Expand Down
79 changes: 52 additions & 27 deletions sway-core/src/asm_lang/allocated_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ use super::*;
use crate::{
asm_generation::fuel::{
compiler_constants::{
DATA_SECTION_REGISTER, LOWER_ALLOCATABLE_REGISTER, UPPER_ALLOCATABLE_REGISTER,
DATA_SECTION_REGISTER, EIGHTEEN_BITS, LOWER_ALLOCATABLE_REGISTER,
UPPER_ALLOCATABLE_REGISTER,
},
data_section::{DataId, DataSection},
},
fuel_prelude::fuel_asm::{self, op},
};
use fuel_vm::fuel_asm::{
op::{ADD, MOVI},
Imm18,
Imm12, Imm18,
};
use std::fmt::{self, Write};
use sway_types::span::Span;
Expand Down Expand Up @@ -947,6 +948,11 @@ fn addr_of(
data_section: &DataSection,
) -> Vec<fuel_asm::Instruction> {
let offset_bytes = data_section.data_id_to_offset(data_id) as u64;
assert!(
offset_bytes <= EIGHTEEN_BITS,
"Data section offset {offset_bytes} bytes exceeds 18-bit MOVI immediate limit. \
Data section too large."
);
vec![
fuel_asm::Instruction::MOVI(MOVI::new(
dest.to_reg_id(),
Expand Down Expand Up @@ -990,18 +996,6 @@ fn realize_load(
);
let offset_words = offset_bytes / 8;

let imm = VirtualImmediate12::try_new(
if is_byte { offset_bytes } else { offset_words },
Span::new(" ".into(), 0, 0, None).unwrap(),
);
let offset = match imm {
Ok(value) => value,
Err(_) => panic!(
"Unable to offset into the data section more than 2^12 bits. \
Unsupported data section length: {offset_words} words."
),
};

if !has_copy_type {
// load the pointer itself into the register. `offset_to_data_section` is in bytes.
// The -4 is because $pc is added in the *next* instruction.
Expand Down Expand Up @@ -1032,19 +1026,50 @@ fn realize_load(
.into(),
);
buf
} else if is_byte {
vec![fuel_asm::op::LB::new(
dest.to_reg_id(),
fuel_asm::RegId::new(DATA_SECTION_REGISTER),
offset.value().into(),
)
.into()]
} else {
vec![fuel_asm::op::LW::new(
dest.to_reg_id(),
fuel_asm::RegId::new(DATA_SECTION_REGISTER),
offset.value().into(),
)
.into()]
let imm_value = if is_byte { offset_bytes } else { offset_words };
let imm = VirtualImmediate12::try_new(imm_value, Span::dummy());

if let Ok(offset) = imm {
if is_byte {
vec![fuel_asm::op::LB::new(
dest.to_reg_id(),
fuel_asm::RegId::new(DATA_SECTION_REGISTER),
offset.value().into(),
)
.into()]
} else {
vec![fuel_asm::op::LW::new(
dest.to_reg_id(),
fuel_asm::RegId::new(DATA_SECTION_REGISTER),
offset.value().into(),
)
.into()]
}
} else {
assert!(
offset_bytes <= EIGHTEEN_BITS,
"Data section offset {offset_bytes} bytes exceeds 18-bit MOVI immediate limit. \
Data section too large ({offset_words} words)."
);
vec![
fuel_asm::Instruction::MOVI(MOVI::new(
dest.to_reg_id(),
Imm18::new(offset_bytes.try_into().unwrap()),
)),
fuel_asm::Instruction::ADD(ADD::new(
dest.to_reg_id(),
dest.to_reg_id(),
fuel_asm::RegId::new(DATA_SECTION_REGISTER),
)),
if is_byte {
fuel_asm::op::LB::new(dest.to_reg_id(), dest.to_reg_id(), Imm12::new(0))
.into()
} else {
fuel_asm::op::LW::new(dest.to_reg_id(), dest.to_reg_id(), Imm12::new(0))
.into()
},
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = "large_data_section"
source = "member"
dependencies = ["std"]

[[package]]
name = "std"
source = "path+from-root-E3854248C161EE9C"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
name = "large_data_section"

[dependencies]
std = { path = "../../../../../../../sway-lib-std" }
Loading