Sfoglia il codice sorgente

Add option for emitting assembly

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 4 anni fa
parent
commit
a3f30647aa
7 ha cambiato i file con 67 aggiunte e 15 eliminazioni
  1. 3 0
      docs/running.rst
  2. 29 3
      src/bin/solang.rs
  3. 2 1
      src/codegen/mod.rs
  4. 5 2
      src/emit/ewasm.rs
  5. 21 7
      src/emit/mod.rs
  6. 3 1
      src/lib.rs
  7. 4 1
      tests/solana.rs

+ 3 - 0
docs/running.rst

@@ -79,6 +79,9 @@ Options:
   llvm-bc
     Output llvm bitcode as binary file.
 
+  asm
+    Output assembly text file.
+
   object
     Output wasm object file; this is the contract before final linking.
 

+ 29 - 3
src/bin/solang.rs

@@ -8,6 +8,7 @@ use std::path::{Path, PathBuf};
 
 use solang::abi;
 use solang::codegen::{codegen, Options};
+use solang::emit::Generate;
 use solang::file_cache::FileCache;
 use solang::sema::{ast::Namespace, diagnostics};
 
@@ -48,7 +49,7 @@ fn main() {
                 .help("Emit compiler state at early stage")
                 .long("emit")
                 .takes_value(true)
-                .possible_values(&["ast", "cfg", "llvm-ir", "llvm-bc", "object"]),
+                .possible_values(&["ast", "cfg", "llvm-ir", "llvm-bc", "object", "asm"]),
         )
         .arg(
             Arg::with_name("OPT")
@@ -287,7 +288,9 @@ fn main() {
                     );
                 }
 
