Explorar o código

Refactor emit (#837)

Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel %!s(int64=3) %!d(string=hai) anos
pai
achega
33429c5aad
Modificáronse 9 ficheiros con 1205 adicións e 1172 borrados
  1. 1 1
      src/bin/solang.rs
  2. 1162 0
      src/emit/binary.rs
  3. 2 2
      src/emit/ewasm.rs
  4. 15 1150
      src/emit/mod.rs
  5. 3 3
      src/emit/solana.rs
  6. 1 1
      src/emit/substrate.rs
  7. 2 2
      src/lib.rs
  8. 2 2
      src/sema/contracts.rs
  9. 17 11
      tests/contract.rs

+ 1 - 1
src/bin/solang.rs

@@ -585,7 +585,7 @@ fn process_file(
     Ok(ns)
 }
 
-fn save_intermediates(binary: &solang::emit::Binary, matches: &ArgMatches) -> bool {
+fn save_intermediates(binary: &solang::emit::binary::Binary, matches: &ArgMatches) -> bool {
     let verbose = matches.is_present("VERBOSE");
 
     match matches.value_of("EMIT") {

+ 1162 - 0
src/emit/binary.rs

@@ -0,0 +1,1162 @@
+use crate::sema::ast::{BuiltinStruct, Contract, Namespace, Type};
+use std::cell::RefCell;
+use std::ffi::CStr;
+use std::path::Path;
+use std::str;
+
+use num_bigint::BigInt;
+use num_traits::ToPrimitive;
+use std::collections::HashMap;
+
+use crate::emit::substrate;
+use crate::emit::{ewasm, solana, BinaryOp, Generate, ReturnCode};
+use crate::linker::link;
+use crate::Target;
+use inkwell::builder::Builder;
+use inkwell::context::Context;
+use inkwell::memory_buffer::MemoryBuffer;
+use inkwell::module::{Linkage, Module};
+use inkwell::passes::PassManager;
+use inkwell::targets::{CodeModel, FileType, RelocMode};
+use inkwell::types::{
+    ArrayType, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, StringRadix,
+};
+use inkwell::values::{BasicValueEnum, FunctionValue, GlobalValue, IntValue, PointerValue};
+use inkwell::AddressSpace;
+use inkwell::IntPredicate;
+use inkwell::OptimizationLevel;
+use once_cell::sync::OnceCell;
+
+static LLVM_INIT: OnceCell<()> = OnceCell::new();
+
+pub struct Binary<'a> {
+    pub name: String,
+    pub module: Module<'a>,
+    pub runtime: Option<Box<Binary<'a>>>,
+    target: Target,
+    pub(crate) function_abort_value_transfers: bool,
+    pub(crate) constructor_abort_value_transfers: bool,
+    pub(crate) math_overflow_check: bool,
+    pub builder: Builder<'a>,
+    pub(crate) context: &'a Context,
+    pub(crate) functions: HashMap<usize, FunctionValue<'a>>,
+    code: RefCell<Vec<u8>>,
+    pub(crate) opt: OptimizationLevel,
+    pub(crate) code_size: RefCell<Option<IntValue<'a>>>,
+    pub(crate) selector: GlobalValue<'a>,
+    pub(crate) calldata_data: GlobalValue<'a>,
+    pub(crate) calldata_len: GlobalValue<'a>,
+    pub(crate) scratch_len: Option<GlobalValue<'a>>,
+    pub(crate) scratch: Option<GlobalValue<'a>>,
+    pub(crate) parameters: Option<PointerValue<'a>>,
+    pub(crate) return_values: HashMap<ReturnCode, IntValue<'a>>,
+}
+
+impl<'a> Binary<'a> {
+    /// Build the LLVM IR for a single contract
+    pub fn build(
+        context: &'a Context,
+        contract: &'a Contract,
+        ns: &'a Namespace,
+        filename: &'a str,
+        opt: OptimizationLevel,
+        math_overflow_check: bool,
+    ) -> Self {
+        match ns.target {
+            Target::Substrate { .. } => substrate::SubstrateTarget::build(
+                context,
+                contract,
+                ns,
+                filename,
+                opt,
+                math_overflow_check,
+            ),
+            Target::Ewasm => {
+                ewasm::EwasmTarget::build(context, contract, ns, filename, opt, math_overflow_check)
+            }
+            Target::Solana => solana::SolanaTarget::build(
+                context,
+                contract,
+                ns,
+                filename,
+                opt,
+                math_overflow_check,
+            ),
+        }
+    }
+
+    /// Build the LLVM IR for a set of contracts in a single namespace
+    pub fn build_bundle(
+        context: &'a Context,
+        namespaces: &'a [Namespace],
+        filename: &str,
+        opt: OptimizationLevel,
+        math_overflow_check: bool,
+    ) -> Self {
+        assert!(namespaces.iter().all(|ns| ns.target == Target::Solana));
+
+        solana::SolanaTarget::build_bundle(context, namespaces, filename, opt, math_overflow_check)
+    }
+
+    /// Compile the bin and return the code as bytes. The result is
+    /// cached, since this function can be called multiple times (e.g. one for
+    /// each time a bin of this type is created).
+    /// Pass our module to llvm for optimization and compilation
+    pub fn code(&self, generate: Generate) -> Result<Vec<u8>, String> {
+        // return cached result if available
+        if !self.code.borrow().is_empty() {
+            return Ok(self.code.borrow().clone());
+        }
+
+        match self.opt {
+            OptimizationLevel::Default | OptimizationLevel::Aggressive => {
+                let pass_manager = PassManager::create(());
+
+                pass_manager.add_promote_memory_to_register_pass();
+                pass_manager.add_function_inlining_pass();
+                pass_manager.add_global_dce_pass();
+                pass_manager.add_constant_merge_pass();
+
+                pass_manager.run_on(&self.module);
+            }
+            _ => {}
+        }
+
+        let target = inkwell::targets::Target::from_name(self.target.llvm_target_name()).unwrap();
+
+        let target_machine = target
+            .create_target_machine(
+                &self.target.llvm_target_triple(),
+                "",
+                self.target.llvm_features(),
+                self.opt,
+                RelocMode::Default,
+                CodeModel::Default,
+            )
+            .unwrap();
+
+        loop {
+            // we need to loop here to support ewasm deployer. It needs to know the size
+            // of itself. Note that in webassembly, the constants are LEB128 encoded so
+            // patching the length might actually change the length. So we need to loop
+            // until it is right.
+
+            // The correct solution is to make ewasm less insane.
+            match target_machine.write_to_memory_buffer(
+                &self.module,
+                if generate == Generate::Assembly {
+                    FileType::Assembly
+                } else {
+                    FileType::Object
+                },
+            ) {
+                Ok(out) => {
+                    let slice = out.as_slice();
+
+                    if generate == Generate::Linked {
+                        let bs = link(slice, &self.name, self.target);
+
+                        if !self.patch_code_size(bs.len() as u64) {
+                            self.code.replace(bs.to_vec());
+
+                            return Ok(bs.to_vec());
+                        }
+                    } else {
+                        return Ok(slice.to_vec());
+                    }
+                }
+                Err(s) => {
+                    return Err(s.to_string());
+                }
+            }
+        }
+    }
+
+    /// Mark all functions as internal unless they're in the export_list. This helps the
+    /// llvm globaldce pass eliminate unnecessary functions and reduce the wasm output.
+    pub(crate) fn internalize(&self, export_list: &[&str]) {
+        let mut func = self.module.get_first_function();
+
+        // FIXME: these functions are called from code generated by lowering into wasm,
+        // so eliminating them now will cause link errors. Either we should prevent these
+        // calls from being done in the first place or do dce at link time
+        let mut export_list = export_list.to_vec();
+        export_list.push("__ashlti3");
+        export_list.push("__lshrti3");
+        export_list.push("__ashrti3");
+
+        while let Some(f) = func {
+            let name = f.get_name().to_str().unwrap();
+
+            if !name.starts_with("llvm.")
+                && export_list.iter().all(|e| {
+                    // symbols may get renamed foo.1 or foo.2, also export those
+                    if let Some(tail) = name.strip_prefix(e) {
+                        if let Some(no) = tail.strip_prefix('.') {
+                            no.parse::<u32>().is_ok()
+                        } else {
+                            tail.is_empty()
+                        }
+                    } else {
+                        false
+                    }
+                })
+            {
+                f.set_linkage(Linkage::Internal);
+            }
+
+            func = f.get_next_function();
+        }
+    }
+
+    pub fn bitcode(&self, path: &Path) {
+        self.module.write_bitcode_to_path(path);
+    }
+
+    pub fn dump_llvm(&self, path: &Path) -> Result<(), String> {
+        if let Err(s) = self.module.print_to_file(path) {
+            return Err(s.to_string());
+        }
+
+        Ok(())
+    }
+
+    pub fn new(
+        context: &'a Context,
+        target: Target,
+        name: &str,
+        filename: &str,
+        opt: OptimizationLevel,
+        math_overflow_check: bool,
+        runtime: Option<Box<Binary<'a>>>,
+    ) -> Self {
+        LLVM_INIT.get_or_init(|| {
+            inkwell::targets::Target::initialize_webassembly(&Default::default());
+            inkwell::targets::Target::initialize_bpf(&Default::default());
+        });
+
+        let triple = target.llvm_target_triple();
+        let module = context.create_module(name);
+
+        module.set_triple(&triple);
+        module.set_source_file_name(filename);
+
+        // stdlib
+        let intr = load_stdlib(context, &target);
+        module.link_in_module(intr).unwrap();
+
+        let selector =
+            module.add_global(context.i32_type(), Some(AddressSpace::Generic), "selector");
+        selector.set_linkage(Linkage::Internal);
+        selector.set_initializer(&context.i32_type().const_zero());
+
+        let calldata_len = module.add_global(
+            context.i32_type(),
+            Some(AddressSpace::Generic),
+            "calldata_len",
+        );
+        calldata_len.set_linkage(Linkage::Internal);
+        calldata_len.set_initializer(&context.i32_type().const_zero());
+
+        let calldata_data = module.add_global(
+            context.i8_type().ptr_type(AddressSpace::Generic),
+            Some(AddressSpace::Generic),
+            "calldata_data",
+        );
+        calldata_data.set_linkage(Linkage::Internal);
+        calldata_data.set_initializer(
+            &context
+                .i8_type()
+                .ptr_type(AddressSpace::Generic)
+                .const_zero(),
+        );
+
+        let mut return_values = HashMap::new();
+
+        return_values.insert(ReturnCode::Success, context.i32_type().const_zero());
+        return_values.insert(
+            ReturnCode::FunctionSelectorInvalid,
+            context.i32_type().const_int(3, false),
+        );
+        return_values.insert(
+            ReturnCode::AbiEncodingInvalid,
+            context.i32_type().const_int(2, false),
+        );
+
+        Binary {
+            name: name.to_owned(),
+            module,
+            runtime,
+            function_abort_value_transfers: false,
+            constructor_abort_value_transfers: false,
+            math_overflow_check,
+            builder: context.create_builder(),
+            context,
+            target,
+            functions: HashMap::new(),
+            code: RefCell::new(Vec::new()),
+            opt,
+            code_size: RefCell::new(None),
+            selector,
+            calldata_data,
+            calldata_len,
+            scratch: None,
+            scratch_len: None,
+            parameters: None,
+            return_values,
+        }
+    }
+
+    /// Set flags for early aborts if a value transfer is done and no function/constructor can handle it
+    pub fn set_early_value_aborts(&mut self, contract: &Contract, ns: &Namespace) {
+        // if there is no payable function, fallback or receive then abort all value transfers at the top
+        // note that receive() is always payable so this just checkes for presence.
+        self.function_abort_value_transfers = !contract.functions.iter().any(|function_no| {
+            let f = &ns.functions[*function_no];
+            !f.is_constructor() && f.is_payable()
+        });
+
+        self.constructor_abort_value_transfers = !contract.functions.iter().any(|function_no| {
+            let f = &ns.functions[*function_no];
+            f.is_constructor() && f.is_payable()
+        });
+    }
+
+    /// llvm value type, as in chain currency (usually 128 bits int)
+    pub(crate) fn value_type(&self, ns: &Namespace) -> IntType<'a> {
+        self.context
+            .custom_width_int_type(ns.value_length as u32 * 8)
+    }
+
+    /// llvm address type
+    pub(crate) fn address_type(&self, ns: &Namespace) -> ArrayType<'a> {
+        self.context.i8_type().array_type(ns.address_length as u32)
+    }
+
+    /// Creates global string in the llvm module with initializer
+    ///
+    pub(crate) fn emit_global_string(
+        &self,
+        name: &str,
+        data: &[u8],
+        constant: bool,
+    ) -> PointerValue<'a> {
+        let ty = self.context.i8_type().array_type(data.len() as u32);
+
+        let gv = self
+            .module
+            .add_global(ty, Some(AddressSpace::Generic), name);
+
+        gv.set_linkage(Linkage::Internal);
+
+        gv.set_initializer(&self.context.const_string(data, false));
+
+        if constant {
+            gv.set_constant(true);
+            gv.set_unnamed_addr(true);
+        }
+
+        self.builder.build_pointer_cast(
+            gv.as_pointer_value(),
+            self.context.i8_type().ptr_type(AddressSpace::Generic),
+            name,
+        )
+    }
+
+    /// Wrapper for alloca. Ensures that the alloca is done on the first basic block.
+    /// If alloca is not on the first basic block, llvm will get to llvm_unreachable
+    /// for the BPF target.
+    pub(crate) fn build_alloca<T: BasicType<'a>>(
+        &self,
+        function: inkwell::values::FunctionValue<'a>,
+        ty: T,
+        name: &str,
+    ) -> PointerValue<'a> {
+        let entry = function
+            .get_first_basic_block()
+            .expect("function missing entry block");
+        let current = self.builder.get_insert_block().unwrap();
+
+        if let Some(instr) = &entry.get_first_instruction() {
+            self.builder.position_before(instr);
+        } else {
+            // if there is no instruction yet, then nothing was built
+            self.builder.position_at_end(entry);
+        }
+
+        let res = self.builder.build_alloca(ty, name);
+
+        self.builder.position_at_end(current);
+
+        res
+    }
+
+    pub(crate) fn build_array_alloca<T: BasicType<'a>>(
+        &self,
+        function: inkwell::values::FunctionValue<'a>,
+        ty: T,
+        length: IntValue<'a>,
+        name: &str,
+    ) -> PointerValue<'a> {
+        let entry = function
+            .get_first_basic_block()
+            .expect("function missing entry block");
+        let current = self.builder.get_insert_block().unwrap();
+
+        if let Some(instr) = entry.get_first_instruction() {
+            self.builder.position_before(&instr);
+        } else {
+            self.builder.position_at_end(entry);
+        }
+
+        let res = self.builder.build_array_alloca(ty, length, name);
+
+        self.builder.position_at_end(current);
+
+        res
+    }
+
+    /// Emit a loop from `from` to `to`. The closure exists to insert the body of the loop; the closure
+    /// gets the loop variable passed to it as an IntValue, and a userdata PointerValue
+    pub fn emit_static_loop_with_pointer<F>(
+        &self,
+        function: FunctionValue,
+        from: IntValue<'a>,
+        to: IntValue<'a>,
+        data_ref: &mut PointerValue<'a>,
+        mut insert_body: F,
+    ) where
+        F: FnMut(IntValue<'a>, &mut PointerValue<'a>),
+    {
+        let body = self.context.append_basic_block(function, "body");
+        let done = self.context.append_basic_block(function, "done");
+        let entry = self.builder.get_insert_block().unwrap();
+
+        self.builder.build_unconditional_branch(body);
+        self.builder.position_at_end(body);
+
+        let loop_ty = from.get_type();
+        let loop_phi = self.builder.build_phi(loop_ty, "index");
+        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
+        let mut data = data_phi.as_basic_value().into_pointer_value();
+
+        let loop_var = loop_phi.as_basic_value().into_int_value();
+
+        // add loop body
+        insert_body(loop_var, &mut data);
+
+        let next = self
+            .builder
+            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
+
+        let comp = self
+            .builder
+            .build_int_compare(IntPredicate::ULT, next, to, "loop_cond");
+        self.builder.build_conditional_branch(comp, body, done);
+
+        let body = self.builder.get_insert_block().unwrap();
+        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
+        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
+
+        self.builder.position_at_end(done);
+
+        *data_ref = data;
+    }
+
+    /// Emit a loop from `from` to `to`. The closure exists to insert the body of the loop; the closure
+    /// gets the loop variable passed to it as an IntValue, and a userdata IntValue
+    pub fn emit_static_loop_with_int<F>(
+        &self,
+        function: FunctionValue,
+        from: IntValue<'a>,
+        to: IntValue<'a>,
+        data_ref: &mut IntValue<'a>,
+        mut insert_body: F,
+    ) where
+        F: FnMut(IntValue<'a>, &mut IntValue<'a>),
+    {
+        let body = self.context.append_basic_block(function, "body");
+        let done = self.context.append_basic_block(function, "done");
+        let entry = self.builder.get_insert_block().unwrap();
+
+        self.builder.build_unconditional_branch(body);
+        self.builder.position_at_end(body);
+
+        let loop_ty = from.get_type();
+        let loop_phi = self.builder.build_phi(loop_ty, "index");
+        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
+        let mut data = data_phi.as_basic_value().into_int_value();
+
+        let loop_var = loop_phi.as_basic_value().into_int_value();
+
+        // add loop body
+        insert_body(loop_var, &mut data);
+
+        let next = self
+            .builder
+            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
+
+        let comp = self
+            .builder
+            .build_int_compare(IntPredicate::ULT, next, to, "loop_cond");
+        self.builder.build_conditional_branch(comp, body, done);
+
+        let body = self.builder.get_insert_block().unwrap();
+        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
+        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
+
+        self.builder.position_at_end(done);
+
+        *data_ref = data;
+    }
+
+    /// Emit a loop from `from` to `to`, checking the condition _before_ the body.
+    pub fn emit_loop_cond_first_with_int<F>(
+        &self,
+        function: FunctionValue,
+        from: IntValue<'a>,
+        to: IntValue<'a>,
+        data_ref: &mut IntValue<'a>,
+        mut insert_body: F,
+    ) where
+        F: FnMut(IntValue<'a>, &mut IntValue<'a>),
+    {
+        let cond = self.context.append_basic_block(function, "cond");
+        let body = self.context.append_basic_block(function, "body");
+        let done = self.context.append_basic_block(function, "done");
+        let entry = self.builder.get_insert_block().unwrap();
+
+        self.builder.build_unconditional_branch(cond);
+        self.builder.position_at_end(cond);
+
+        let loop_ty = from.get_type();
+        let loop_phi = self.builder.build_phi(loop_ty, "index");
+        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
+        let mut data = data_phi.as_basic_value().into_int_value();
+
+        let loop_var = loop_phi.as_basic_value().into_int_value();
+
+        let next = self
+            .builder
+            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
+
+        let comp = self
+            .builder
+            .build_int_compare(IntPredicate::ULT, loop_var, to, "loop_cond");
+        self.builder.build_conditional_branch(comp, body, done);
+
+        self.builder.position_at_end(body);
+        // add loop body
+        insert_body(loop_var, &mut data);
+
+        let body = self.builder.get_insert_block().unwrap();
+
+        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
+        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
+
+        self.builder.build_unconditional_branch(cond);
+
+        self.builder.position_at_end(done);
+
+        *data_ref = data_phi.as_basic_value().into_int_value();
+    }
+
+    /// Emit a loop from `from` to `to`, checking the condition _before_ the body.
+    pub fn emit_loop_cond_first_with_pointer<F>(
+        &self,
+        function: FunctionValue,
+        from: IntValue<'a>,
+        to: IntValue<'a>,
+        data_ref: &mut PointerValue<'a>,
+        mut insert_body: F,
+    ) where
+        F: FnMut(IntValue<'a>, &mut PointerValue<'a>),
+    {
+        let cond = self.context.append_basic_block(function, "cond");
+        let body = self.context.append_basic_block(function, "body");
+        let done = self.context.append_basic_block(function, "done");
+        let entry = self.builder.get_insert_block().unwrap();
+
+        self.builder.build_unconditional_branch(cond);
+        self.builder.position_at_end(cond);
+
+        let loop_ty = from.get_type();
+        let loop_phi = self.builder.build_phi(loop_ty, "index");
+        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
+        let mut data = data_phi.as_basic_value().into_pointer_value();
+
+        let loop_var = loop_phi.as_basic_value().into_int_value();
+
+        let next = self
+            .builder
+            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
+
+        let comp = self
+            .builder
+            .build_int_compare(IntPredicate::ULT, loop_var, to, "loop_cond");
+        self.builder.build_conditional_branch(comp, body, done);
+
+        self.builder.position_at_end(body);
+        // add loop body
+        insert_body(loop_var, &mut data);
+
+        let body = self.builder.get_insert_block().unwrap();
+
+        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
+        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
+
+        self.builder.build_unconditional_branch(cond);
+
+        self.builder.position_at_end(done);
+
+        *data_ref = data_phi.as_basic_value().into_pointer_value();
+    }
+
+    /// Convert a BigInt number to llvm const value
+    pub(crate) fn number_literal(&self, bits: u32, n: &BigInt, _ns: &Namespace) -> IntValue<'a> {
+        let ty = self.context.custom_width_int_type(bits);
+        let s = n.to_string();
+
+        ty.const_int_from_string(&s, StringRadix::Decimal).unwrap()
+    }
+
+    /// Emit function prototype
+    pub(crate) fn function_type(
+        &self,
+        params: &[Type],
+        returns: &[Type],
+        ns: &Namespace,
+    ) -> FunctionType<'a> {
+        // function parameters
+        let mut args = params
+            .iter()
+            .map(|ty| self.llvm_var_ty(ty, ns).into())
+            .collect::<Vec<BasicMetadataTypeEnum>>();
+
+        // add return values
+        for ty in returns {
+            args.push(if ty.is_reference_type(ns) && !ty.is_contract_storage() {
+                self.llvm_type(ty, ns)
+                    .ptr_type(AddressSpace::Generic)
+                    .ptr_type(AddressSpace::Generic)
+                    .into()
+            } else {
+                self.llvm_type(ty, ns)
+                    .ptr_type(AddressSpace::Generic)
+                    .into()
+            });
+        }
+
+        // On Solana, we need to pass around the accounts
+        if ns.target == Target::Solana {
+            args.push(
+                self.module
+                    .get_struct_type("struct.SolParameters")
+                    .unwrap()
+                    .ptr_type(AddressSpace::Generic)
+                    .into(),
+            );
+        }
+
+        // Solana return type should be 64 bit, 32 bit on wasm
+        self.return_values[&ReturnCode::Success]
+            .get_type()
+            .fn_type(&args, false)
+    }
+
+    // Create the llvm intrinsic for counting leading zeros
+    pub fn llvm_ctlz(&self, bit: u32) -> FunctionValue<'a> {
+        let name = format!("llvm.ctlz.i{}", bit);
+        let ty = self.context.custom_width_int_type(bit);
+
+        if let Some(f) = self.module.get_function(&name) {
+            return f;
+        }
+
+        self.module.add_function(
+            &name,
+            ty.fn_type(&[ty.into(), self.context.bool_type().into()], false),
+            None,
+        )
+    }
+
+    // Create the llvm intrinsic for bswap
+    pub fn llvm_bswap(&self, bit: u32) -> FunctionValue<'a> {
+        let name = format!("llvm.bswap.i{}", bit);
+        let ty = self.context.custom_width_int_type(bit);
+
+        if let Some(f) = self.module.get_function(&name) {
+            return f;
+        }
+
+        self.module
+            .add_function(&name, ty.fn_type(&[ty.into()], false), None)
+    }
+
+    // Create the llvm intrinsic for overflows
+    pub fn llvm_overflow(
+        &self,
+        ret_ty: BasicTypeEnum<'a>,
+        ty: IntType<'a>,
+        signed: bool,
+        op: BinaryOp,
+    ) -> FunctionValue<'a> {
+        let bit = ty.get_bit_width();
+        let name = format!(
+            "llvm.{}{}.with.overflow.i{}",
+            if signed { "s" } else { "u" },
+            op,
+            bit,
+        );
+
+        if let Some(f) = self.module.get_function(&name) {
+            return f;
+        }
+
+        self.module
+            .add_function(&name, ret_ty.fn_type(&[ty.into(), ty.into()], false), None)
+    }
+
+    /// Return the llvm type for a variable holding the type, not the type itself
+    pub(crate) fn llvm_var_ty(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
+        let llvm_ty = self.llvm_type(ty, ns);
+        match ty.deref_memory() {
+            Type::Struct(_) | Type::Array(..) | Type::DynamicBytes | Type::String => {
+                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
+            }
+            _ => llvm_ty,
+        }
+    }
+
+    /// Default empty value
+    pub(crate) fn default_value(&self, ty: &Type, ns: &Namespace) -> BasicValueEnum<'a> {
+        let llvm_ty = self.llvm_var_ty(ty, ns);
+
+        // const_zero() on BasicTypeEnum yet. Should be coming to inkwell soon
+        if llvm_ty.is_pointer_type() {
+            llvm_ty.into_pointer_type().const_null().into()
+        } else if llvm_ty.is_array_type() {
+            self.address_type(ns).const_zero().into()
+        } else {
+            llvm_ty.into_int_type().const_zero().into()
+        }
+    }
+
+    /// Return the llvm type for field in struct or array
+    pub(crate) fn llvm_field_ty(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
+        let llvm_ty = self.llvm_type(ty, ns);
+        match ty.deref_memory() {
+            Type::Array(_, dim) if dim[0].is_none() => {
+                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
+            }
+            Type::DynamicBytes | Type::String => {
+                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
+            }
+            _ => llvm_ty,
+        }
+    }
+
+    /// Return the llvm type for the resolved type.
+    pub(crate) fn llvm_type(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
+        if ty.builtin_struct(ns) == BuiltinStruct::AccountInfo {
+            return self
+                .module
+                .get_struct_type("struct.SolAccountInfo")
+                .unwrap()
+                .into();
+        } else {
+            match ty {
+                Type::Bool => BasicTypeEnum::IntType(self.context.bool_type()),
+                Type::Int(n) | Type::Uint(n) => {
+                    BasicTypeEnum::IntType(self.context.custom_width_int_type(*n as u32))
+                }
+                Type::Value => BasicTypeEnum::IntType(
+                    self.context
+                        .custom_width_int_type(ns.value_length as u32 * 8),
+                ),
+                Type::Contract(_) | Type::Address(_) => {
+                    BasicTypeEnum::ArrayType(self.address_type(ns))
+                }
+                Type::Bytes(n) => {
+                    BasicTypeEnum::IntType(self.context.custom_width_int_type(*n as u32 * 8))
+                }
+                Type::Enum(n) => self.llvm_type(&ns.enums[*n].ty, ns),
+                Type::String | Type::DynamicBytes => {
+                    self.module.get_struct_type("struct.vector").unwrap().into()
+                }
+                Type::Array(base_ty, dims) => {
+                    let ty = self.llvm_field_ty(base_ty, ns);
+
+                    let mut dims = dims.iter();
+
+                    let mut aty = match dims.next().unwrap() {
+                        Some(d) => ty.array_type(d.to_u32().unwrap()),
+                        None => {
+                            return self.module.get_struct_type("struct.vector").unwrap().into()
+                        }
+                    };
+
+                    for dim in dims {
+                        match dim {
+                            Some(d) => aty = aty.array_type(d.to_u32().unwrap()),
+                            None => {
+                                return self.module.get_struct_type("struct.vector").unwrap().into()
+                            }
+                        }
+                    }
+
+                    BasicTypeEnum::ArrayType(aty)
+                }
+                Type::Struct(n) => self
+                    .context
+                    .struct_type(
+                        &ns.structs[*n]
+                            .fields
+                            .iter()
+                            .map(|f| self.llvm_field_ty(&f.ty, ns))
+                            .collect::<Vec<BasicTypeEnum>>(),
+                        false,
+                    )
+                    .as_basic_type_enum(),
+                Type::Mapping(..) => unreachable!(),
+                Type::Ref(r) => self
+                    .llvm_type(r, ns)
+                    .ptr_type(AddressSpace::Generic)
+                    .as_basic_type_enum(),
+                Type::StorageRef(..) => self.llvm_type(&ns.storage_type(), ns),
+                Type::InternalFunction {
+                    params, returns, ..
+                } => {
+                    let ftype = self.function_type(params, returns, ns);
+
+                    BasicTypeEnum::PointerType(ftype.ptr_type(AddressSpace::Generic))
+                }
+                Type::ExternalFunction { .. } => {
+                    let address = self.llvm_type(&Type::Address(false), ns);
+                    let selector = self.llvm_type(&Type::Uint(32), ns);
+
+                    BasicTypeEnum::PointerType(
+                        self.context
+                            .struct_type(&[address, selector], false)
+                            .ptr_type(AddressSpace::Generic),
+                    )
+                }
+                Type::Slice => BasicTypeEnum::StructType(
+                    self.context.struct_type(
+                        &[
+                            self.context
+                                .i8_type()
+                                .ptr_type(AddressSpace::Generic)
+                                .into(),
+                            self.context.i32_type().into(),
+                        ],
+                        false,
+                    ),
+                ),
+                Type::UserType(no) => self.llvm_type(&ns.user_types[*no].ty, ns),
+                _ => unreachable!(),
+            }
+        }
+    }
+
+    /// ewasm deployer needs to know what its own code size is, so we compile once to
+    /// get the size, patch in the value and then recompile.
+    fn patch_code_size(&self, code_size: u64) -> bool {
+        let current_size = {
+            let current_size_opt = self.code_size.borrow();
+
+            if let Some(current_size) = *current_size_opt {
+                if code_size == current_size.get_zero_extended_constant().unwrap() {
+                    return false;
+                }
+
+                current_size
+            } else {
+                return false;
+            }
+        };
+
+        let new_size = self.context.i32_type().const_int(code_size, false);
+
+        current_size.replace_all_uses_with(new_size);
+
+        self.code_size.replace(Some(new_size));
+
+        true
+    }
+
+    /// Allocate vector
+    pub(crate) fn vector_new(
+        &self,
+        size: IntValue<'a>,
+        elem_size: IntValue<'a>,
+        init: Option<&Vec<u8>>,
+    ) -> PointerValue<'a> {
+        if let Some(init) = init {
+            if init.is_empty() {
+                return self
+                    .module
+                    .get_struct_type("struct.vector")
+                    .unwrap()
+                    .ptr_type(AddressSpace::Generic)
+                    .const_null();
+            }
+        }
+
+        let init = match init {
+            None => self.builder.build_int_to_ptr(
+                self.context.i32_type().const_all_ones(),
+                self.context.i8_type().ptr_type(AddressSpace::Generic),
+                "invalid",
+            ),
+            Some(s) => self.emit_global_string("const_string", s, true),
+        };
+
+        let v = self
+            .builder
+            .build_call(
+                self.module.get_function("vector_new").unwrap(),
+                &[size.into(), elem_size.into(), init.into()],
+                "",
+            )
+            .try_as_basic_value()
+            .left()
+            .unwrap();
+
+        self.builder.build_pointer_cast(
+            v.into_pointer_value(),
+            self.module
+                .get_struct_type("struct.vector")
+                .unwrap()
+                .ptr_type(AddressSpace::Generic),
+            "vector",
+        )
+    }
+
+    /// Number of element in a vector
+    pub(crate) fn vector_len(&self, vector: BasicValueEnum<'a>) -> IntValue<'a> {
+        if vector.is_struct_value() {
+            // slice
+            let slice = vector.into_struct_value();
+
+            self.builder
+                .build_extract_value(slice, 1, "slice_len")
+                .unwrap()
+                .into_int_value()
+        } else {
+            let struct_ty = vector
+                .into_pointer_value()
+                .get_type()
+                .get_element_type()
+                .into_struct_type();
+            let name = struct_ty.get_name().unwrap();
+
+            if name == CStr::from_bytes_with_nul(b"struct.SolAccountInfo\0").unwrap() {
+                // load the data pointer
+                let data = self
+                    .builder
+                    .build_load(
+                        self.builder
+                            .build_struct_gep(vector.into_pointer_value(), 3, "data")
+                            .unwrap(),
+                        "data",
+                    )
+                    .into_pointer_value();
+
+                // get the offset of the return data
+                let header_ptr = self.builder.build_pointer_cast(
+                    data,
+                    self.context.i32_type().ptr_type(AddressSpace::Generic),
+                    "header_ptr",
+                );
+
+                let data_len_ptr = unsafe {
+                    self.builder.build_gep(
+                        header_ptr,
+                        &[self.context.i64_type().const_int(1, false)],
+                        "data_len_ptr",
+                    )
+                };
+
+                self.builder
+                    .build_load(data_len_ptr, "len")
+                    .into_int_value()
+            } else {
+                // field 0 is the length
+                let vector = vector.into_pointer_value();
+
+                let len = unsafe {
+                    self.builder.build_gep(
+                        vector,
+                        &[
+                            self.context.i32_type().const_zero(),
+                            self.context.i32_type().const_zero(),
+                        ],
+                        "vector_len",
+                    )
+                };
+
+                self.builder
+                    .build_select(
+                        self.builder.build_is_null(vector, "vector_is_null"),
+                        self.context.i32_type().const_zero(),
+                        self.builder.build_load(len, "vector_len").into_int_value(),
+                        "length",
+                    )
+                    .into_int_value()
+            }
+        }
+    }
+
+    /// Return the pointer to the actual bytes in the vector
+    pub(crate) fn vector_bytes(&self, vector: BasicValueEnum<'a>) -> PointerValue<'a> {
+        if vector.is_struct_value() {
+            // slice
+            let slice = vector.into_struct_value();
+
+            self.builder
+                .build_extract_value(slice, 0, "slice_data")
+                .unwrap()
+                .into_pointer_value()
+        } else {
+            let data = unsafe {
+                self.builder.build_gep(
+                    vector.into_pointer_value(),
+                    &[
+                        self.context.i32_type().const_zero(),
+                        self.context.i32_type().const_int(2, false),
+                    ],
+                    "data",
+                )
+            };
+
+            self.builder.build_pointer_cast(
+                data,
+                self.context.i8_type().ptr_type(AddressSpace::Generic),
+                "data",
+            )
+        }
+    }
+
+    /// Dereference an array
+    pub(crate) fn array_subscript(
+        &self,
+        array_ty: &Type,
+        array: PointerValue<'a>,
+        index: IntValue<'a>,
+        ns: &Namespace,
+    ) -> PointerValue<'a> {
+        match array_ty {
+            Type::Array(_, dim) => {
+                if dim[0].is_some() {
+                    // fixed size array
+                    unsafe {
+                        self.builder.build_gep(
+                            array,
+                            &[self.context.i32_type().const_zero(), index],
+                            "index_access",
+                        )
+                    }
+                } else {
+                    let elem_ty = array_ty.array_deref();
+                    let llvm_elem_ty = self.llvm_field_ty(&elem_ty, ns);
+
+                    // dynamic length array or vector
+                    let index = self.builder.build_int_mul(
+                        index,
+                        llvm_elem_ty
+                            .into_pointer_type()
+                            .get_element_type()
+                            .size_of()
+                            .unwrap()
+                            .const_cast(self.context.i32_type(), false),
+                        "",
+                    );
+
+                    let elem = unsafe {
+                        self.builder.build_gep(
+                            array,
+                            &[
+                                self.context.i32_type().const_zero(),
+                                self.context.i32_type().const_int(2, false),
+                                index,
+                            ],
+                            "index_access",
+                        )
+                    };
+
+                    self.builder
+                        .build_pointer_cast(elem, llvm_elem_ty.into_pointer_type(), "elem")
+                }
+            }
+            _ => unreachable!(),
+        }
+    }
+}
+
+/// Return the stdlib as parsed llvm module. The solidity standard library is hardcoded into
+/// the solang library
+fn load_stdlib<'a>(context: &'a Context, target: &Target) -> Module<'a> {
+    if *target == Target::Solana {
+        let memory = MemoryBuffer::create_from_memory_range(BPF_IR[0], "bpf_bc");
+
+        let module = Module::parse_bitcode_from_buffer(&memory, context).unwrap();
+
+        for bc in BPF_IR.iter().skip(1) {
+            let memory = MemoryBuffer::create_from_memory_range(bc, "bpf_bc");
+
+            module
+                .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
+                .unwrap();
+        }
+
+        return module;
+    }
+
+    let memory = MemoryBuffer::create_from_memory_range(WASM_IR[0], "wasm_bc");
+
+    let module = Module::parse_bitcode_from_buffer(&memory, context).unwrap();
+
+    for bc in WASM_IR.iter().skip(1) {
+        let memory = MemoryBuffer::create_from_memory_range(bc, "wasm_bc");
+
+        module
+            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
+            .unwrap();
+    }
+
+    if let Target::Substrate { .. } = *target {
+        let memory = MemoryBuffer::create_from_memory_range(SUBSTRATE_IR, "substrate");
+
+        module
+            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
+            .unwrap();
+
+        // substrate does not provide ripemd160
+        let memory = MemoryBuffer::create_from_memory_range(RIPEMD160_IR, "ripemd160");
+
+        module
+            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
+            .unwrap();
+    }
+
+    module
+}
+
+static BPF_IR: [&[u8]; 5] = [
+    include_bytes!("../../stdlib/bpf/stdlib.bc"),
+    include_bytes!("../../stdlib/bpf/bigint.bc"),
+    include_bytes!("../../stdlib/bpf/format.bc"),
+    include_bytes!("../../stdlib/bpf/solana.bc"),
+    include_bytes!("../../stdlib/bpf/ripemd160.bc"),
+];
+
+static WASM_IR: [&[u8]; 4] = [
+    include_bytes!("../../stdlib/wasm/stdlib.bc"),
+    include_bytes!("../../stdlib/wasm/wasmheap.bc"),
+    include_bytes!("../../stdlib/wasm/bigint.bc"),
+    include_bytes!("../../stdlib/wasm/format.bc"),
+];
+
+static RIPEMD160_IR: &[u8] = include_bytes!("../../stdlib/wasm/ripemd160.bc");
+static SUBSTRATE_IR: &[u8] = include_bytes!("../../stdlib/wasm/substrate.bc");

