Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Jan 29, 2021
1 parent 163b1a4 commit 515c565
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 10 deletions.
2 changes: 2 additions & 0 deletions compiler/src/yul/operations/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ pub fn encode_size<T: AbiEncoding>(types: Vec<T>, vals: Vec<yul::Expression>) ->
for (typ, val) in typed_vals {
match typ.abi_type() {
AbiType::Uint { .. } => static_size += 32,
AbiType::Tuple => unimplemented!("encode_size for tuple"),
AbiType::Array { inner, size } => {
let inner_size = match *inner {
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => padded_size,
AbiType::Array { .. } => unimplemented!(),
AbiType::Tuple => unimplemented!("Encode size for tuple in array")
};
match size {
AbiArraySize::Static { size } => {
Expand Down
14 changes: 10 additions & 4 deletions compiler/src/yul/runtime/functions/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ fn encode<T: AbiEncoding>(types: Vec<T>) -> yul::Statement {
encode_uint(dyn_offset)
}
AbiType::Uint { .. } => encode_uint(param),
AbiType::Tuple => unimplemented!("encode for Tuple"),
})
.collect::<Vec<_>>();

Expand Down Expand Up @@ -118,6 +119,7 @@ fn decode<T: AbiEncoding>(typ: T, location: AbiDecodeLocation) -> yul::Statement
AbiArraySize::Static { size } => decode_static_array(*inner, size, location),
AbiArraySize::Dynamic => decode_dyn_array(*inner, location),
},
AbiType::Tuple => unimplemented!("decode for Tuple")
};

function_definition! {
Expand Down Expand Up @@ -178,7 +180,8 @@ fn dyn_array_data_size(val: yul::Expression, inner: AbiType) -> yul::Expression
let array_size = expression! { mload([val]) };
let elements_size = expression! { mul([array_size], [inner_padded_size]) };
expression! { add(32, (ceil32([elements_size]))) }
}
},
AbiType::Tuple => unimplemented!(),
}
}

Expand Down Expand Up @@ -233,7 +236,8 @@ fn encode_array(
} else {
statement! { abi_unpack([val], [array_size], [inner_data_size]) }
}
}
},
AbiType::Tuple => unimplemented!("encoding of tuples in arrays")
}
}

Expand Down Expand Up @@ -281,7 +285,8 @@ fn decode_dyn_array(inner: AbiType, location: AbiDecodeLocation) -> yul::Express
} else {
unimplemented!("packing of dynamically sized arrays")
}
}
},
AbiType::Tuple => unimplemented!("Decoding of tuples in arrays")
}
}

Expand Down Expand Up @@ -327,7 +332,8 @@ fn decode_static_array(
}
}
}
}
},
AbiType::Tuple => unimplemented!("Decoding of tuples in arrays")
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/src/yul/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ pub fn abi_head_offsets<T: AbiEncoding>(types: &[T]) -> (Vec<usize>, usize) {
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => ceil_32(padded_size * size),
AbiType::Tuple => unimplemented!(),
},
AbiType::Uint {
size: AbiUintSize { padded_size, .. },
} => padded_size,
AbiType::Tuple => unimplemented!(),
};
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/tests/fixtures/structs.fe
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ contract Foo:
citizen: u256

