Skip to content

Commit

Permalink
merge from master
Browse files Browse the repository at this point in the history
  • Loading branch information
sezna committed Nov 5, 2021
2 parents af5b1f6 + 4a3855e commit f67fd7b
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 9 deletions.
55 changes: 48 additions & 7 deletions core_lang/src/asm_generation/expression/structs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! This module contains the logic for struct layout in memory and instantiation.
use crate::{
asm_generation::{convert_expression_to_asm, AsmNamespace, RegisterSequencer},
asm_lang::{ConstantRegister, Op, VirtualImmediate12, VirtualImmediate24, VirtualRegister},
asm_lang::{
ConstantRegister, Op, VirtualImmediate12, VirtualImmediate24, VirtualOp, VirtualRegister,
},
error::*,
semantic_analysis::ast_node::TypedStructExpressionField,
type_engine::{look_up_type_id, resolve_type, TypeId},
Expand Down Expand Up @@ -219,6 +221,7 @@ pub(crate) fn convert_struct_expression_to_asm<'sc>(
}

// step 3
// `offset` is in words
let mut offset = 0;
for TypedStructExpressionField { name, value } in fields {
// evaluate the expression
Expand All @@ -243,12 +246,50 @@ pub(crate) fn convert_struct_expression_to_asm<'sc>(
errors
);
asm_buf.append(&mut field_instantiation);
asm_buf.push(Op::write_register_to_memory(
struct_beginning_pointer.clone(),
return_register,
VirtualImmediate12::new_unchecked(offset, "the whole struct is less than 12 bits so every individual field should be as well."),
name.span.clone(),
));
// if the value is less than one word in size, we write it via the SW opcode.
// Otherwise, use MCPI to copy the contiguous memory
let type_size = match look_up_type_id(value.return_type).stack_size_of(&name.span) {
Ok(o) => o,
Err(e) => {
errors.push(e.into());
return err(warnings, errors);
}
};
if type_size > 1 {
// copy the struct beginning pointer and add the offset to it
let address_to_write_to = register_sequencer.next();
// load the address via ADDI
asm_buf.push(Op {
opcode: either::Either::Left(VirtualOp::ADDI(
address_to_write_to.clone(),
struct_beginning_pointer.clone(),
VirtualImmediate12::new_unchecked(offset * 8, "struct size is too large"),
)),
owning_span: Some(value.span.clone()),
comment: format!(
"prep struct field reg (size {} for field {})",
type_size, name.primary_name
),
});

// copy the data
asm_buf.push(Op {
opcode: either::Either::Left(VirtualOp::MCPI(
address_to_write_to,
return_register,
VirtualImmediate12::new_unchecked(type_size * 8, "struct cannot be this big"),
)),
owning_span: Some(value.span.clone()),
comment: format!("cp type size {} for field {}", type_size, name.primary_name),
});
} else {
asm_buf.push(Op::write_register_to_memory(
struct_beginning_pointer.clone(),
return_register,
VirtualImmediate12::new_unchecked(offset, "the whole struct is less than 12 bits so every individual field should be as well."),
name.span.clone(),
));
}
// TODO: if the struct needs multiple allocations, this offset could exceed the size of the
// immediate value allowed in SW. In that case, we need to shift `struct_beginning_pointer`
// to the max offset and start the offset back from 0. This is only for structs in excess
Expand Down
5 changes: 3 additions & 2 deletions test/src/e2e_vm_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ pub fn run(filter_regex: Option<regex::Regex>) {
(
"retd_struct",
ProgramState::ReturnData(Bytes32::from([
139, 216, 67, 1, 172, 74, 189, 183, 82, 11, 99, 241, 23, 111, 195, 89, 208, 127,
16, 95, 247, 254, 168, 151, 227, 225, 199, 179, 50, 80, 63, 175,
251, 57, 24, 241, 63, 94, 17, 102, 252, 182, 8, 110, 140, 105, 102, 105, 138, 202,
155, 39, 97, 32, 94, 129, 141, 144, 190, 142, 33, 32, 33, 75,
])),
),
("op_precedence", ProgramState::Return(0)),
Expand All @@ -54,6 +54,7 @@ pub fn run(filter_regex: Option<regex::Regex>) {
("const_decl_in_library", ProgramState::Return(1)), // true
("aliased_imports", ProgramState::Return(42)),
("empty_method_initializer", ProgramState::Return(1)), // true
("b512_struct_alignment", ProgramState::Return(1)), // true
];

project_names.into_iter().for_each(|(name, res)| {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[project]
author = "Alexander Hansen"
license = "MIT"
name = "b512_panic_test"
entry = "main.sw"

[dependencies]
std = { path = "../../../../../stdlib" }

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
script;

// Stores two b256s in contiguous memory.
// Guaranteed to be contiguous for things like ECR.
struct B512 {
hi: b256,
lo: b256,
}

// temp
pub fn build_from_b256s(hi: b256, lo: b256) -> B512 {
let hi = asm(r1: hi, rhi) {
move rhi sp; // move stack pointer to rhi
cfei i32; // extend call frame by 32 bytes to allocate more memory. now $rhi is pointing to blank, uninitialized (but allocated) memory
// addi r5 zero i32;
mcpi rhi r1 i32;
rhi: b256
};

let lo = asm(r1: lo, rlo) {
move rlo sp;
cfei i32;
// now $rlo is pointing to blank memory that we can use
mcpi rlo r1 i32;
rlo: b256
};

B512 {
hi: hi,
lo: lo
}
}

fn main() -> bool {
let hi_bits: b256 = 0x7777777777777777777777777777777777777777777777777777777777777777;
let lo_bits: b256 = 0x5555555555555555555555555555555555555555555555555555555555555555;

let b: B512 = build_from_b256s(hi_bits, lo_bits);

b.lo == lo_bits && b.hi == hi_bits
}

0 comments on commit f67fd7b

Please # to comment.