Skip to content

WIP: data section packing #7086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
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
6 changes: 2 additions & 4 deletions sway-core/src/asm_generation/evm/evm_asm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, sync::Arc};

use crate::{
asm_generation::{
asm_builder::AsmBuilder, from_ir::StateAccessType, fuel::data_section::DataSection,
asm_builder::AsmBuilder, from_ir::StateAccessType, fuel::data_section::{DataSection, FinalDataSection, PackedDataSection},
instruction_set::InstructionSet, FinalizedAsm, ProgramABI, ProgramKind,
},
asm_lang::Label,
Expand Down Expand Up @@ -729,9 +729,7 @@ struct EvmFinalProgram {
impl EvmFinalProgram {
fn finalize(self) -> FinalizedAsm {
FinalizedAsm {
data_section: DataSection {
..Default::default()
},
data_section: FinalDataSection::default(),
program_section: InstructionSet::Evm { ops: self.ops },
program_kind: ProgramKind::Script,
entries: vec![],
Expand Down
49 changes: 10 additions & 39 deletions sway-core/src/asm_generation/finalized_asm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::fuel::data_section::{FinalDataSection, PackedDataSection};
use super::instruction_set::InstructionSet;
use super::{
fuel::{checks, data_section::DataSection},
Expand Down Expand Up @@ -40,7 +41,7 @@ pub struct DataSectionInformation {
/// applied to it
#[derive(Clone)]
pub struct FinalizedAsm {
pub data_section: DataSection,
pub data_section: FinalDataSection,
pub program_section: InstructionSet,
pub program_kind: ProgramKind,
pub entries: Vec<FinalizedEntry>,
Expand Down Expand Up @@ -69,7 +70,7 @@ pub struct CompiledBytecode {

impl FinalizedAsm {
pub(crate) fn to_bytecode_mut(
&mut self,
self,
handler: &Handler,
source_map: &mut SourceMap,
source_engine: &SourceEngine,
Expand Down Expand Up @@ -115,7 +116,7 @@ impl fmt::Display for FinalizedAsm {

fn to_bytecode_mut(
ops: &[AllocatedOp],
data_section: &mut DataSection,
data_section: &mut PackedDataSection,
source_map: &mut SourceMap,
source_engine: &SourceEngine,
build_config: &BuildConfig,
Expand Down Expand Up @@ -314,11 +315,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 +334,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 All @@ -368,22 +354,7 @@ fn to_bytecode_mut(
assert_eq!(half_word_ix * 4, offset_to_data_section_in_bytes as usize);
assert_eq!(bytecode.len(), offset_to_data_section_in_bytes as usize);

let num_nonconfigurables = data_section.non_configurables.len();
let named_data_section_entries_offsets = data_section
.configurables
.iter()
.enumerate()
.map(|(id, entry)| {
let EntryName::Configurable(name) = &entry.name else {
panic!("Non-configurable in configurables part of datasection");
};
(
name.clone(),
offset_to_data_section_in_bytes
+ data_section.absolute_idx_to_offset(id + num_nonconfigurables) as u64,
)
})
.collect::<BTreeMap<String, u64>>();
let named_data_section_entries_offsets = data_section.named_offsets();

let mut data_section = data_section.serialize_to_bytes();
bytecode.append(&mut data_section);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
use super::{
abstract_instruction_set::RealizedAbstractInstructionSet,
compiler_constants as consts,
data_section::{DataSection, Entry},
data_section::{DataSection, Entry, PackedDataSection},
};

use fuel_vm::fuel_asm::Imm12;
Expand Down Expand Up @@ -199,7 +199,7 @@ impl AllocatedAbstractInstructionSet {
/// labels in the organizational ops
pub(crate) fn realize_labels(
mut self,
data_section: &mut DataSection,
data_section: &mut PackedDataSection,
) -> Result<(RealizedAbstractInstructionSet, LabeledBlocks), crate::CompileError> {
let label_offsets = self.resolve_labels(data_section, 0)?;
let mut curr_offset = 0;
Expand Down Expand Up @@ -377,7 +377,6 @@ impl AllocatedAbstractInstructionSet {
let data_id = data_section.insert_data_value(Entry::new_word(
offset,
EntryName::NonConfigurable,
None,
));
realized_ops.push(RealizedOp {
opcode: AllocatedOpcode::LoadDataId(r1, data_id),
Expand All @@ -402,7 +401,7 @@ impl AllocatedAbstractInstructionSet {

fn resolve_labels(
&mut self,
data_section: &mut DataSection,
data_section: &mut PackedDataSection,
iter_count: usize,
) -> Result<LabeledBlocks, crate::CompileError> {
// Iteratively resolve the label offsets.
Expand All @@ -428,7 +427,7 @@ impl AllocatedAbstractInstructionSet {
));
}

let (remap_needed, label_offsets) = self.map_label_offsets(data_section);
let (remap_needed, label_offsets) = self.map_label_offsets();

if !remap_needed || !self.rewrite_far_jumps(&label_offsets, data_section) {
// We didn't need to make any changes to the ops, so the labels are now correct.
Expand All @@ -439,8 +438,57 @@ impl AllocatedAbstractInstructionSet {
}
}

// Maximum amount of concrete (4 byte) opcodes that can be emitted in a single instruction.
fn max_instruction_size(op: &AllocatedAbstractOp) -> u64 {
use ControlFlowOp::*;
match op.opcode {
Either::Right(Label(_)) => 0,

// Data section referencing can take up to 2 instructions
Either::Left(AllocatedOpcode::LoadDataId(_, _) | AllocatedOpcode::AddrDataId(_, _))=> {
2
}

// cfei 0 and cfsi 0 are omitted from asm emission, don't count them for offsets
Either::Left(AllocatedOpcode::CFEI(ref op))
| Either::Left(AllocatedOpcode::CFSI(ref op))
if op.value() == 0 =>
{
0
}

// Another special case for the blob opcode, used for testing.
Either::Left(AllocatedOpcode::BLOB(ref count)) => count.value() as u64,

// These ops will end up being exactly one op, so the cur_offset goes up one.
Either::Right(Jump(..) | JumpIfNotZero(..) | Call(..) | LoadLabel(..))
| Either::Left(_) => 1,

// We use three instructions to save the absolute address for return.
// SUB r1 $pc $is
// SRLI r1 r1 2 / DIVI r1 r1 4
// ADDI $r1 $r1 offset
Either::Right(SaveRetAddr(..)) => 3,

Either::Right(Comment) => 0,

Either::Right(DataSectionOffsetPlaceholder) => {
// If the placeholder is 32 bits, this is 1. if 64, this should be 2. We use LW
// to load the data, which loads a whole word, so for now this is 2.
2
}

Either::Right(ConfigurablesOffsetPlaceholder) => 2,

Either::Right(PushAll(_)) | Either::Right(PopAll(_)) => unreachable!(
"fix me, pushall and popall don't really belong in control flow ops \
since they're not about control flow"
),
}
}

// Instruction size in units of 32b.
fn instruction_size(op: &AllocatedAbstractOp, data_section: &DataSection) -> u64 {
fn instruction_size(op: &AllocatedAbstractOp, data_section: &PackedDataSection) -> u64 {
use ControlFlowOp::*;
match op.opcode {
Either::Right(Label(_)) => 0,
Expand Down Expand Up @@ -504,7 +552,7 @@ impl AllocatedAbstractInstructionSet {
}
}

fn map_label_offsets(&self, data_section: &DataSection) -> (bool, LabeledBlocks) {
fn map_label_offsets(&self) -> (bool, LabeledBlocks) {
let mut labelled_blocks = LabeledBlocks::new();
let mut cur_offset = 0;
let mut cur_basic_block = None;
Expand Down Expand Up @@ -540,8 +588,9 @@ impl AllocatedAbstractInstructionSet {
jnz_labels.insert((cur_offset, lab));
}

// Update the offset.
cur_offset += Self::instruction_size(op, data_section);
// Update the maximum offset. We're pessimistic here, so if the all labels
// can still be placed this will definitely work.
cur_offset += Self::max_instruction_size(op);
}

// Don't forget the final block.
Expand Down Expand Up @@ -571,7 +620,7 @@ impl AllocatedAbstractInstructionSet {
fn rewrite_far_jumps(
&mut self,
label_offsets: &LabeledBlocks,
data_section: &DataSection,
data_section: &PackedDataSection,
) -> bool {
let min_ops = self.ops.len();
let mut modified = false;
Expand Down
Loading
Loading