Skip to content

Commit

Permalink
Introduce __eq intrinsic (#2100)
Browse files Browse the repository at this point in the history
* Introduce `__eq` intrinsic

* Lower to `Instruction::Cmp` instead of to assembly in IRGen

* Refactor intrinsics to all have arg and type arg vectors
  • Loading branch information
vaivaswatha authored Jun 29, 2022
1 parent 6befe78 commit 753639c
Show file tree
Hide file tree
Showing 27 changed files with 520 additions and 326 deletions.
42 changes: 15 additions & 27 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,44 +1033,32 @@ fn connect_expression(
}

fn connect_intrinsic_function(
kind: &TypedIntrinsicFunctionKind,
TypedIntrinsicFunctionKind {
kind, arguments, ..
}: &TypedIntrinsicFunctionKind,
graph: &mut ControlFlowGraph,
leaves: &[NodeIndex],
exit_node: Option<NodeIndex>,
tree_type: &TreeType,
) -> Result<Vec<NodeIndex>, CompileError> {
let result = match kind {
TypedIntrinsicFunctionKind::SizeOfVal { exp } => connect_expression(
let node = graph.add_node(kind.to_string().into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
let mut result = vec![node];
let _ = arguments.iter().try_fold(&mut result, |accum, exp| {
let mut res = connect_expression(
&(*exp).expression,
graph,
leaves,
exit_node,
"size_of",
"intrinsic",
tree_type,
exp.span.clone(),
)?,
TypedIntrinsicFunctionKind::SizeOfType { .. } => {
let node = graph.add_node("size of type".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
TypedIntrinsicFunctionKind::IsRefType { .. } => {
let node = graph.add_node("is ref type".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
TypedIntrinsicFunctionKind::GetStorageKey => {
let node = graph.add_node("Get storage key".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
};
)?;
accum.append(&mut res);
Ok::<_, CompileError>(accum)
})?;
Ok(result)
}

Expand Down
159 changes: 32 additions & 127 deletions sway-core/src/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use {
AbiDeclaration, AsmExpression, AsmOp, AsmRegister, AsmRegisterDeclaration, AstNode,
AstNodeContent, CallPath, CodeBlock, ConstantDeclaration, Declaration, EnumDeclaration,
EnumVariant, Expression, FunctionDeclaration, FunctionParameter, ImplSelf, ImplTrait,
ImportType, IncludeStatement, IntrinsicFunctionKind, LazyOp, Literal, MatchBranch,
MethodName, ParseTree, Purity, Reassignment, ReassignmentTarget, ReturnStatement,
Scrutinee, StorageDeclaration, StorageField, StructDeclaration, StructExpressionField,
StructField, StructScrutineeField, Supertrait, TraitDeclaration, TraitFn, TreeType,
TypeInfo, UseStatement, VariableDeclaration, Visibility, WhileLoop,
ImportType, IncludeStatement, LazyOp, Literal, MatchBranch, MethodName, ParseTree, Purity,
Reassignment, ReassignmentTarget, ReturnStatement, Scrutinee, StorageDeclaration,
StorageField, StructDeclaration, StructExpressionField, StructField, StructScrutineeField,
Supertrait, TraitDeclaration, TraitFn, TreeType, TypeInfo, UseStatement,
VariableDeclaration, Visibility, WhileLoop,
},
std::{
collections::HashMap,
Expand Down Expand Up @@ -102,16 +102,6 @@ pub enum ConvertParseTreeError {
GenericsNotSupportedHere { span: Span },
#[error("fully qualified paths are not supported here")]
FullyQualifiedPathsNotSupportedHere { span: Span },
#[error("__size_of does not take arguments")]
SizeOfTooManyArgs { span: Span },
#[error("__size_of requires exactly one generic argument")]
SizeOfOneGenericArg { span: Span },
#[error("__is_reference_type does not take arguments")]
IsReferenceTypeTooManyArgs { span: Span },
#[error("__is_reference_type requires exactly one generic argument")]
IsReferenceTypeOneGenericArg { span: Span },
#[error("__size_of_val requires exactly one argument")]
SizeOfValOneArg { span: Span },
#[error("tuple index out of range")]
TupleIndexOutOfRange { span: Span },
#[error("shift-left expressions are not implemented")]
Expand Down Expand Up @@ -199,11 +189,6 @@ impl Spanned for ConvertParseTreeError {
ConvertParseTreeError::FunctionArbitraryExpression { span } => span.clone(),
ConvertParseTreeError::GenericsNotSupportedHere { span } => span.clone(),
ConvertParseTreeError::FullyQualifiedPathsNotSupportedHere { span } => span.clone(),
ConvertParseTreeError::SizeOfTooManyArgs { span } => span.clone(),
ConvertParseTreeError::SizeOfOneGenericArg { span } => span.clone(),
ConvertParseTreeError::IsReferenceTypeTooManyArgs { span } => span.clone(),
ConvertParseTreeError::IsReferenceTypeOneGenericArg { span } => span.clone(),
ConvertParseTreeError::SizeOfValOneArg { span } => span.clone(),
ConvertParseTreeError::TupleIndexOutOfRange { span } => span.clone(),
ConvertParseTreeError::ShlNotImplemented { span } => span.clone(),
ConvertParseTreeError::ShrNotImplemented { span } => span.clone(),
Expand Down Expand Up @@ -1442,118 +1427,38 @@ fn expr_to_expression(ec: &mut ErrorContext, expr: Expr) -> Result<Expression, E
}
}
None => {
if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOf)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::SizeOfTooManyArgs { span };
return Err(ec.error(error));
}
let ty = match {
generics_opt.and_then(|(_double_colon_token, generic_args)| {
iter_to_array(generic_args.parameters.into_inner())
})
} {
Some([ty]) => ty,
None => {
let error = ConvertParseTreeError::SizeOfOneGenericArg { span };
return Err(ec.error(error));
}
};
let type_span = ty.span();
let type_name = ty_to_type_info(ec, ty)?;
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::SizeOfType {
type_name,
type_span,
},
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::GetStorageKey)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::GetStorageKeyTooManyArgs { span };
return Err(ec.error(error));
}
if generics_opt.is_some() {
let error = ConvertParseTreeError::GenericsNotSupportedHere { span };
return Err(ec.error(error));
}
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::GetStorageKey,
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::IsReferenceType)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::IsReferenceTypeTooManyArgs { span };
return Err(ec.error(error));
}
let ty = match {
generics_opt.and_then(|(_double_colon_token, generic_args)| {
iter_to_array(generic_args.parameters.into_inner())
})
} {
Some([ty]) => ty,
None => {
let error =
ConvertParseTreeError::IsReferenceTypeOneGenericArg { span };
return Err(ec.error(error));
}
};
let type_span = ty.span();
let type_name = ty_to_type_info(ec, ty)?;
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::IsRefType {
type_name,
type_span,
},
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOfVal)
{
let exp = match <[_; 1]>::try_from(arguments) {
Ok([exp]) => Box::new(exp),
Err(..) => {
let error = ConvertParseTreeError::SizeOfValOneArg { span };
return Err(ec.error(error));
}
};
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::SizeOfVal { exp },
span,
let type_arguments = match generics_opt {
Some((_double_colon_token, generic_args)) => {
generic_args_to_type_arguments(ec, generic_args)?
}
} else {
let type_arguments = match generics_opt {
Some((_double_colon_token, generic_args)) => {
generic_args_to_type_arguments(ec, generic_args)?
}
None => Vec::new(),
};
if call_path.prefixes.is_empty() {
Expression::FunctionApplication {
name: call_path,
None => Vec::new(),
};
match Intrinsic::try_from_str(call_path.suffix.as_str()) {
Some(intrinsic)
if call_path.prefixes.is_empty() && !call_path.is_absolute =>
{
Expression::IntrinsicFunction {
kind: intrinsic,
arguments,
type_arguments,
span,
}
} else {
Expression::DelineatedPath {
call_path,
args: arguments,
type_arguments,
span,
}
_ => {
if call_path.prefixes.is_empty() {
Expression::FunctionApplication {
name: call_path,
arguments,
type_arguments,
span,
}
} else {
Expression::DelineatedPath {
call_path,
args: arguments,
type_arguments,
span,
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions sway-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,20 @@ pub enum CompileError {
NonConstantDeclValue { span: Span },
#[error("Declaring storage in a {program_kind} is not allowed.")]
StorageDeclarationInNonContract { program_kind: String, span: Span },
#[error("Unsupported argument type to intrinsic \"{name}\".")]
IntrinsicUnsupportedArgType { name: String, span: Span },
#[error("Call to \"{name}\" expects {expected} arguments")]
IntrinsicIncorrectNumArgs {
name: String,
expected: u64,
span: Span,
},
#[error("Call to \"{name}\" expects {expected} type arguments")]
IntrinsicIncorrectNumTArgs {
name: String,
expected: u64,
span: Span,
},
}

impl std::convert::From<TypeError> for CompileError {
Expand Down Expand Up @@ -1151,6 +1165,9 @@ impl Spanned for CompileError {
TupleIndexOutOfBounds { span, .. } => span.clone(),
NonConstantDeclValue { span } => span.clone(),
StorageDeclarationInNonContract { span, .. } => span.clone(),
IntrinsicUnsupportedArgType { span, .. } => span.clone(),
IntrinsicIncorrectNumArgs { span, .. } => span.clone(),
IntrinsicIncorrectNumTArgs { span, .. } => span.clone(),
}
}
}
Expand Down
39 changes: 31 additions & 8 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
type_engine::{insert_type, resolve_type, TypeId, TypeInfo},
};
use sway_ir::{Context, *};
use sway_parse::intrinsics::Intrinsic;
use sway_types::{
ident::Ident,
span::{Span, Spanned},
Expand Down Expand Up @@ -319,41 +320,63 @@ impl FnCompiler {
fn compile_intrinsic_function(
&mut self,
context: &mut Context,
kind: TypedIntrinsicFunctionKind,
TypedIntrinsicFunctionKind {
kind,
arguments,
type_arguments,
span: _,
}: TypedIntrinsicFunctionKind,
span: Span,
) -> Result<Value, CompileError> {
// We safely index into arguments and type_arguments arrays below
// because the type-checker ensures that the arguments are all there.
match kind {
TypedIntrinsicFunctionKind::SizeOfVal { exp } => {
Intrinsic::SizeOfVal => {
let exp = arguments[0].clone();
// Compile the expression in case of side-effects but ignore its value.
let ir_type = convert_resolved_typeid(context, &exp.return_type, &exp.span)?;
self.compile_expression(context, *exp)?;
self.compile_expression(context, exp)?;
Ok(Constant::get_uint(
context,
64,
ir_type_size_in_bytes(context, &ir_type),
None,
))
}
TypedIntrinsicFunctionKind::SizeOfType { type_id, type_span } => {
let ir_type = convert_resolved_typeid(context, &type_id, &type_span)?;
Intrinsic::SizeOfType => {
let targ = type_arguments[0].clone();
let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?;
Ok(Constant::get_uint(
context,
64,
ir_type_size_in_bytes(context, &ir_type),
None,
))
}
TypedIntrinsicFunctionKind::IsRefType { type_id, type_span } => {
let ir_type = convert_resolved_typeid(context, &type_id, &type_span)?;
Intrinsic::IsReferenceType => {
let targ = type_arguments[0].clone();
let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?;
Ok(Constant::get_bool(context, !ir_type.is_copy_type(), None))
}
TypedIntrinsicFunctionKind::GetStorageKey => {
Intrinsic::GetStorageKey => {
let span_md_idx = MetadataIndex::from_span(context, &span);
Ok(self
.current_block
.ins(context)
.get_storage_key(span_md_idx, None))
}
Intrinsic::Eq => {
let lhs = arguments[0].clone();
let rhs = arguments[1].clone();
let lhs_value = self.compile_expression(context, lhs)?;
let rhs_value = self.compile_expression(context, rhs)?;
Ok(self.current_block.ins(context).cmp(
Predicate::Equal,
lhs_value,
rhs_value,
None,
))
}
}
}

Expand Down
18 changes: 0 additions & 18 deletions sway-core/src/parse_tree/expression/intrinsic_function.rs

This file was deleted.

Loading

0 comments on commit 753639c

Please sign in to comment.