+ 2 - 2
src/emit/ewasm.rs

@@ -17,9 +17,9 @@ use inkwell::AddressSpace;
 use inkwell::IntPredicate;
 use inkwell::OptimizationLevel;
 
-use super::ethabiencoder;
-use super::{Binary, TargetRuntime, Variable};
+use crate::emit::ethabiencoder;
 use crate::emit::Generate;
+use crate::emit::{Binary, TargetRuntime, Variable};
 
 pub struct EwasmTarget {
     abi: ethabiencoder::EthAbiDecoder,

+ 15 - 1150
src/emit/mod.rs

@@ -4,11 +4,8 @@ use crate::sema::ast::RetrieveType;
 use crate::sema::ast::{
     BuiltinStruct, CallTy, Contract, FormatArg, Namespace, Parameter, StringLocation, Type,
 };
-use std::cell::RefCell;
 use std::convert::TryFrom;
-use std::ffi::CStr;
 use std::fmt;
-use std::path::Path;
 use std::str;
 
 use num_bigint::{BigInt, Sign};
@@ -17,39 +14,28 @@ use num_traits::ToPrimitive;
 use std::collections::{HashMap, VecDeque};
 
 use crate::Target;
-use inkwell::builder::Builder;
-use inkwell::context::Context;
-use inkwell::memory_buffer::MemoryBuffer;
-use inkwell::module::{Linkage, Module};
-use inkwell::passes::PassManager;
-use inkwell::targets::{CodeModel, FileType, RelocMode, TargetTriple};
-use inkwell::types::{
-    ArrayType, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, StringRadix,
-};
+use inkwell::module::Linkage;
+use inkwell::targets::TargetTriple;
+use inkwell::types::{BasicType, IntType, StringRadix};
 use inkwell::values::{
-    ArrayValue, BasicMetadataValueEnum, BasicValueEnum, CallableValue, FunctionValue, GlobalValue,
-    IntValue, PhiValue, PointerValue,
+    ArrayValue, BasicMetadataValueEnum, BasicValueEnum, CallableValue, FunctionValue, IntValue,
+    PhiValue, PointerValue,
 };
 use inkwell::AddressSpace;
 use inkwell::IntPredicate;
-use inkwell::OptimizationLevel;
 
+pub mod binary;
 mod ethabiencoder;
-mod ewasm;
+pub mod ewasm;
 mod loop_builder;
-mod solana;
-mod substrate;
-use once_cell::sync::OnceCell;
-
-use crate::{
-    codegen::{
-        cfg::{ControlFlowGraph, HashTy, Instr, InternalCallTy},
-        vartable::Storage,
-    },
-    linker::link,
-};
+pub mod solana;
+pub mod substrate;
 
-static LLVM_INIT: OnceCell<()> = OnceCell::new();
+use crate::codegen::{
+    cfg::{ControlFlowGraph, HashTy, Instr, InternalCallTy},
+    vartable::Storage,
+};
+use crate::emit::binary::Binary;
 
 #[derive(Clone)]
 pub struct Variable<'a> {
@@ -5567,31 +5553,9 @@ pub trait TargetRuntime<'a> {
             .into_int_value()
     }
 }
