Skip to content

Commit

Permalink
Remove pointers from the Sway IR. (FuelLabs#3663)
Browse files Browse the repository at this point in the history
Remove pointers from IR.
    
The pointers in the IR are not really pointers, but are local variables.
We want to add proper pointers to the IR though and naming the local
variables as pointers adds ambiguity.
    
This change renames `get_ptr` to `get_local` and removes `ptr` and `mut`
from the serialised output.  `get_local` no longer performs casts so
`cast_ptr` has been added as a stopgap until we add a better solution.
  • Loading branch information
otrho authored Jan 2, 2023
1 parent 3bfc15d commit 76f5653
Show file tree
Hide file tree
Showing 67 changed files with 1,254 additions and 1,409 deletions.
241 changes: 145 additions & 96 deletions sway-core/src/asm_generation/asm_builder.rs

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions sway-core/src/asm_generation/asm_builder/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,10 @@ impl<'ir> AsmBuilder<'ir> {
}

// The base is an offset. Dereference it.
if val.get_type(self.context).unwrap().is_copy_type() {
if val
.get_type(self.context)
.map_or(false, |t| self.is_copy_type(&t))
{
self.cur_bytecode.push(Op {
opcode: either::Either::Left(VirtualOp::LW(
single_arg_reg.clone(),
Expand Down Expand Up @@ -344,7 +347,7 @@ impl<'ir> AsmBuilder<'ir> {
let current_arg_reg = self.value_to_register(val);
let arg_type = val.get_type(self.context).unwrap();
let arg_type_size_bytes = ir_type_size_in_bytes(self.context, &arg_type);
if arg_type.is_copy_type() {
if self.is_copy_type(&arg_type) {
if arg_word_offset > compiler_constants::TWELVE_BITS {
let offs_reg = self.reg_seqr.next();
self.cur_bytecode.push(Op {
Expand Down Expand Up @@ -589,15 +592,14 @@ impl<'ir> AsmBuilder<'ir> {
// Stack offsets are in words to both enforce alignment and simplify use with LW/SW.
let mut stack_base = 0_u64;
for (_name, ptr) in function.locals_iter(self.context) {
if !ptr.is_mutable(self.context) && ptr.get_initializer(self.context).is_some() {
let constant = ptr.get_initializer(self.context).unwrap();
if let Some(constant) = ptr.get_initializer(self.context) {
let data_id = self
.data_section
.insert_data_value(Entry::from_constant(self.context, constant));
self.ptr_map.insert(*ptr, Storage::Data(data_id));
} else {
match ptr.get_type(self.context) {
Type::Unit | Type::Bool | Type::Uint(_) | Type::Pointer(_) => {
Type::Unit | Type::Bool | Type::Uint(_) => {
self.ptr_map.insert(*ptr, Storage::Stack(stack_base));
stack_base += 1;
}
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/asm_generation/from_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub enum StateAccessType {

pub(crate) fn ir_type_size_in_bytes(context: &Context, ty: &Type) -> u64 {
match ty {
Type::Unit | Type::Bool | Type::Uint(_) | Type::Pointer(_) => 8,
Type::Unit | Type::Bool | Type::Uint(_) => 8,
Type::Slice => 16,
Type::B256 => 32,
Type::String(n) => size_bytes_round_up_to_word_alignment!(n),
Expand Down
33 changes: 13 additions & 20 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ pub(super) fn compile_function(
.parameters
.iter()
.map(|param| convert_fn_param(type_engine, context, param))
.collect::<Result<Vec<(String, Type, Span)>, CompileError>>()?;
.collect::<Result<Vec<(String, Type, bool, Span)>, CompileError>>()?;

compile_fn_with_args(
engines,
Expand Down Expand Up @@ -388,17 +388,11 @@ fn convert_fn_param(
type_engine: &TypeEngine,
context: &mut Context,
param: &ty::TyFunctionParameter,
) -> Result<(String, Type, Span), CompileError> {
) -> Result<(String, Type, bool, Span), CompileError> {
convert_resolved_typeid(type_engine, context, &param.type_id, &param.type_span).map(|ty| {
(
param.name.as_str().into(),
if param.is_reference && type_engine.look_up_type_id(param.type_id).is_copy_type() {
Type::Pointer(Pointer::new(context, ty, param.is_mutable, None))
} else {
ty
},
param.name.span(),
)
let by_ref =
param.is_reference && type_engine.look_up_type_id(param.type_id).is_copy_type();
(param.name.as_str().into(), ty, by_ref, param.name.span())
})
}

Expand All @@ -410,7 +404,7 @@ fn compile_fn_with_args(
module: Module,
ast_fn_decl: &ty::TyFunctionDeclaration,
is_entry: bool,
args: Vec<(String, Type, Span)>,
args: Vec<(String, Type, bool, Span)>,
selector: Option<[u8; 4]>,
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
Expand All @@ -432,17 +426,18 @@ fn compile_fn_with_args(

let mut args = args
.into_iter()
.map(|(name, ty, span)| (name, ty, md_mgr.span_to_md(context, &span)))
.map(|(name, ty, by_ref, span)| (name, ty, by_ref, md_mgr.span_to_md(context, &span)))
.collect::<Vec<_>>();

let ret_type = convert_resolved_typeid(type_engine, context, return_type, return_type_span)?;

let returns_by_ref = !is_entry && !ret_type.is_copy_type();
let returns_by_ref = !is_entry && !type_engine.look_up_type_id(*return_type).is_copy_type();
if returns_by_ref {
// Instead of 'returning' a by-ref value we make the last argument an 'out' parameter.
args.push((
"__ret_value".to_owned(),
Type::Pointer(Pointer::new(context, ret_type, true, None)),
ret_type,
true,
md_mgr.span_to_md(context, return_type_span),
));
}
Expand Down Expand Up @@ -488,9 +483,7 @@ fn compile_fn_with_args(
// together and is invalid. This can happen with diverging control flow or with implicit
// returns. We can double check here and make sure the return value type is correct.
ret_val = match ret_val.get_type(context) {
Some(ret_val_type) if ret_type.eq(context, &ret_val_type.strip_ptr_type(context)) => {
ret_val
}
Some(ret_val_type) if ret_type.eq(context, &ret_val_type) => ret_val,

// Mismatched or unavailable type. Set ret_val to a correctly typed Undef.
_otherwise => Value::new_constant(context, Constant::get_undef(ret_type)),
Expand Down Expand Up @@ -593,9 +586,9 @@ fn compile_abi_method(
.iter()
.map(|param| {
convert_resolved_typeid(type_engine, context, &param.type_id, &param.type_span)
.map(|ty| (param.name.as_str().into(), ty, param.name.span()))
.map(|ty| (param.name.as_str().into(), ty, false, param.name.span()))
})
.collect::<Result<Vec<(String, Type, Span)>, CompileError>>()?;
.collect::<Result<Vec<(String, Type, bool, Span)>, CompileError>>()?;

compile_fn_with_args(
engines,
Expand Down
18 changes: 7 additions & 11 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,24 @@ pub(crate) fn compile_const_decl(
// Check if it's a processed local constant.
if let Some(fn_compiler) = env.function_compiler {
let mut found_local = false;
if let Some(ptr) = fn_compiler.get_function_ptr(env.context, name.as_str()) {
if let Some(local_var) = fn_compiler.get_function_var(env.context, name.as_str()) {
found_local = true;
if !ptr.is_mutable(env.context) {
if let Some(constant) = ptr.get_initializer(env.context) {
return Ok(Some(Value::new_constant(env.context, constant.clone())));
}
if let Some(constant) = local_var.get_initializer(env.context) {
return Ok(Some(Value::new_constant(env.context, constant.clone())));
}

// Check if a constant was stored to the pointer in the current block
// Check if a constant was stored to a local variable in the current block.
let mut stored_const_opt: Option<&Constant> = None;
for ins in fn_compiler.current_block.instruction_iter(env.context) {
if let Some(Instruction::Store {
dst_val,
stored_val,
}) = ins.get_instruction(env.context)
{
if let Some(Instruction::GetPointer {
base_ptr: base_ptr_2,
..
}) = dst_val.get_instruction(env.context)
if let Some(Instruction::GetLocal(store_dst_var)) =
dst_val.get_instruction(env.context)
{
if &ptr == base_ptr_2 {
if &local_var == store_dst_var {
stored_const_opt = stored_val.get_constant(env.context);
}
}
Expand Down
Loading

0 comments on commit 76f5653

Please sign in to comment.