Skip to content

Commit

Permalink
Generalise IR metadata. (FuelLabs#2394)
Browse files Browse the repository at this point in the history
* Generalise the IR metadata.

Instead of knowing of specific IR like `Span` or `StateIndex` it now has
a simple general representation of numbers, strings, references to other
metadata and structs.

Also, only a single metadatum reference may be attached to an IR value
or function at a time.  If multiple metadata are needed then they may be
aggregated in a `List` metadatum.

* Use the new generalised IR metadata in IR generation.

To minimise redundancy a new `MetadataManager` full of `HashMap` caches
is used to track previously created or converted metadata, in both the
IR generation and ASM generation.

* Update the test suite to handle the generalised metadata.
  • Loading branch information
otrho authored Jul 27, 2022
1 parent 79d8caa commit dcaee96
Show file tree
Hide file tree
Showing 33 changed files with 2,061 additions and 1,968 deletions.
290 changes: 117 additions & 173 deletions sway-core/src/asm_generation/from_ir.rs

Large diffs are not rendered by default.

68 changes: 30 additions & 38 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
error::CompileError,
parse_tree::{Purity, Visibility},
metadata::MetadataManager,
parse_tree::Visibility,
semantic_analysis::{ast_node::*, namespace},
};

Expand All @@ -10,7 +11,7 @@ use super::{
function::FnCompiler,
};

use sway_ir::*;
use sway_ir::{metadata::combine as md_combine, *};
use sway_types::{span::Span, Spanned};