pub def bar() -> u256:
return 42
# Consider requiring KW syntax to instantiate structs
self.building = House(1, 1)
return 10
174 changes: 174 additions & 0 deletions output/Foo/Foo_ir.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
object \"Contract\" {
code {
let size := datasize(\"runtime\") datacopy(0, dataoffset(\"runtime\"), size) return(0, size)
}
object \"runtime\" {
code {
function $$bar() -> return_val {
mcopys(1, 0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d, 64) {
return_val := 10 leave
}

}
function avail() -> ptr {
ptr := mload(0x00) if eq(ptr, 0x00) {
ptr := 0x20
}

}
function alloc(size) -> ptr {
ptr := mload(0x00) if eq(ptr, 0x00) {
ptr := 0x20
}
mstore(0x00, add(ptr, size))
}
function alloc_mstoren(val, size) -> ptr {
ptr := alloc(size) mstoren(ptr, val, size)
}
function free(ptr) {
mstore(0x00, ptr)
}
function ccopym(cptr, size) -> mptr {
mptr := alloc(size) calldatacopy(mptr, cptr, size)
}
function load_data_string(code_ptr, size) -> mptr {
mptr := alloc(32) mstore(mptr, size) let content_ptr := alloc(size) datacopy(content_ptr, code_ptr, size)
}
function mcopys(mptr, sptr, size) {
let offset := 0 for {

}
lt(add(offset, 32), size) {

}
{
let _mptr := add(mptr, offset) let _sptr := add(sptr, offset) sstore(_sptr, mload(_mptr)) offset := add(offset, 32)
}
let rem := sub(size, offset) if gt(rem, 0) {
let _mptr := add(mptr, offset) let _sptr := add(sptr, offset) sstoren(_sptr, mloadn(_mptr, rem), rem)
}

}
function scopym(sptr, size) -> mptr {
mptr := alloc(size) let offset := 0 for {

}
lt(add(offset, 32), size) {

}
{
let _mptr := add(mptr, offset) let _sptr := add(sptr, offset) mstore(_mptr, sload(_sptr)) offset := add(offset, 32)
}
let rem := sub(size, offset) if gt(rem, 0) {
let _mptr := add(mptr, offset) let _sptr := add(sptr, offset) mstoren(_mptr, sloadn(_sptr, rem), rem)
}

}
function mcopym(ptr1, size) -> ptr2 {
ptr2 := alloc(size) let offset := 0 for {

}
lt(add(offset, 32), size) {

}
{
let _ptr1 := add(ptr1, offset) let _ptr2 := add(ptr2, offset) mstore(_ptr2, mload(_ptr1)) offset := add(offset, 32)
}
let rem := sub(size, offset) if gt(rem, 0) {
let _ptr1 := add(ptr1, offset) let _ptr2 := add(ptr2, offset) mstoren(_ptr2, mloadn(_ptr1, rem), rem)
}

}
function scopys(ptr1, ptr2, size) {
let offset := 0 for {

}
lt(add(offset, 32), size) {

}
{
let _ptr1 := add(ptr1, offset) let _ptr2 := add(ptr2, offset) sstore(_ptr2, sload(_ptr1)) offset := add(offset, 32)
}
let rem := sub(size, offset) if gt(rem, 0) {
let _ptr1 := add(ptr1, offset) let _ptr2 := add(ptr2, offset) sstoren(_ptr2, sloadn(_ptr1, rem), rem)
}

}
function mloadn(ptr, size) -> val {
val := shr(sub(256, mul(8, size)), mload(ptr))
}
function sloadn(ptr, size) -> val {
val := shr(sub(256, mul(8, size)), sload(ptr))
}
function cloadn(ptr, size) -> val {
val := shr(sub(256, mul(8, size)), calldataload(ptr))
}
function mstoren(ptr, val, size) {
let size_bits := mul(8, size) let left := shl(sub(256, size_bits), val) let right := shr(size_bits, mload(add(ptr, size))) mstore(ptr, or(left, right))
}
function sstoren(ptr, val, size) {
let size_bits := mul(8, size) let left := shl(sub(256, size_bits), val) let right := shr(size_bits, sload(add(ptr, size))) sstore(ptr, or(left, right))
}
function dualkeccak256(a, b) -> return_val {
let ptr := avail() mstore(ptr, a) mstore(add(ptr, 32), b) return_val := keccak256(ptr, 64)
}
function ceil32(n) -> return_val {
return_val := mul(div(add(n, 31), 32), 32)
}
function ternary(test, if_expr, else_expr) -> result {
switch test case 1 {
result := if_expr
}
case 0 {
result := else_expr
}

}
function abi_unpack(mptr, array_size, inner_data_size) {
for {
let i := 0
}
lt(i, array_size) {
i := add(i, 1)
}
{
let val_ptr := add(mptr, mul(i, inner_data_size)) let val := mloadn(val_ptr, inner_data_size) pop(alloc_mstoren(val, 32))
}

}
function abi_pack_calldata(mptr, array_size, inner_data_size) -> packed_ptr {
packed_ptr := avail() for {
let i := 0
}
lt(i, array_size) {
i := add(i, 1)
}
{
let val_ptr := add(mptr, mul(i, 32)) let val := calldataload(val_ptr) pop(alloc_mstoren(val, inner_data_size))
}

}
function abi_pack_mem(mptr, array_size, inner_data_size) -> packed_ptr {
packed_ptr := avail() for {
let i := 0
}
lt(i, array_size) {
i := add(i, 1)
}
{
let val_ptr := add(mptr, mul(i, 32)) let val := mload(val_ptr) pop(alloc_mstoren(val, inner_data_size))
}

}
function abi_encode_uint256(val_0) -> ptr {
ptr := avail() pop(alloc_mstoren(val_0, 32))
}
switch cloadn(0, 4) case 0xfebb0f7e {
let raw_return := $$bar() return(abi_encode_uint256(raw_return), add(32, 0))
}

}

}

}
2 changes: 2 additions & 0 deletions semantics/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub enum AbiType {
},
/// All elements are encoded as a uint or set of uints.
Uint { size: AbiUintSize },
Tuple,

}