-                let code = binary.code(true).expect("llvm code emit should work");
+                let code = binary
+                    .code(Generate::Linked)
+                    .expect("llvm code emit should work");
 
                 let mut file = match File::create(&bin_filename) {
                     Ok(file) => file,
@@ -589,7 +592,7 @@ fn save_intermediates(binary: &solang::emit::Binary, matches: &ArgMatches) -> bo
         }
 
         Some("object") => {
-            let obj = match binary.code(false) {
+            let obj = match binary.code(Generate::Object) {
                 Ok(o) => o,
                 Err(s) => {
                     println!("error: {}", s);
@@ -611,6 +614,29 @@ fn save_intermediates(binary: &solang::emit::Binary, matches: &ArgMatches) -> bo
             file.write_all(&obj).unwrap();
             true
         }
+        Some("asm") => {
+            let obj = match binary.code(Generate::Assembly) {
+                Ok(o) => o,
+                Err(s) => {
+                    println!("error: {}", s);
+                    std::process::exit(1);
+                }
+            };
+
+            let obj_filename = output_file(matches, &binary.name, "asm");
+
+            if verbose {
+                eprintln!(
+                    "info: Saving Assembly {} for contract {}",
+                    obj_filename.display(),
+                    binary.name
+                );
+            }
+
+            let mut file = File::create(obj_filename).unwrap();
+            file.write_all(&obj).unwrap();
+            true
+        }
         Some("cfg") => true,
         Some("ast") => true,
         _ => false,

+ 2 - 1
src/codegen/mod.rs

@@ -13,6 +13,7 @@ mod vector_to_slice;
 
 use self::cfg::{optimize_and_check_cfg, ControlFlowGraph, Instr, Vartable};
 use self::expression::expression;
+use crate::emit::Generate;
 use crate::sema::ast::{Layout, Namespace};
 use crate::sema::contracts::visit_bases;
 use crate::sema::diagnostics::any_errors;
@@ -98,7 +99,7 @@ pub fn codegen(ns: &mut Namespace, opt: &Options) {
                     opt.math_overflow_check,
                 );
 
-                let code = binary.code(true).expect("llvm build");
+                let code = binary.code(Generate::Linked).expect("llvm build");
 
                 drop(binary);
 

+ 5 - 2
src/emit/ewasm.rs

@@ -17,6 +17,7 @@ use tiny_keccak::{Hasher, Keccak};
 
 use super::ethabiencoder;
 use super::{Binary, TargetRuntime, Variable};
+use crate::emit::Generate;
 
 pub struct EwasmTarget {
     abi: ethabiencoder::EthAbiDecoder,
@@ -58,7 +59,7 @@ impl EwasmTarget {
 
         runtime_code.internalize(&["main"]);
 
-        let runtime_bs = runtime_code.code(true).unwrap();
+        let runtime_bs = runtime_code.code(Generate::Linked).unwrap();
 
         // Now we have the runtime code, create the deployer
         let mut b = EwasmTarget {
@@ -1239,7 +1240,9 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
         );
 
         // wasm
-        let wasm = target_binary.code(true).expect("compile should succeeed");
+        let wasm = target_binary
+            .code(Generate::Linked)
+            .expect("compile should succeeed");
 
         let code = binary.emit_global_string(
             &format!("contract_{}_code", resolver_binary.name),

+ 21 - 7
src/emit/mod.rs

@@ -1166,10 +1166,12 @@ pub trait TargetRuntime<'a> {
                     target_bin
                         .runtime
                         .unwrap()
-                        .code(true)
+                        .code(Generate::Linked)
                         .expect("compile should succeeed")
                 } else {
-                    target_bin.code(true).expect("compile should succeeed")
+                    target_bin
+                        .code(Generate::Linked)
+                        .expect("compile should succeeed")
                 };
 
                 let size = bin.context.i32_type().const_int(code.len() as u64, false);
@@ -5227,6 +5229,13 @@ enum ReturnCode {
     AbiEncodingInvalid,
 }
 
+#[derive(PartialEq)]
+pub enum Generate {
+    Object,
+    Assembly,
+    Linked,
+}
+
 impl<'a> Binary<'a> {
     /// Build the LLVM IR for a single contract
     pub fn build(
@@ -5288,7 +5297,7 @@ impl<'a> Binary<'a> {
     /// 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, linking: bool) -> Result<Vec<u8>, String> {
+    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());
@@ -5328,11 +5337,18 @@ impl<'a> Binary<'a> {
             // until it is right.
 
             // The correct solution is to make ewasm less insane.
-            match target_machine.write_to_memory_buffer(&self.module, FileType::Object) {
+            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 linking {
+                    if generate == Generate::Linked {
                         let bs = link(slice, &self.name, self.target);
 
                         if !self.patch_code_size(bs.len() as u64) {
@@ -5341,8 +5357,6 @@ impl<'a> Binary<'a> {
                             return Ok(bs.to_vec());
                         }
                     } else {
-                        self.code.replace(slice.to_vec());
-
                         return Ok(slice.to_vec());
                     }
                 }

+ 3 - 1
src/lib.rs

@@ -82,7 +82,9 @@ pub fn compile(
                 math_overflow_check,
             );
 
-            let bc = binary.code(true).expect("llvm code emit should work");
+            let bc = binary
+                .code(emit::Generate::Linked)
+                .expect("llvm code emit should work");
 
             let (abistr, _) = abi::generate_abi(c, &ns, &bc, false);
 

+ 4 - 1
tests/solana.rs

@@ -21,6 +21,7 @@ use solang::{
     abi::generate_abi,
     codegen::{codegen, Options},
     compile_many,
+    emit::Generate,
     file_cache::FileCache,
     sema::{ast, diagnostics},
     Target,
@@ -131,7 +132,9 @@ fn build_solidity(src: &str) -> VirtualMachine {
         false,
     );
 
-    let code = binary.code(true).expect("llvm code emit should work");
+    let code = binary
+        .code(Generate::Linked)
+        .expect("llvm code emit should work");
 
     let mut account_data = HashMap::new();
     let mut programs = Vec::new();