From 549a788eddabbdee8a12d975b2ea454ac9e34cdb Mon Sep 17 00:00:00 2001 From: Toby Hutton Date: Fri, 18 Feb 2022 16:18:37 +1100 Subject: [PATCH 1/4] Introduce IrError and use it for most Results in the library. --- sway-ir/src/bin/opt.rs | 37 ++++++++++++++++---- sway-ir/src/context.rs | 5 +-- sway-ir/src/error.rs | 44 ++++++++++++++++++++++++ sway-ir/src/function.rs | 31 +++++++++-------- sway-ir/src/lib.rs | 2 ++ sway-ir/src/metadata.rs | 13 +++---- sway-ir/src/optimize/constants.rs | 3 +- sway-ir/src/optimize/inline.rs | 5 +-- sway-ir/src/parser.rs | 11 +++--- sway-ir/src/verify.rs | 57 ++++++++++++++++--------------- 10 files changed, 142 insertions(+), 66 deletions(-) create mode 100644 sway-ir/src/error.rs diff --git a/sway-ir/src/bin/opt.rs b/sway-ir/src/bin/opt.rs index dc36f9e1237..8510e62465b 100644 --- a/sway-ir/src/bin/opt.rs +++ b/sway-ir/src/bin/opt.rs @@ -3,26 +3,29 @@ use std::{ io::{BufReader, BufWriter, Error, ErrorKind, Read, Write}, }; -use sway_ir::{function::Function, optimize, Context}; +use sway_ir::{error::IrError, function::Function, optimize, Context}; // ------------------------------------------------------------------------------------------------- fn main() -> std::io::Result<()> { - let str_to_err = |msg| Error::new(ErrorKind::Other, msg); + fn to_err(err: S) -> Error { + Error::new(ErrorKind::Other, err.to_string()) + } // Build the config from the command line. - let config = ConfigBuilder::build(std::env::args()).map_err(&str_to_err)?; + let config = ConfigBuilder::build(std::env::args()).map_err(&to_err)?; // Read the input file, or standard in. let input_str = read_from_input(&config.input_path)?; // Parse it. XXX Improve this error message too. - let mut ir = sway_ir::parser::parse(&input_str).map_err(&str_to_err)?; + let mut ir = sway_ir::parser::parse(&input_str).map_err(&to_err)?; // Perform optimisation passes in order. for pass in config.passes { match pass.name.as_ref() { - "inline" => perform_inline(&mut ir).map_err(&str_to_err)?, + "inline" => perform_inline(&mut ir).map_err(&to_err)?, + "constcombine" => perform_combine_constants(&mut ir).map_err(&to_err)?, _otherwise => unreachable!("Unknown pass name: {}", pass.name), }; } @@ -62,7 +65,7 @@ fn write_to_output>(ir_str: S, path_str: &Option) -> std // ------------------------------------------------------------------------------------------------- -fn perform_inline(ir: &mut Context) -> Result { +fn perform_inline(ir: &mut Context) -> Result { // For now we inline everything into `main()`. Eventually we can be more selective. let main_fn = ir .functions @@ -72,6 +75,19 @@ fn perform_inline(ir: &mut Context) -> Result { optimize::inline_all_function_calls(ir, &Function(main_fn)) } +// ------------------------------------------------------------------------------------------------- + +fn perform_combine_constants(ir: &mut Context) -> Result { + let funcs = ir.functions.iter().map(|(idx, _)| idx).collect::>(); + let mut modified = false; + for idx in funcs { + if optimize::combine_constants(ir, &Function(idx))? { + modified = true; + } + } + Ok(modified) +} + // ------------------------------------------------------------------------------------------------- // Using a bespoke CLI parser since the order in which passes are specified is important. @@ -133,6 +149,7 @@ impl> ConfigBuilder { "-o" => self.build_output(), "inline" => self.build_inline_pass(), + "constcombine" => self.build_const_combine_pass(), _otherwise => Err(format!("Unrecognised option '{}'.", opt)), } @@ -169,6 +186,14 @@ impl> ConfigBuilder { self.next = self.rest.next(); self.build_root() } + + fn build_const_combine_pass(mut self) -> Result { + // No args yet. Eventually we should allow specifying which functions should have consts + // combined. + self.cfg.passes.push("constcombine".into()); + self.next = self.rest.next(); + self.build_root() + } } // ------------------------------------------------------------------------------------------------- diff --git a/sway-ir/src/context.rs b/sway-ir/src/context.rs index 31acddfb9fd..491cd749673 100644 --- a/sway-ir/src/context.rs +++ b/sway-ir/src/context.rs @@ -13,6 +13,7 @@ use generational_arena::Arena; use crate::{ asm::AsmBlockContent, block::BlockContent, + error::IrError, function::FunctionContent, irtype::{AbiInstanceContent, Aggregate, AggregateContent}, metadata::Metadatum, @@ -59,10 +60,10 @@ impl Context { &mut self, aggregate: Aggregate, symbols: HashMap, - ) -> Result<(), String> { + ) -> Result<(), IrError> { match self.aggregate_symbols.insert(aggregate, symbols) { None => Ok(()), - Some(_) => Err("Aggregate symbols were overwritten/shadowed.".into()), + Some(_) => Err(IrError::ShadowedAggregates), } } diff --git a/sway-ir/src/error.rs b/sway-ir/src/error.rs new file mode 100644 index 00000000000..c87c9b8aff8 --- /dev/null +++ b/sway-ir/src/error.rs @@ -0,0 +1,44 @@ +#[derive(Debug)] +pub enum IrError { + FunctionLocalClobbered(String, String), + InvalidMetadatum, + MismatchedReturnTypes(String), + MisplacedTerminator(String), + MissingBlock(String), + MissingTerminator(String), + NonUniquePhiLabels, + ParseFailure(String, String), + ShadowedAggregates, +} + +use std::fmt; + +impl fmt::Display for IrError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self { + IrError::FunctionLocalClobbered(fn_str, var_str) => write!( + f, + "Local storage for function {fn_str} already has an entry for variable {var_str}" + ), + IrError::InvalidMetadatum => write!(f, "Unable to convert from invalid metadatum."), + IrError::MismatchedReturnTypes(fn_str) => write!( + f, + "Function {fn_str} return type must match its RET instructions." + ), + IrError::MisplacedTerminator(blk_str) => { + write!(f, "Block {blk_str} has a misplaced terminator.") + } + IrError::MissingBlock(blk_str) => write!(f, "Unable to find block {blk_str}."), + IrError::MissingTerminator(blk_str) => { + write!(f, "Block {blk_str} is missing its terminator.") + } + IrError::NonUniquePhiLabels => write!(f, "PHI must have unique block labels."), + IrError::ParseFailure(expecting, found) => { + write!(f, "Parse failure: expecting '{expecting}', found '{found}'") + } + IrError::ShadowedAggregates => { + write!(f, "Aggregate symbols were overwritten/shadowed.") + } + } + } +} diff --git a/sway-ir/src/function.rs b/sway-ir/src/function.rs index d47e140fc02..c319a8497f1 100644 --- a/sway-ir/src/function.rs +++ b/sway-ir/src/function.rs @@ -12,6 +12,7 @@ use crate::{ block::{Block, BlockIterator, Label}, constant::Constant, context::Context, + error::IrError, irtype::Type, metadata::MetadataIndex, module::Module, @@ -100,7 +101,7 @@ impl Function { context: &mut Context, other: &Block, label: Option