Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
address.span.clone(),
options,
),
Array {
ArrayExplicit {
elem_type: _,
contents,
} => {
Expand All @@ -1818,6 +1818,35 @@ fn connect_expression<'eng: 'cfg, 'cfg>(

Ok(last)
}
ArrayRepeat {
elem_type: _,
value,
length,
} => {
let value_idx = connect_expression(
engines,
&value.expression,
graph,
leaves,
exit_node,
"",
tree_type,
value.span.clone(),
options,
)?;
let length_idx = connect_expression(
engines,
&length.expression,
graph,
leaves,
exit_node,
"",
tree_type,
length.span.clone(),
options,
)?;
Ok([value_idx, length_idx].concat())
}
ArrayIndex { prefix, index } => {
let prefix_idx = connect_expression(
engines,
Expand Down
77 changes: 52 additions & 25 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,38 @@ pub(crate) fn compile_constant_expression_to_constant(
}
}

fn create_array_from_vec(
lookup: &mut LookupEnv,
elem_type: crate::TypeId,
element_typs: Vec<crate::TypeId>,
element_vals: Vec<Constant>,
) -> Option<Constant> {
let te = lookup.engines.te();
assert!({
let unify_check = UnifyCheck::coercion(lookup.engines);
element_typs
.iter()
.all(|tid| unify_check.check(*tid, elem_type))
});

let arr = create_array_aggregate(
te,
lookup.engines.de(),
lookup.context,
elem_type,
element_typs.len().try_into().unwrap(),
)
.map_or(None, |array_ty| {
Some(Constant::new_array(
lookup.context,
array_ty.get_array_elem_type(lookup.context).unwrap(),
element_vals,
))
});

arr
}

/// Given an environment mapping names to constants,
/// attempt to evaluate a typed expression to a constant.
fn const_eval_typed_expr(
Expand Down Expand Up @@ -413,7 +445,7 @@ fn const_eval_typed_expr(
))
})
}
ty::TyExpressionVariant::Array {
ty::TyExpressionVariant::ArrayExplicit {
elem_type,
contents,
} => {
Expand All @@ -434,30 +466,25 @@ fn const_eval_typed_expr(
assert!(element_typs.len() == contents.len());
assert!(element_vals.len() == contents.len());

let te = lookup.engines.te();
assert!({
let unify_check = UnifyCheck::coercion(lookup.engines);
element_typs
.iter()
.all(|tid| unify_check.check(*tid, *elem_type))
});

let arr = create_array_aggregate(
te,
lookup.engines.de(),
lookup.context,
*elem_type,
element_typs.len().try_into().unwrap(),
)
.map_or(None, |array_ty| {
Some(Constant::new_array(
lookup.context,
array_ty.get_array_elem_type(lookup.context).unwrap(),
element_vals,
))
});

arr
create_array_from_vec(lookup, *elem_type, element_typs, element_vals)
}
ty::TyExpressionVariant::ArrayRepeat {
elem_type,
value,
length,
} => {
let constant = const_eval_typed_expr(lookup, known_consts, value)?.unwrap();
let length = const_eval_typed_expr(lookup, known_consts, length)?
.unwrap()
.as_uint()
.unwrap() as usize;
let element_vals = (0..length).map(|_| constant.clone()).collect::<Vec<_>>();
let element_typs = (0..length).map(|_| value.return_type).collect::<Vec<_>>();

assert!(element_typs.len() == length);
assert!(element_vals.len() == length);

create_array_from_vec(lookup, *elem_type, element_typs, element_vals)
}
ty::TyExpressionVariant::EnumInstantiation {
enum_ref,
Expand Down
200 changes: 147 additions & 53 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,10 +545,24 @@ impl<'eng> FnCompiler<'eng> {
ty::TyExpressionVariant::VariableExpression {
name, call_path, ..
} => self.compile_var_expr(context, call_path, name, span_md_idx),
ty::TyExpressionVariant::Array {
ty::TyExpressionVariant::ArrayExplicit {
elem_type,
contents,
} => self.compile_array_expr(context, md_mgr, *elem_type, contents, span_md_idx),
} => {
self.compile_array_explicit_expr(context, md_mgr, *elem_type, contents, span_md_idx)
}
ty::TyExpressionVariant::ArrayRepeat {
elem_type,
value,
length,
} => self.compile_array_repeat_expr(
context,
md_mgr,
*elem_type,
value,
length,
span_md_idx,
),
ty::TyExpressionVariant::ArrayIndex { prefix, index } => {
self.compile_array_index(context, md_mgr, prefix, index, span_md_idx)
}
Expand Down Expand Up @@ -3635,7 +3649,67 @@ impl<'eng> FnCompiler<'eng> {
Ok(TerminatorValue::new(val, context))
}

fn compile_array_expr(
fn compile_array_repeat_expr(
&mut self,
context: &mut Context,
md_mgr: &mut MetadataManager,
elem_type: TypeId,
value: &ty::TyExpression,
length: &ty::TyExpression,
span_md_idx: Option<MetadataIndex>,
) -> Result<TerminatorValue, CompileError> {
let elem_type = convert_resolved_typeid_no_span(
self.engines.te(),
self.engines.de(),
context,
elem_type,
)?;

let length_as_u64 = length.as_literal_u64().unwrap();
let array_type = Type::new_array(context, elem_type, length_as_u64);

let temp_name = self.lexical_map.insert_anon();
let array_local_var = self
.function
.new_local_var(context, temp_name, array_type, None, false)
.map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?;
let array_value = self
.current_block
.append(context)
.get_local(array_local_var)
.add_metadatum(context, span_md_idx);

let value_value = return_on_termination_or_extract!(
self.compile_expression_to_value(context, md_mgr, value)?
);

if length_as_u64 > 5 {
self.compile_array_init_loop(
context,
array_value,
elem_type,
value_value,
length_as_u64,
span_md_idx,
);
} else {
for i in 0..length_as_u64 {
let gep_val = self.current_block.append(context).get_elem_ptr_with_idx(
array_value,
elem_type,
i,
);
self.current_block
.append(context)
.store(gep_val, value_value)
.add_metadatum(context, span_md_idx);
}
}

Ok(TerminatorValue::new(array_value, context))
}

fn compile_array_explicit_expr(
&mut self,
context: &mut Context,
md_mgr: &mut MetadataManager,
Expand Down Expand Up @@ -3700,59 +3774,14 @@ impl<'eng> FnCompiler<'eng> {
})
});
if let Some(const_initializer) = const_initialiser_opt {
// Create a loop to insert const_initializer to all array elements.
let loop_block = self
.function
.create_block(context, Some("array_init_loop".into()));
// The loop begins with 0.
let zero = Constant::new_uint(context, 64, 0);
let zero = Value::new_constant(context, zero);
// Branch to the loop block, passing the initial iteration value.
self.current_block
.append(context)
.branch(loop_block, vec![zero]);
// Add a block argument (for the IV) to the loop block.
let index_var_index = loop_block.new_arg(context, Type::get_uint64(context));
let index = loop_block.get_arg(context, index_var_index).unwrap();
// Create an exit block.
let exit_block = self
.function
.create_block(context, Some("array_init_exit".into()));
// Start building the loop block.
self.current_block = loop_block;
let gep_val = self.current_block.append(context).get_elem_ptr(
self.compile_array_init_loop(
context,
array_value,
elem_type,
vec![index],
);
self.current_block
.append(context)
.store(gep_val, *const_initializer)
.add_metadatum(context, span_md_idx);
// Increment index by one.
let one = Constant::new_uint(context, 64, 1);
let one = Value::new_constant(context, one);
let index_inc =
self.current_block
.append(context)
.binary_op(BinaryOpKind::Add, index, one);
// continue = index_inc < contents.len()
let len = Constant::new_uint(context, 64, contents.len() as u64);
let len = Value::new_constant(context, len);
let r#continue =
self.current_block
.append(context)
.cmp(Predicate::LessThan, index_inc, len);
// if continue then loop_block else exit_block.
self.current_block.append(context).conditional_branch(
r#continue,
loop_block,
exit_block,
vec![index_inc],
vec![],
*const_initializer,
contents.len() as u64,
span_md_idx,
);
// Continue compilation in the exit block.
self.current_block = exit_block;
} else {
// Insert each element separately.
for (idx, elem_value) in compiled_elems.iter().enumerate() {
Expand Down Expand Up @@ -3788,6 +3817,71 @@ impl<'eng> FnCompiler<'eng> {
Ok(TerminatorValue::new(array_value, context))
}

// initialize an array with all elements equals to "init_value",
// which should be "Copy", concept that sway still don´t have.
fn compile_array_init_loop(
&mut self,
context: &mut Context,
array_value: Value,
elem_type: Type,
init_value: Value,
length: u64,
span_md_idx: Option<MetadataIndex>,
) {
// Create a loop to insert const_initializer to all array elements.
let loop_block = self
.function
.create_block(context, Some("array_init_loop".into()));
// The loop begins with 0.
let zero = Constant::new_uint(context, 64, 0);
let zero = Value::new_constant(context, zero);
// Branch to the loop block, passing the initial iteration value.
self.current_block
.append(context)
.branch(loop_block, vec![zero]);
// Add a block argument (for the IV) to the loop block.
let index_var_index = loop_block.new_arg(context, Type::get_uint64(context));
let index = loop_block.get_arg(context, index_var_index).unwrap();
// Create an exit block.
let exit_block = self
.function
.create_block(context, Some("array_init_exit".into()));
// Start building the loop block.
self.current_block = loop_block;
let gep_val =
self.current_block
.append(context)
.get_elem_ptr(array_value, elem_type, vec![index]);
self.current_block
.append(context)
.store(gep_val, init_value)
.add_metadatum(context, span_md_idx);
// Increment index by one.
let one = Constant::new_uint(context, 64, 1);
let one = Value::new_constant(context, one);
let index_inc = self
.current_block
.append(context)
.binary_op(BinaryOpKind::Add, index, one);
// continue = index_inc < contents.len()
let len = Constant::new_uint(context, 64, length);
let len = Value::new_constant(context, len);
let r#continue =
self.current_block
.append(context)
.cmp(Predicate::LessThan, index_inc, len);
// if continue then loop_block else exit_block.
self.current_block.append(context).conditional_branch(
r#continue,
loop_block,
exit_block,
vec![index_inc],
vec![],
);
// Continue compilation in the exit block.
self.current_block = exit_block;
}

fn compile_array_index(
&mut self,
context: &mut Context,
Expand Down
Loading
Loading