-pub struct Binary<'a> {
-    pub name: String,
-    pub module: Module<'a>,
-    pub runtime: Option<Box<Binary<'a>>>,
-    target: Target,
-    function_abort_value_transfers: bool,
-    constructor_abort_value_transfers: bool,
-    math_overflow_check: bool,
-    builder: Builder<'a>,
-    context: &'a Context,
-    functions: HashMap<usize, FunctionValue<'a>>,
-    code: RefCell<Vec<u8>>,
-    opt: OptimizationLevel,
-    code_size: RefCell<Option<IntValue<'a>>>,
-    selector: GlobalValue<'a>,
-    calldata_data: GlobalValue<'a>,
-    calldata_len: GlobalValue<'a>,
-    scratch_len: Option<GlobalValue<'a>>,
-    scratch: Option<GlobalValue<'a>>,
-    parameters: Option<PointerValue<'a>>,
-    return_values: HashMap<ReturnCode, IntValue<'a>>,
-}
 
 #[derive(PartialEq, Eq, Hash)]
-enum ReturnCode {
+pub(crate) enum ReturnCode {
     Success,
     FunctionSelectorInvalid,
     AbiEncodingInvalid,
@@ -5604,1105 +5568,6 @@ pub enum Generate {
     Linked,
 }
 
-impl<'a> Binary<'a> {
-    /// Build the LLVM IR for a single contract
-    pub fn build(
-        context: &'a Context,
-        contract: &'a Contract,
-        ns: &'a Namespace,
-        filename: &'a str,
-        opt: OptimizationLevel,
-        math_overflow_check: bool,
-    ) -> Self {
-        match ns.target {
-            Target::Substrate { .. } => substrate::SubstrateTarget::build(
-                context,
-                contract,
-                ns,
-                filename,
-                opt,
-                math_overflow_check,
-            ),
-            Target::Ewasm => {
-                ewasm::EwasmTarget::build(context, contract, ns, filename, opt, math_overflow_check)
-            }
-            Target::Solana => solana::SolanaTarget::build(
-                context,
-                contract,
-                ns,
-                filename,
-                opt,
-                math_overflow_check,
-            ),
-        }
-    }
-
-    /// Build the LLVM IR for a set of contracts in a single namespace
-    pub fn build_bundle(
-        context: &'a Context,
-        namespaces: &'a [Namespace],
-        filename: &str,
-        opt: OptimizationLevel,
-        math_overflow_check: bool,
-    ) -> Self {
-        assert!(namespaces.iter().all(|ns| ns.target == Target::Solana));
-
-        solana::SolanaTarget::build_bundle(context, namespaces, filename, opt, math_overflow_check)
-    }
-
-    /// Compile the bin and return the code as bytes. The result is
-    /// cached, since this function can be called multiple times (e.g. one for
-    /// each time a bin of this type is created).
-    /// Pass our module to llvm for optimization and compilation
-    pub fn code(&self, generate: Generate) -> Result<Vec<u8>, String> {
-        // return cached result if available
-        if !self.code.borrow().is_empty() {
-            return Ok(self.code.borrow().clone());
-        }
-
-        match self.opt {
-            OptimizationLevel::Default | OptimizationLevel::Aggressive => {
-                let pass_manager = PassManager::create(());
-
-                pass_manager.add_promote_memory_to_register_pass();
-                pass_manager.add_function_inlining_pass();
-                pass_manager.add_global_dce_pass();
-                pass_manager.add_constant_merge_pass();
-
-                pass_manager.run_on(&self.module);
-            }
-            _ => {}
-        }
-
-        let target = inkwell::targets::Target::from_name(self.target.llvm_target_name()).unwrap();
-
-        let target_machine = target
-            .create_target_machine(
-                &self.target.llvm_target_triple(),
-                "",
-                self.target.llvm_features(),
-                self.opt,
-                RelocMode::Default,
-                CodeModel::Default,
-            )
-            .unwrap();
-
-        loop {
-            // we need to loop here to support ewasm deployer. It needs to know the size
-            // of itself. Note that in webassembly, the constants are LEB128 encoded so
-            // patching the length might actually change the length. So we need to loop
-            // until it is right.
-
-            // The correct solution is to make ewasm less insane.
-            match target_machine.write_to_memory_buffer(
-                &self.module,
-                if generate == Generate::Assembly {
-                    FileType::Assembly
-                } else {
-                    FileType::Object
-                },
-            ) {
-                Ok(out) => {
-                    let slice = out.as_slice();
-
-                    if generate == Generate::Linked {
-                        let bs = link(slice, &self.name, self.target);
-
-                        if !self.patch_code_size(bs.len() as u64) {
-                            self.code.replace(bs.to_vec());
-
-                            return Ok(bs.to_vec());
-                        }
-                    } else {
-                        return Ok(slice.to_vec());
-                    }
-                }
-                Err(s) => {
-                    return Err(s.to_string());
-                }
-            }
-        }
-    }
-
-    /// Mark all functions as internal unless they're in the export_list. This helps the
-    /// llvm globaldce pass eliminate unnecessary functions and reduce the wasm output.
-    fn internalize(&self, export_list: &[&str]) {
-        let mut func = self.module.get_first_function();
-
-        // FIXME: these functions are called from code generated by lowering into wasm,
-        // so eliminating them now will cause link errors. Either we should prevent these
-        // calls from being done in the first place or do dce at link time
-        let mut export_list = export_list.to_vec();
-        export_list.push("__ashlti3");
-        export_list.push("__lshrti3");
-        export_list.push("__ashrti3");
-
-        while let Some(f) = func {
-            let name = f.get_name().to_str().unwrap();
-
-            if !name.starts_with("llvm.")
-                && export_list.iter().all(|e| {
-                    // symbols may get renamed foo.1 or foo.2, also export those
-                    if let Some(tail) = name.strip_prefix(e) {
-                        if let Some(no) = tail.strip_prefix('.') {
-                            no.parse::<u32>().is_ok()
-                        } else {
-                            tail.is_empty()
-                        }
-                    } else {
-                        false
-                    }
-                })
-            {
-                f.set_linkage(Linkage::Internal);
-            }
-
-            func = f.get_next_function();
-        }
-    }
-
-    pub fn bitcode(&self, path: &Path) {
-        self.module.write_bitcode_to_path(path);
-    }
-
-    pub fn dump_llvm(&self, path: &Path) -> Result<(), String> {
-        if let Err(s) = self.module.print_to_file(path) {
-            return Err(s.to_string());
-        }
-
-        Ok(())
-    }
-
-    pub fn new(
-        context: &'a Context,
-        target: Target,
-        name: &str,
-        filename: &str,
-        opt: OptimizationLevel,
-        math_overflow_check: bool,
-        runtime: Option<Box<Binary<'a>>>,
-    ) -> Self {
-        LLVM_INIT.get_or_init(|| {
-            inkwell::targets::Target::initialize_webassembly(&Default::default());
-            inkwell::targets::Target::initialize_bpf(&Default::default());
-        });
-
-        let triple = target.llvm_target_triple();
-        let module = context.create_module(name);
-
-        module.set_triple(&triple);
-        module.set_source_file_name(filename);
-
-        // stdlib
-        let intr = load_stdlib(context, &target);
-        module.link_in_module(intr).unwrap();
-
-        let selector =
-            module.add_global(context.i32_type(), Some(AddressSpace::Generic), "selector");
-        selector.set_linkage(Linkage::Internal);
-        selector.set_initializer(&context.i32_type().const_zero());
-
-        let calldata_len = module.add_global(
-            context.i32_type(),
-            Some(AddressSpace::Generic),
-            "calldata_len",
-        );
-        calldata_len.set_linkage(Linkage::Internal);
-        calldata_len.set_initializer(&context.i32_type().const_zero());
-
-        let calldata_data = module.add_global(
-            context.i8_type().ptr_type(AddressSpace::Generic),
-            Some(AddressSpace::Generic),
-            "calldata_data",
-        );
-        calldata_data.set_linkage(Linkage::Internal);
-        calldata_data.set_initializer(
-            &context
-                .i8_type()
-                .ptr_type(AddressSpace::Generic)
-                .const_zero(),
-        );
-
-        let mut return_values = HashMap::new();
-
-        return_values.insert(ReturnCode::Success, context.i32_type().const_zero());
-        return_values.insert(
-            ReturnCode::FunctionSelectorInvalid,
-            context.i32_type().const_int(3, false),
-        );
-        return_values.insert(
-            ReturnCode::AbiEncodingInvalid,
-            context.i32_type().const_int(2, false),
-        );
-
-        Binary {
-            name: name.to_owned(),
-            module,
-            runtime,
-            function_abort_value_transfers: false,
-            constructor_abort_value_transfers: false,
-            math_overflow_check,
-            builder: context.create_builder(),
-            context,
-            target,
-            functions: HashMap::new(),
-            code: RefCell::new(Vec::new()),
-            opt,
-            code_size: RefCell::new(None),
-            selector,
-            calldata_data,
-            calldata_len,
-            scratch: None,
-            scratch_len: None,
-            parameters: None,
-            return_values,
-        }
-    }
-
-    /// Set flags for early aborts if a value transfer is done and no function/constructor can handle it
-    pub fn set_early_value_aborts(&mut self, contract: &Contract, ns: &Namespace) {
-        // if there is no payable function, fallback or receive then abort all value transfers at the top
-        // note that receive() is always payable so this just checkes for presence.
-        self.function_abort_value_transfers = !contract.functions.iter().any(|function_no| {
-            let f = &ns.functions[*function_no];
-            !f.is_constructor() && f.is_payable()
-        });
-
-        self.constructor_abort_value_transfers = !contract.functions.iter().any(|function_no| {
-            let f = &ns.functions[*function_no];
-            f.is_constructor() && f.is_payable()
-        });
-    }
-
-    /// llvm value type, as in chain currency (usually 128 bits int)
-    fn value_type(&self, ns: &Namespace) -> IntType<'a> {
-        self.context
-            .custom_width_int_type(ns.value_length as u32 * 8)
-    }
-
-    /// llvm address type
-    fn address_type(&self, ns: &Namespace) -> ArrayType<'a> {
-        self.context.i8_type().array_type(ns.address_length as u32)
-    }
-
-    /// Creates global string in the llvm module with initializer
-    ///
-    fn emit_global_string(&self, name: &str, data: &[u8], constant: bool) -> PointerValue<'a> {
-        let ty = self.context.i8_type().array_type(data.len() as u32);
-
-        let gv = self
-            .module
-            .add_global(ty, Some(AddressSpace::Generic), name);
-
-        gv.set_linkage(Linkage::Internal);
-
-        gv.set_initializer(&self.context.const_string(data, false));
-
-        if constant {
-            gv.set_constant(true);
-            gv.set_unnamed_addr(true);
-        }
-
-        self.builder.build_pointer_cast(
-            gv.as_pointer_value(),
-            self.context.i8_type().ptr_type(AddressSpace::Generic),
-            name,
-        )
-    }
-
-    /// Wrapper for alloca. Ensures that the alloca is done on the first basic block.
-    /// If alloca is not on the first basic block, llvm will get to llvm_unreachable
-    /// for the BPF target.
-    fn build_alloca<T: BasicType<'a>>(
-        &self,
-        function: inkwell::values::FunctionValue<'a>,
-        ty: T,
-        name: &str,
-    ) -> PointerValue<'a> {
-        let entry = function
-            .get_first_basic_block()
-            .expect("function missing entry block");
-        let current = self.builder.get_insert_block().unwrap();
-
-        if let Some(instr) = &entry.get_first_instruction() {
-            self.builder.position_before(instr);
-        } else {
-            // if there is no instruction yet, then nothing was built
-            self.builder.position_at_end(entry);
-        }
-
-        let res = self.builder.build_alloca(ty, name);
-
-        self.builder.position_at_end(current);
-
-        res
-    }
-
-    fn build_array_alloca<T: BasicType<'a>>(
-        &self,
-        function: inkwell::values::FunctionValue<'a>,
-        ty: T,
-        length: IntValue<'a>,
-        name: &str,
-    ) -> PointerValue<'a> {
-        let entry = function
-            .get_first_basic_block()
-            .expect("function missing entry block");
-        let current = self.builder.get_insert_block().unwrap();
-
-        if let Some(instr) = entry.get_first_instruction() {
-            self.builder.position_before(&instr);
-        } else {
-            self.builder.position_at_end(entry);
-        }
-
-        let res = self.builder.build_array_alloca(ty, length, name);
-
-        self.builder.position_at_end(current);
-
-        res
-    }
-
-    /// Emit a loop from `from` to `to`. The closure exists to insert the body of the loop; the closure
-    /// gets the loop variable passed to it as an IntValue, and a userdata PointerValue
-    pub fn emit_static_loop_with_pointer<F>(
-        &self,
-        function: FunctionValue,
-        from: IntValue<'a>,
-        to: IntValue<'a>,
-        data_ref: &mut PointerValue<'a>,
-        mut insert_body: F,
-    ) where
-        F: FnMut(IntValue<'a>, &mut PointerValue<'a>),
-    {
-        let body = self.context.append_basic_block(function, "body");
-        let done = self.context.append_basic_block(function, "done");
-        let entry = self.builder.get_insert_block().unwrap();
-
-        self.builder.build_unconditional_branch(body);
-        self.builder.position_at_end(body);
-
-        let loop_ty = from.get_type();
-        let loop_phi = self.builder.build_phi(loop_ty, "index");
-        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
-        let mut data = data_phi.as_basic_value().into_pointer_value();
-
-        let loop_var = loop_phi.as_basic_value().into_int_value();
-
-        // add loop body
-        insert_body(loop_var, &mut data);
-
-        let next = self
-            .builder
-            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
-
-        let comp = self
-            .builder
-            .build_int_compare(IntPredicate::ULT, next, to, "loop_cond");
-        self.builder.build_conditional_branch(comp, body, done);
-
-        let body = self.builder.get_insert_block().unwrap();
-        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
-        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
-
-        self.builder.position_at_end(done);
-
-        *data_ref = data;
-    }
-
-    /// Emit a loop from `from` to `to`. The closure exists to insert the body of the loop; the closure
-    /// gets the loop variable passed to it as an IntValue, and a userdata IntValue
-    pub fn emit_static_loop_with_int<F>(
-        &self,
-        function: FunctionValue,
-        from: IntValue<'a>,
-        to: IntValue<'a>,
-        data_ref: &mut IntValue<'a>,
-        mut insert_body: F,
-    ) where
-        F: FnMut(IntValue<'a>, &mut IntValue<'a>),
-    {
-        let body = self.context.append_basic_block(function, "body");
-        let done = self.context.append_basic_block(function, "done");
-        let entry = self.builder.get_insert_block().unwrap();
-
-        self.builder.build_unconditional_branch(body);
-        self.builder.position_at_end(body);
-
-        let loop_ty = from.get_type();
-        let loop_phi = self.builder.build_phi(loop_ty, "index");
-        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
-        let mut data = data_phi.as_basic_value().into_int_value();
-
-        let loop_var = loop_phi.as_basic_value().into_int_value();
-
-        // add loop body
-        insert_body(loop_var, &mut data);
-
-        let next = self
-            .builder
-            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
-
-        let comp = self
-            .builder
-            .build_int_compare(IntPredicate::ULT, next, to, "loop_cond");
-        self.builder.build_conditional_branch(comp, body, done);
-
-        let body = self.builder.get_insert_block().unwrap();
-        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
-        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
-
-        self.builder.position_at_end(done);
-
-        *data_ref = data;
-    }
-
-    /// Emit a loop from `from` to `to`, checking the condition _before_ the body.
-    pub fn emit_loop_cond_first_with_int<F>(
-        &self,
-        function: FunctionValue,
-        from: IntValue<'a>,
-        to: IntValue<'a>,
-        data_ref: &mut IntValue<'a>,
-        mut insert_body: F,
-    ) where
-        F: FnMut(IntValue<'a>, &mut IntValue<'a>),
-    {
-        let cond = self.context.append_basic_block(function, "cond");
-        let body = self.context.append_basic_block(function, "body");
-        let done = self.context.append_basic_block(function, "done");
-        let entry = self.builder.get_insert_block().unwrap();
-
-        self.builder.build_unconditional_branch(cond);
-        self.builder.position_at_end(cond);
-
-        let loop_ty = from.get_type();
-        let loop_phi = self.builder.build_phi(loop_ty, "index");
-        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
-        let mut data = data_phi.as_basic_value().into_int_value();
-
-        let loop_var = loop_phi.as_basic_value().into_int_value();
-
-        let next = self
-            .builder
-            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
-
-        let comp = self
-            .builder
-            .build_int_compare(IntPredicate::ULT, loop_var, to, "loop_cond");
-        self.builder.build_conditional_branch(comp, body, done);
-
-        self.builder.position_at_end(body);
-        // add loop body
-        insert_body(loop_var, &mut data);
-
-        let body = self.builder.get_insert_block().unwrap();
-
-        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
-        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
-
-        self.builder.build_unconditional_branch(cond);
-
-        self.builder.position_at_end(done);
-
-        *data_ref = data_phi.as_basic_value().into_int_value();
-    }
-
-    /// Emit a loop from `from` to `to`, checking the condition _before_ the body.
-    pub fn emit_loop_cond_first_with_pointer<F>(
-        &self,
-        function: FunctionValue,
-        from: IntValue<'a>,
-        to: IntValue<'a>,
-        data_ref: &mut PointerValue<'a>,
-        mut insert_body: F,
-    ) where
-        F: FnMut(IntValue<'a>, &mut PointerValue<'a>),
-    {
-        let cond = self.context.append_basic_block(function, "cond");
-        let body = self.context.append_basic_block(function, "body");
-        let done = self.context.append_basic_block(function, "done");
-        let entry = self.builder.get_insert_block().unwrap();
-
-        self.builder.build_unconditional_branch(cond);
-        self.builder.position_at_end(cond);
-
-        let loop_ty = from.get_type();
-        let loop_phi = self.builder.build_phi(loop_ty, "index");
-        let data_phi = self.builder.build_phi(data_ref.get_type(), "data");
-        let mut data = data_phi.as_basic_value().into_pointer_value();
-
-        let loop_var = loop_phi.as_basic_value().into_int_value();
-
-        let next = self
-            .builder
-            .build_int_add(loop_var, loop_ty.const_int(1, false), "next_index");
-
-        let comp = self
-            .builder
-            .build_int_compare(IntPredicate::ULT, loop_var, to, "loop_cond");
-        self.builder.build_conditional_branch(comp, body, done);
-
-        self.builder.position_at_end(body);
-        // add loop body
-        insert_body(loop_var, &mut data);
-
-        let body = self.builder.get_insert_block().unwrap();
-
-        loop_phi.add_incoming(&[(&from, entry), (&next, body)]);
-        data_phi.add_incoming(&[(&*data_ref, entry), (&data, body)]);
-
-        self.builder.build_unconditional_branch(cond);
-
-        self.builder.position_at_end(done);
-
-        *data_ref = data_phi.as_basic_value().into_pointer_value();
-    }
-
-    /// Convert a BigInt number to llvm const value
-    fn number_literal(&self, bits: u32, n: &BigInt, _ns: &Namespace) -> IntValue<'a> {
-        let ty = self.context.custom_width_int_type(bits);
-        let s = n.to_string();
-
-        ty.const_int_from_string(&s, StringRadix::Decimal).unwrap()
-    }
-
-    /// Emit function prototype
-    fn function_type(&self, params: &[Type], returns: &[Type], ns: &Namespace) -> FunctionType<'a> {
-        // function parameters
-        let mut args = params
-            .iter()
-            .map(|ty| self.llvm_var_ty(ty, ns).into())
-            .collect::<Vec<BasicMetadataTypeEnum>>();
-
-        // add return values
-        for ty in returns {
-            args.push(if ty.is_reference_type(ns) && !ty.is_contract_storage() {
-                self.llvm_type(ty, ns)
-                    .ptr_type(AddressSpace::Generic)
-                    .ptr_type(AddressSpace::Generic)
-                    .into()
-            } else {
-                self.llvm_type(ty, ns)
-                    .ptr_type(AddressSpace::Generic)
-                    .into()
-            });
-        }
-
-        // On Solana, we need to pass around the accounts
-        if ns.target == Target::Solana {
-            args.push(
-                self.module
-                    .get_struct_type("struct.SolParameters")
-                    .unwrap()
-                    .ptr_type(AddressSpace::Generic)
-                    .into(),
-            );
-        }
-
-        // Solana return type should be 64 bit, 32 bit on wasm
-        self.return_values[&ReturnCode::Success]
-            .get_type()
-            .fn_type(&args, false)
-    }
-
-    // Create the llvm intrinsic for counting leading zeros
-    pub fn llvm_ctlz(&self, bit: u32) -> FunctionValue<'a> {
-        let name = format!("llvm.ctlz.i{}", bit);
-        let ty = self.context.custom_width_int_type(bit);
-
-        if let Some(f) = self.module.get_function(&name) {
-            return f;
-        }
-
-        self.module.add_function(
-            &name,
-            ty.fn_type(&[ty.into(), self.context.bool_type().into()], false),
-            None,
-        )
-    }
-
-    // Create the llvm intrinsic for bswap
-    pub fn llvm_bswap(&self, bit: u32) -> FunctionValue<'a> {
-        let name = format!("llvm.bswap.i{}", bit);
-        let ty = self.context.custom_width_int_type(bit);
-
-        if let Some(f) = self.module.get_function(&name) {
-            return f;
-        }
-
-        self.module
-            .add_function(&name, ty.fn_type(&[ty.into()], false), None)
-    }
-
-    // Create the llvm intrinsic for overflows
-    pub fn llvm_overflow(
-        &self,
-        ret_ty: BasicTypeEnum<'a>,
-        ty: IntType<'a>,
-        signed: bool,
-        op: BinaryOp,
-    ) -> FunctionValue<'a> {
-        let bit = ty.get_bit_width();
-        let name = format!(
-            "llvm.{}{}.with.overflow.i{}",
-            if signed { "s" } else { "u" },
-            op,
-            bit,
-        );
-
-        if let Some(f) = self.module.get_function(&name) {
-            return f;
-        }
-
-        self.module
-            .add_function(&name, ret_ty.fn_type(&[ty.into(), ty.into()], false), None)
-    }
-
-    /// Return the llvm type for a variable holding the type, not the type itself
-    fn llvm_var_ty(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
-        let llvm_ty = self.llvm_type(ty, ns);
-        match ty.deref_memory() {
-            Type::Struct(_) | Type::Array(..) | Type::DynamicBytes | Type::String => {
-                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
-            }
-            _ => llvm_ty,
-        }
-    }
-
-    /// Default empty value
-    fn default_value(&self, ty: &Type, ns: &Namespace) -> BasicValueEnum<'a> {
-        let llvm_ty = self.llvm_var_ty(ty, ns);
-
-        // const_zero() on BasicTypeEnum yet. Should be coming to inkwell soon
-        if llvm_ty.is_pointer_type() {
-            llvm_ty.into_pointer_type().const_null().into()
-        } else if llvm_ty.is_array_type() {
-            self.address_type(ns).const_zero().into()
-        } else {
-            llvm_ty.into_int_type().const_zero().into()
-        }
-    }
-
-    /// Return the llvm type for field in struct or array
-    fn llvm_field_ty(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
-        let llvm_ty = self.llvm_type(ty, ns);
-        match ty.deref_memory() {
-            Type::Array(_, dim) if dim[0].is_none() => {
-                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
-            }
-            Type::DynamicBytes | Type::String => {
-                llvm_ty.ptr_type(AddressSpace::Generic).as_basic_type_enum()
-            }
-            _ => llvm_ty,
-        }
-    }
-
-    /// Return the llvm type for the resolved type.
-    fn llvm_type(&self, ty: &Type, ns: &Namespace) -> BasicTypeEnum<'a> {
-        if ty.builtin_struct(ns) == BuiltinStruct::AccountInfo {
-            return self
-                .module
-                .get_struct_type("struct.SolAccountInfo")
-                .unwrap()
-                .into();
-        } else {
-            match ty {
-                Type::Bool => BasicTypeEnum::IntType(self.context.bool_type()),
-                Type::Int(n) | Type::Uint(n) => {
-                    BasicTypeEnum::IntType(self.context.custom_width_int_type(*n as u32))
-                }
-                Type::Value => BasicTypeEnum::IntType(
-                    self.context
-                        .custom_width_int_type(ns.value_length as u32 * 8),
-                ),
-                Type::Contract(_) | Type::Address(_) => {
-                    BasicTypeEnum::ArrayType(self.address_type(ns))
-                }
-                Type::Bytes(n) => {
-                    BasicTypeEnum::IntType(self.context.custom_width_int_type(*n as u32 * 8))
-                }
-                Type::Enum(n) => self.llvm_type(&ns.enums[*n].ty, ns),
-                Type::String | Type::DynamicBytes => {
-                    self.module.get_struct_type("struct.vector").unwrap().into()
-                }
-                Type::Array(base_ty, dims) => {
-                    let ty = self.llvm_field_ty(base_ty, ns);
-
-                    let mut dims = dims.iter();
-
-                    let mut aty = match dims.next().unwrap() {
-                        Some(d) => ty.array_type(d.to_u32().unwrap()),
-                        None => {
-                            return self.module.get_struct_type("struct.vector").unwrap().into()
-                        }
-                    };
-
-                    for dim in dims {
-                        match dim {
-                            Some(d) => aty = aty.array_type(d.to_u32().unwrap()),
-                            None => {
-                                return self.module.get_struct_type("struct.vector").unwrap().into()
-                            }
-                        }
-                    }
-
-                    BasicTypeEnum::ArrayType(aty)
-                }
-                Type::Struct(n) => self
-                    .context
-                    .struct_type(
-                        &ns.structs[*n]
-                            .fields
-                            .iter()
-                            .map(|f| self.llvm_field_ty(&f.ty, ns))
-                            .collect::<Vec<BasicTypeEnum>>(),
-                        false,
-                    )
-                    .as_basic_type_enum(),
-                Type::Mapping(..) => unreachable!(),
-                Type::Ref(r) => self
-                    .llvm_type(r, ns)
-                    .ptr_type(AddressSpace::Generic)
-                    .as_basic_type_enum(),
-                Type::StorageRef(..) => self.llvm_type(&ns.storage_type(), ns),
-                Type::InternalFunction {
-                    params, returns, ..
-                } => {
-                    let ftype = self.function_type(params, returns, ns);
-
-                    BasicTypeEnum::PointerType(ftype.ptr_type(AddressSpace::Generic))
-                }
-                Type::ExternalFunction { .. } => {
-                    let address = self.llvm_type(&Type::Address(false), ns);
-                    let selector = self.llvm_type(&Type::Uint(32), ns);
-
-                    BasicTypeEnum::PointerType(
-                        self.context
-                            .struct_type(&[address, selector], false)
-                            .ptr_type(AddressSpace::Generic),
-                    )
-                }
-                Type::Slice => BasicTypeEnum::StructType(
-                    self.context.struct_type(
-                        &[
-                            self.context
-                                .i8_type()
-                                .ptr_type(AddressSpace::Generic)
-                                .into(),
-                            self.context.i32_type().into(),
-                        ],
-                        false,
-                    ),
-                ),
-                Type::UserType(no) => self.llvm_type(&ns.user_types[*no].ty, ns),
-                _ => unreachable!(),
-            }
-        }
-    }
-
-    /// ewasm deployer needs to know what its own code size is, so we compile once to
-    /// get the size, patch in the value and then recompile.
-    fn patch_code_size(&self, code_size: u64) -> bool {
-        let current_size = {
-            let current_size_opt = self.code_size.borrow();
-
-            if let Some(current_size) = *current_size_opt {
-                if code_size == current_size.get_zero_extended_constant().unwrap() {
-                    return false;
-                }
-
-                current_size
-            } else {
-                return false;
-            }
-        };
-
-        let new_size = self.context.i32_type().const_int(code_size, false);
-
-        current_size.replace_all_uses_with(new_size);
-
-        self.code_size.replace(Some(new_size));
-
-        true
-    }
-
-    /// Allocate vector
-    fn vector_new(
-        &self,
-        size: IntValue<'a>,
-        elem_size: IntValue<'a>,
-        init: Option<&Vec<u8>>,
-    ) -> PointerValue<'a> {
-        if let Some(init) = init {
-            if init.is_empty() {
-                return self
-                    .module
-                    .get_struct_type("struct.vector")
-                    .unwrap()
-                    .ptr_type(AddressSpace::Generic)
-                    .const_null();
-            }
-        }
-
-        let init = match init {
-            None => self.builder.build_int_to_ptr(
-                self.context.i32_type().const_all_ones(),
-                self.context.i8_type().ptr_type(AddressSpace::Generic),
-                "invalid",
-            ),
-            Some(s) => self.emit_global_string("const_string", s, true),
-        };
-
-        let v = self
-            .builder
-            .build_call(
-                self.module.get_function("vector_new").unwrap(),
-                &[size.into(), elem_size.into(), init.into()],
-                "",
-            )
-            .try_as_basic_value()
-            .left()
-            .unwrap();
-
-        self.builder.build_pointer_cast(
-            v.into_pointer_value(),
-            self.module
-                .get_struct_type("struct.vector")
-                .unwrap()
-                .ptr_type(AddressSpace::Generic),
-            "vector",
-        )
-    }
-
-    /// Number of element in a vector
-    fn vector_len(&self, vector: BasicValueEnum<'a>) -> IntValue<'a> {
-        if vector.is_struct_value() {
-            // slice
-            let slice = vector.into_struct_value();
-
-            self.builder
-                .build_extract_value(slice, 1, "slice_len")
-                .unwrap()
-                .into_int_value()
-        } else {
-            let struct_ty = vector
-                .into_pointer_value()
-                .get_type()
-                .get_element_type()
-                .into_struct_type();
-            let name = struct_ty.get_name().unwrap();
-
-            if name == CStr::from_bytes_with_nul(b"struct.SolAccountInfo\0").unwrap() {
-                // load the data pointer
-                let data = self
-                    .builder
-                    .build_load(
-                        self.builder
-                            .build_struct_gep(vector.into_pointer_value(), 3, "data")
-                            .unwrap(),
-                        "data",
-                    )
-                    .into_pointer_value();
-
-                // get the offset of the return data
-                let header_ptr = self.builder.build_pointer_cast(
-                    data,
-                    self.context.i32_type().ptr_type(AddressSpace::Generic),
-                    "header_ptr",
-                );
-
-                let data_len_ptr = unsafe {
-                    self.builder.build_gep(
-                        header_ptr,
-                        &[self.context.i64_type().const_int(1, false)],
-                        "data_len_ptr",
-                    )
-                };
-
-                self.builder
-                    .build_load(data_len_ptr, "len")
-                    .into_int_value()
-            } else {
-                // field 0 is the length
-                let vector = vector.into_pointer_value();
-
-                let len = unsafe {
-                    self.builder.build_gep(
-                        vector,
-                        &[
-                            self.context.i32_type().const_zero(),
-                            self.context.i32_type().const_zero(),
-                        ],
-                        "vector_len",
-                    )
-                };
-
-                self.builder
-                    .build_select(
-                        self.builder.build_is_null(vector, "vector_is_null"),
-                        self.context.i32_type().const_zero(),
-                        self.builder.build_load(len, "vector_len").into_int_value(),
-                        "length",
-                    )
-                    .into_int_value()
-            }
-        }
-    }
-
-    /// Return the pointer to the actual bytes in the vector
-    fn vector_bytes(&self, vector: BasicValueEnum<'a>) -> PointerValue<'a> {
-        if vector.is_struct_value() {
-            // slice
-            let slice = vector.into_struct_value();
-
-            self.builder
-                .build_extract_value(slice, 0, "slice_data")
-                .unwrap()
-                .into_pointer_value()
-        } else {
-            let data = unsafe {
-                self.builder.build_gep(
-                    vector.into_pointer_value(),
-                    &[
-                        self.context.i32_type().const_zero(),
-                        self.context.i32_type().const_int(2, false),
-                    ],
-                    "data",
-                )
-            };
-
-            self.builder.build_pointer_cast(
-                data,
-                self.context.i8_type().ptr_type(AddressSpace::Generic),
-                "data",
-            )
-        }
-    }
-
-    /// Dereference an array
-    fn array_subscript(
-        &self,
-        array_ty: &Type,
-        array: PointerValue<'a>,
-        index: IntValue<'a>,
-        ns: &Namespace,
-    ) -> PointerValue<'a> {
-        match array_ty {
-            Type::Array(_, dim) => {
-                if dim[0].is_some() {
-                    // fixed size array
-                    unsafe {
-                        self.builder.build_gep(
-                            array,
-                            &[self.context.i32_type().const_zero(), index],
-                            "index_access",
-                        )
-                    }
-                } else {
-                    let elem_ty = array_ty.array_deref();
-                    let llvm_elem_ty = self.llvm_field_ty(&elem_ty, ns);
-
-                    // dynamic length array or vector
-                    let index = self.builder.build_int_mul(
-                        index,
-                        llvm_elem_ty
-                            .into_pointer_type()
-                            .get_element_type()
-                            .size_of()
-                            .unwrap()
-                            .const_cast(self.context.i32_type(), false),
-                        "",
-                    );
-
-                    let elem = unsafe {
-                        self.builder.build_gep(
-                            array,
-                            &[
-                                self.context.i32_type().const_zero(),
-                                self.context.i32_type().const_int(2, false),
-                                index,
-                            ],
-                            "index_access",
-                        )
-                    };
-
-                    self.builder
-                        .build_pointer_cast(elem, llvm_elem_ty.into_pointer_type(), "elem")
-                }
-            }
-            _ => unreachable!(),
-        }
-    }
-}
-
-static BPF_IR: [&[u8]; 5] = [
-    include_bytes!("../../stdlib/bpf/stdlib.bc"),
-    include_bytes!("../../stdlib/bpf/bigint.bc"),
-    include_bytes!("../../stdlib/bpf/format.bc"),
-    include_bytes!("../../stdlib/bpf/solana.bc"),
-    include_bytes!("../../stdlib/bpf/ripemd160.bc"),
-];
-
-static WASM_IR: [&[u8]; 4] = [
-    include_bytes!("../../stdlib/wasm/stdlib.bc"),
-    include_bytes!("../../stdlib/wasm/wasmheap.bc"),
-    include_bytes!("../../stdlib/wasm/bigint.bc"),
-    include_bytes!("../../stdlib/wasm/format.bc"),
-];
-
-static RIPEMD160_IR: &[u8] = include_bytes!("../../stdlib/wasm/ripemd160.bc");
-static SUBSTRATE_IR: &[u8] = include_bytes!("../../stdlib/wasm/substrate.bc");
-
-/// Return the stdlib as parsed llvm module. The solidity standard library is hardcoded into
-/// the solang library
-fn load_stdlib<'a>(context: &'a Context, target: &Target) -> Module<'a> {
-    if *target == Target::Solana {
-        let memory = MemoryBuffer::create_from_memory_range(BPF_IR[0], "bpf_bc");
-
-        let module = Module::parse_bitcode_from_buffer(&memory, context).unwrap();
-
-        for bc in BPF_IR.iter().skip(1) {
-            let memory = MemoryBuffer::create_from_memory_range(bc, "bpf_bc");
-
-            module
-                .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
-                .unwrap();
-        }
-
-        return module;
-    }
-
-    let memory = MemoryBuffer::create_from_memory_range(WASM_IR[0], "wasm_bc");
-
-    let module = Module::parse_bitcode_from_buffer(&memory, context).unwrap();
-
-    for bc in WASM_IR.iter().skip(1) {
-        let memory = MemoryBuffer::create_from_memory_range(bc, "wasm_bc");
-
-        module
-            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
-            .unwrap();
-    }
-
-    if let Target::Substrate { .. } = *target {
-        let memory = MemoryBuffer::create_from_memory_range(SUBSTRATE_IR, "substrate");
-
-        module
-            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
-            .unwrap();
-
-        // substrate does not provide ripemd160
-        let memory = MemoryBuffer::create_from_memory_range(RIPEMD160_IR, "ripemd160");
-
-        module
-            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
-            .unwrap();
-    }
-
-    module
-}
-
 impl Target {
     /// LLVM Target name
     fn llvm_target_name(&self) -> &'static str {

+ 3 - 3
src/emit/solana.rs

@@ -15,9 +15,9 @@ use inkwell::{context::Context, types::BasicTypeEnum};
 use inkwell::{AddressSpace, IntPredicate, OptimizationLevel};
 use num_traits::ToPrimitive;
 
-use super::ethabiencoder;
-use super::loop_builder::LoopBuilder;
-use super::{Binary, ReturnCode, TargetRuntime, Variable};
+use crate::emit::ethabiencoder;
+use crate::emit::loop_builder::LoopBuilder;
+use crate::emit::{Binary, ReturnCode, TargetRuntime, Variable};
 
 pub struct SolanaTarget {
     abi: ethabiencoder::EthAbiDecoder,

+ 1 - 1
src/emit/substrate.rs

@@ -15,7 +15,7 @@ use num_traits::ToPrimitive;
 use std::collections::HashMap;
 use std::convert::TryFrom;
 
-use super::{Binary, TargetRuntime, Variable};
+use crate::emit::{Binary, TargetRuntime, Variable};
 
 // When using the seal api, we use our own scratch buffer.
 const SCRATCH_SIZE: u32 = 32 * 1024;

+ 2 - 2
src/lib.rs

@@ -157,8 +157,8 @@ pub fn compile_many<'a>(
     filename: &str,
     opt: inkwell::OptimizationLevel,
     math_overflow_check: bool,
-) -> emit::Binary<'a> {
-    emit::Binary::build_bundle(context, namespaces, filename, opt, math_overflow_check)
+) -> emit::binary::Binary<'a> {
+    emit::binary::Binary::build_bundle(context, namespaces, filename, opt, math_overflow_check)
 }
 
 /// Parse and resolve the Solidity source code provided in src, for the target chain as specified in target.