pub(super) fn compile_script(
Expand All @@ -20,10 +21,11 @@ pub(super) fn compile_script(
declarations: Vec<TypedDeclaration>,
) -> Result<Module, CompileError> {
let module = Module::new(context, Kind::Script);
let mut md_mgr = MetadataManager::default();

compile_constants(context, module, namespace, false)?;
compile_declarations(context, module, namespace, declarations)?;
compile_function(context, module, main_function)?;
compile_constants(context, &mut md_mgr, module, namespace)?;
compile_declarations(context, &mut md_mgr, module, namespace, declarations)?;
compile_function(context, &mut md_mgr, module, main_function)?;

Ok(module)
}
Expand All @@ -35,37 +37,38 @@ pub(super) fn compile_contract(
declarations: Vec<TypedDeclaration>,
) -> Result<Module, CompileError> {
let module = Module::new(context, Kind::Contract);
let mut md_mgr = MetadataManager::default();

compile_constants(context, module, namespace, false)?;
compile_declarations(context, module, namespace, declarations)?;
compile_constants(context, &mut md_mgr, module, namespace)?;
compile_declarations(context, &mut md_mgr, module, namespace, declarations)?;
for decl in abi_entries {
compile_abi_method(context, module, decl)?;
compile_abi_method(context, &mut md_mgr, module, decl)?;
}

Ok(module)
}

fn compile_constants(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
module_ns: &namespace::Module,
public_only: bool,
) -> Result<(), CompileError> {
for decl_name in module_ns.get_all_declared_symbols() {
compile_const_decl(
&mut LookupEnv {
context,
md_mgr,
module,
module_ns: Some(module_ns),
public_only,
lookup: compile_const_decl,
},
decl_name,
)?;
}

for submodule_ns in module_ns.submodules().values() {
compile_constants(context, module, submodule_ns, true)?;
compile_constants(context, md_mgr, module, submodule_ns)?;
}

Ok(())
Expand All @@ -83,6 +86,7 @@ fn compile_constants(

fn compile_declarations(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
namespace: &namespace::Module,
declarations: Vec<TypedDeclaration>,
Expand All @@ -93,9 +97,9 @@ fn compile_declarations(
compile_const_decl(
&mut LookupEnv {
context,
md_mgr,
module,
module_ns: Some(namespace),
public_only: false,
lookup: compile_const_decl,
},
&decl.name,
Expand Down Expand Up @@ -139,6 +143,7 @@ fn compile_declarations(

pub(super) fn compile_function(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
ast_fn_decl: TypedFunctionDeclaration,
) -> Result<Option<Function>, CompileError> {
Expand All @@ -156,12 +161,13 @@ pub(super) fn compile_function(
})
.collect::<Result<Vec<(String, Type, Span)>, CompileError>>()?;

compile_fn_with_args(context, module, ast_fn_decl, args, None).map(&Some)
compile_fn_with_args(context, md_mgr, module, ast_fn_decl, args, None).map(&Some)
}
}

fn compile_fn_with_args(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
ast_fn_decl: TypedFunctionDeclaration,
args: Vec<(String, Type, Span)>,
Expand All @@ -180,23 +186,12 @@ fn compile_fn_with_args(

let args = args
.into_iter()
.map(|(name, ty, span)| (name, ty, MetadataIndex::from_span(context, &span)))
.map(|(name, ty, span)| (name, ty, md_mgr.span_to_md(context, &span)))
.collect();
let ret_type = convert_resolved_typeid(context, &return_type, &return_type_span)?;
let span_md_idx = MetadataIndex::from_span(context, &span);
let storage_md_idx = if purity == Purity::Pure {
None
} else {
Some(MetadataIndex::get_storage_index(
context,
match purity {
Purity::Pure => unreachable!("Already checked for Pure above."),
Purity::Reads => StorageOperation::Reads,
Purity::Writes => StorageOperation::Writes,
Purity::ReadsWrites => StorageOperation::ReadsWrites,
},
))
};
let span_md_idx = md_mgr.span_to_md(context, &span);
let storage_md_idx = md_mgr.purity_to_md(context, purity);
let metadata = md_combine(context, &span_md_idx, &storage_md_idx);
let func = Function::new(
context,
module,
Expand All @@ -205,23 +200,22 @@ fn compile_fn_with_args(
ret_type,
selector,
visibility == Visibility::Public,
span_md_idx,
storage_md_idx,
metadata,
);

// We clone the struct symbols here, as they contain the globals; any new local declarations
// may remain within the function scope.
let mut compiler = FnCompiler::new(context, module, func);

let mut ret_val = compiler.compile_code_block(context, body)?;
let mut ret_val = compiler.compile_code_block(context, md_mgr, body)?;

// Special case: if the return type is unit but the return value type is not, then we have an
// implicit return from the last expression in the code block having a semi-colon. This isn't
// codified in the AST explicitly so we need to make a unit to return here.
if ret_type.eq(context, &Type::Unit) && !matches!(ret_val.get_type(context), Some(Type::Unit)) {
// NOTE: We're replacing the ret_val and throwing away whatever it used to be, as it is
// never actually used anyway.
ret_val = Constant::get_unit(context, None);
ret_val = Constant::get_unit(context);
}

let already_returns = compiler.current_block.is_terminated_by_ret(context);
Expand All @@ -241,12 +235,9 @@ fn compile_fn_with_args(
|| compiler.current_block.num_predecessors(context) > 0)
{
if ret_type.eq(context, &Type::Unit) {
ret_val = Constant::get_unit(context, None);
ret_val = Constant::get_unit(context);
}
compiler
.current_block
.ins(context)
.ret(ret_val, ret_type, None);
compiler.current_block.ins(context).ret(ret_val, ret_type);
}
Ok(func)
}
Expand Down Expand Up @@ -281,6 +272,7 @@ fn compile_impl(

fn compile_abi_method(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
ast_fn_decl: TypedFunctionDeclaration,
) -> Result<Function, CompileError> {
Expand Down Expand Up @@ -314,5 +306,5 @@ fn compile_abi_method(
})
.collect::<Result<Vec<(String, Type, Span)>, CompileError>>()?;

compile_fn_with_args(context, module, ast_fn_decl, args, Some(selector))
compile_fn_with_args(context, md_mgr, module, ast_fn_decl, args, Some(selector))
}
39 changes: 21 additions & 18 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
error::CompileError,
metadata::MetadataManager,
semantic_analysis::{
declaration::ProjectionKind, namespace, TypedAstNode, TypedAstNodeContent,
TypedConstantDeclaration, TypedDeclaration, TypedExpression, TypedExpressionVariant,
Expand All @@ -12,7 +13,6 @@ use super::{convert::convert_literal_to_constant, types::*};
use sway_ir::{
constant::{Constant, ConstantValue},
context::Context,
metadata::MetadataIndex,
module::Module,
value::Value,
};
Expand All @@ -21,15 +21,15 @@ use sway_types::{ident::Ident, span::Spanned};

use std::collections::HashMap;

pub struct LookupEnv<'a> {
pub context: &'a mut Context,
pub module: Module,
pub module_ns: Option<&'a namespace::Module>,
pub public_only: bool,
pub lookup: fn(&mut LookupEnv, &Ident) -> Result<Option<Value>, CompileError>,
pub(crate) struct LookupEnv<'a> {
pub(crate) context: &'a mut Context,
pub(crate) md_mgr: &'a mut MetadataManager,
pub(crate) module: Module,
pub(crate) module_ns: Option<&'a namespace::Module>,
pub(crate) lookup: fn(&mut LookupEnv, &Ident) -> Result<Option<Value>, CompileError>,
}

pub fn compile_const_decl(
pub(crate) fn compile_const_decl(
env: &mut LookupEnv,
name: &Ident,
) -> Result<Option<Value>, CompileError> {
Expand All @@ -51,8 +51,13 @@ pub fn compile_const_decl(
_otherwise => None,
};
if let Some((name, value)) = decl_name_value {
let const_val =
compile_constant_expression(env.context, env.module, env.module_ns, value)?;
let const_val = compile_constant_expression(
env.context,
env.md_mgr,
env.module,
env.module_ns,
value,
)?;
env.module
.add_global_constant(env.context, name.as_str().to_owned(), const_val);
Ok(Some(const_val))
Expand All @@ -66,32 +71,30 @@ pub fn compile_const_decl(

pub(super) fn compile_constant_expression(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
module_ns: Option<&namespace::Module>,
const_expr: &TypedExpression,
) -> Result<Value, CompileError> {
let span_id_idx = MetadataIndex::from_span(context, &const_expr.span);
let span_id_idx = md_mgr.span_to_md(context, &const_expr.span);

let constant_evaluated =
compile_constant_expression_to_constant(context, module, module_ns, const_expr)?;
Ok(Value::new_constant(
context,
constant_evaluated,
span_id_idx,
))
compile_constant_expression_to_constant(context, md_mgr, module, module_ns, const_expr)?;
Ok(Value::new_constant(context, constant_evaluated).add_metadatum(context, span_id_idx))
}

pub(crate) fn compile_constant_expression_to_constant(
context: &mut Context,
md_mgr: &mut MetadataManager,
module: Module,
module_ns: Option<&namespace::Module>,
const_expr: &TypedExpression,
) -> Result<Constant, CompileError> {
let lookup = &mut LookupEnv {
context,
md_mgr,
module,
module_ns,
public_only: false,
lookup: compile_const_decl,
};

Expand Down
28 changes: 10 additions & 18 deletions sway-core/src/ir_generation/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,25 @@ use crate::{

use super::types::{create_enum_aggregate, create_tuple_aggregate};

use sway_ir::{Aggregate, Constant, Context, MetadataIndex, Type, Value};
use sway_ir::{Aggregate, Constant, Context, Type, Value};
use sway_types::span::Span;

pub(super) fn convert_literal_to_value(
context: &mut Context,
ast_literal: &Literal,
span_id_idx: Option<MetadataIndex>,
) -> Value {
pub(super) fn convert_literal_to_value(context: &mut Context, ast_literal: &Literal) -> Value {
match ast_literal {
// In Sway for now we don't have `as` casting and for integers which may be implicitly cast
// between widths we just emit a warning, and essentially ignore it. We also assume a
// 'Numeric' integer of undetermined width is 'u64`. The IR would like to be type
// consistent and doesn't tolerate mising integers of different width, so for now, until we
// do introduce explicit `as` casting, all integers are `u64` as far as the IR is
// concerned.
Literal::U8(n) | Literal::Byte(n) => {
Constant::get_uint(context, 64, *n as u64, span_id_idx)
}
Literal::U16(n) => Constant::get_uint(context, 64, *n as u64, span_id_idx),
Literal::U32(n) => Constant::get_uint(context, 64, *n as u64, span_id_idx),
Literal::U64(n) => Constant::get_uint(context, 64, *n, span_id_idx),
Literal::Numeric(n) => Constant::get_uint(context, 64, *n, span_id_idx),
Literal::String(s) => {
Constant::get_string(context, s.as_str().as_bytes().to_vec(), span_id_idx)
}
Literal::Boolean(b) => Constant::get_bool(context, *b, span_id_idx),
Literal::B256(bs) => Constant::get_b256(context, *bs, span_id_idx),
Literal::U8(n) | Literal::Byte(n) => Constant::get_uint(context, 64, *n as u64),
Literal::U16(n) => Constant::get_uint(context, 64, *n as u64),
Literal::U32(n) => Constant::get_uint(context, 64, *n as u64),
Literal::U64(n) => Constant::get_uint(context, 64, *n),
Literal::Numeric(n) => Constant::get_uint(context, 64, *n),
Literal::String(s) => Constant::get_string(context, s.as_str().as_bytes().to_vec()),
Literal::Boolean(b) => Constant::get_bool(context, *b),
Literal::B256(bs) => Constant::get_b256(context, *bs),
}
}

Expand Down
Loading

0 comments on commit dcaee96

Please sign in to comment.