/// Data can be decoded from memory or calldata.
Expand Down
49 changes: 44 additions & 5 deletions semantics/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::namespace::types::{
FeString,
FixedSize,
Integer,
Struct,
Type,
U256,
};
Expand Down Expand Up @@ -403,12 +404,37 @@ fn expr_call(
unreachable!()
}

fn expr_call_struct_constructor(
scope: Shared<BlockScope>,
context: Shared<Context>,
typ: Struct,
args: &Spanned<Vec<Spanned<fe::CallArg>>>,
) -> Result<ExpressionAttributes, SemanticError> {

let argument_attributes = expr_call_args(Rc::clone(&scope), Rc::clone(&context), args)?;

// TODO: implement From<Struct> for Type
let struct_types: Vec<Type> = typ.fields.values().map(|val| Type::Base(val.clone())).collect();

if struct_types != expression_attributes_to_types(argument_attributes)
{
return Err(SemanticError::type_error());
}

Ok(ExpressionAttributes::new(Type::Struct(typ), Location::Memory))
}

fn expr_call_type_constructor(
scope: Shared<BlockScope>,
context: Shared<Context>,
typ: Type,
args: &Spanned<Vec<Spanned<fe::CallArg>>>,
) -> Result<ExpressionAttributes, SemanticError> {

if let Type::Struct(val) = typ {
return expr_call_struct_constructor(scope, context, val, args)
}

if args.node.len() != 1 {
return Err(SemanticError::wrong_number_of_params());
}
Expand Down Expand Up @@ -472,6 +498,16 @@ fn validate_str_literal_fits_type(
Err(SemanticError::type_error())
}

fn expr_call_args(scope: Shared<BlockScope>,
context: Shared<Context>,
args: &Spanned<Vec<Spanned<fe::CallArg>>>) -> Result<Vec<ExpressionAttributes>, SemanticError> {
args
.node
.iter()
.map(|arg| call_arg(Rc::clone(&scope), Rc::clone(&context), arg))
.collect::<Result<Vec<_>, _>>()
}

fn expr_call_self_attribute(
scope: Shared<BlockScope>,
context: Shared<Context>,
Expand All @@ -489,11 +525,7 @@ fn expr_call_self_attribute(
.borrow()
.function_def(func_name)
{
let argument_attributes = args
.node
.iter()
.map(|arg| call_arg(Rc::clone(&scope), Rc::clone(&context), arg))
.collect::<Result<Vec<_>, _>>()?;
let argument_attributes = expr_call_args(Rc::clone(&scope), Rc::clone(&context), args)?;

if fixed_sizes_to_types(param_types) != expression_attributes_to_types(argument_attributes)
{
Expand Down Expand Up @@ -602,6 +634,13 @@ fn expr_name_call_type(
TryFrom::try_from(value).map_err(|_| SemanticError::undefined_value())?,
),
}),
value => {
let custom_type = _scope.borrow().module_scope().borrow().type_defs.get(value).ok_or(SemanticError::undefined_value())?.clone();

Ok(CallType::TypeConstructor {
typ: custom_type
})
},
_ => Err(SemanticError::undefined_value()),
}
}
Expand Down

0 comments on commit 515c565

Please sign in to comment.