+ 2 - 2
src/sema/contracts.rs

@@ -53,8 +53,8 @@ impl ast::Contract {
         filename: &'a str,
         opt: inkwell::OptimizationLevel,
         math_overflow_check: bool,
-    ) -> emit::Binary {
-        emit::Binary::build(context, self, ns, filename, opt, math_overflow_check)
+    ) -> emit::binary::Binary {
+        emit::binary::Binary::build(context, self, ns, filename, opt, math_overflow_check)
     }
 
     /// Selector for this contract. This is used by Solana contract bundle

+ 17 - 11
tests/contract.rs

@@ -8,20 +8,26 @@ use std::{
 };
 
 #[test]
-fn contract_tests() -> io::Result<()> {
-    let targets = read_dir("tests/contract_testcases")?;
+fn solana_contracts() -> io::Result<()> {
+    contract_tests("tests/contract_testcases/solana", Target::Solana)
+}
 
-    for target in targets {
-        let path = target?.path();
+#[test]
+fn substrate_contracts() -> io::Result<()> {
+    contract_tests(
+        "tests/contract_testcases/substrate",
+        Target::default_substrate(),
+    )
+}
 
-        if let Some(filename) = path.file_name() {
-            if let Some(target) = Target::from(&filename.to_string_lossy()) {
-                recurse_directory(path, target)?;
-            }
-        }
-    }
+#[test]
+fn ewasm_contracts() -> io::Result<()> {
+    contract_tests("tests/contract_testcases/ewasm", Target::Ewasm)
+}
 
-    Ok(())
+fn contract_tests(file_path: &str, target: Target) -> io::Result<()> {
+    let path = PathBuf::from(file_path);
+    recurse_directory(path, target)
 }
 
 fn recurse_directory(path: PathBuf, target: Target) -> io::Result<()> {