Skip to content

Commit

Permalink
Provision IR for future storage API. (FuelLabs#866)
Browse files Browse the repository at this point in the history
* Introduce storage operations to IR.

- Switch `load` and `store` instructions to use a Value for the source
  or destination.
  - Instead of accessing a Pointer directly the use of a `get_ptr`
    instruction is now mandated.
  - Introduct a `ptr_cast` operation which casts the type of a pointer
    and may also be passed to `load` and `store`.
- Add `state_load` and `state_store` which take a `b256` key and read or
  write either `u64` or `b256` values from or to memory.
- Change the serialised syntax a little bit, update the tests.

* Use the new `get_ptr` and `ptr_cast` instructions in IRgen.

- `load` and `store` must now take a value as the address arg.
- Add stubs to ASMgen for the yet to be utilised `ptr_cast`,
  `state_load` and `state_store` IR operations.
- Update the tests for the new `load` and `store`.
  • Loading branch information
otrho authored Mar 4, 2022
1 parent 6ede1d2 commit 142156f
Show file tree
Hide file tree
Showing 37 changed files with 620 additions and 272 deletions.
72 changes: 60 additions & 12 deletions sway-core/src/asm_generation/from_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ struct AsmBuilder<'ir> {
// Label map is from IR block to label name.
label_map: HashMap<Block, Label>,

// Reg map, const map and var map are all tracking IR values to VM values. Var map has an
// optional (None) register until its first assignment.
// Reg map is tracking IR values to VM values. Ptr map is tracking IR pointers to local
// storage types.
reg_map: HashMap<Value, VirtualRegister>,
ptr_map: HashMap<Pointer, Storage>,

Expand Down Expand Up @@ -407,13 +407,27 @@ impl<'ir> AsmBuilder<'ir> {
value,
indices,
} => self.compile_insert_value(instr_val, aggregate, ty, value, indices),
Instruction::Load(ptr) => self.compile_load(instr_val, ptr),
Instruction::Load(src_val) => check!(
self.compile_load(instr_val, src_val),
return err(warnings, errors),
warnings,
errors
),
Instruction::Nop => (),
Instruction::Phi(_) => (), // Managing the phi value is done in br and cbr compilation.
Instruction::PointerCast(..) => todo!(),
Instruction::Ret(ret_val, ty) => self.compile_ret(instr_val, ret_val, ty),
Instruction::Store { ptr, stored_val } => {
self.compile_store(instr_val, ptr, stored_val)
}
Instruction::StateLoad { .. } => todo!(),
Instruction::StateStore { .. } => todo!(),
Instruction::Store {
dst_val,
stored_val,
} => check!(
self.compile_store(instr_val, dst_val, stored_val),
return err(warnings, errors),
warnings,
errors
),
}
} else {
errors.push(CompileError::Internal(
Expand Down Expand Up @@ -1021,11 +1035,16 @@ impl<'ir> AsmBuilder<'ir> {
self.reg_map.insert(*instr_val, base_reg);
}

fn compile_load(&mut self, instr_val: &Value, ptr: &Pointer) {
fn compile_load(&mut self, instr_val: &Value, src_val: &Value) -> CompileResult<()> {
let ptr = self.resolve_ptr(src_val);
if ptr.value.is_none() {
return ptr.map(|_| ());
}
let ptr = ptr.value.unwrap();
let load_size_in_words =
size_bytes_in_words!(self.ir_type_size_in_bytes(ptr.get_type(self.context)));
let instr_reg = self.reg_seqr.next();
match self.ptr_map.get(ptr) {
match self.ptr_map.get(&ptr) {
None => unimplemented!("BUG? Uninitialised pointer."),
Some(storage) => match storage.clone() {
Storage::Data(data_id) => {
Expand Down Expand Up @@ -1118,6 +1137,7 @@ impl<'ir> AsmBuilder<'ir> {
},
}
self.reg_map.insert(*instr_val, instr_reg);
ok((), Vec::new(), Vec::new())
}

fn compile_ret(&mut self, instr_val: &Value, ret_val: &Value, ret_type: &Type) {
Expand Down Expand Up @@ -1165,10 +1185,20 @@ impl<'ir> AsmBuilder<'ir> {
}
}

fn compile_store(&mut self, instr_val: &Value, ptr: &Pointer, stored_val: &Value) {
fn compile_store(
&mut self,
instr_val: &Value,
dst_val: &Value,
stored_val: &Value,
) -> CompileResult<()> {
let ptr = self.resolve_ptr(dst_val);
if ptr.value.is_none() {
return ptr.map(|_| ());
}
let ptr = ptr.value.unwrap();
let stored_reg = self.value_to_register(stored_val);
let is_struct_ptr = ptr.is_struct_ptr(self.context);
match self.ptr_map.get(ptr) {
let is_aggregate_ptr = ptr.is_aggregate_ptr(self.context);
match self.ptr_map.get(&ptr) {
None => unreachable!("Bug! Trying to store to an unknown pointer."),
Some(storage) => match storage {
Storage::Data(_) => unreachable!("BUG! Trying to store to the data section."),
Expand All @@ -1191,7 +1221,7 @@ impl<'ir> AsmBuilder<'ir> {
let base_reg = self.stack_base_reg.as_ref().unwrap().clone();

// A single word can be stored with SW.
let stored_reg = if !is_struct_ptr {
let stored_reg = if !is_aggregate_ptr {
// stored_reg is a value.
stored_reg
} else {
Expand Down Expand Up @@ -1319,6 +1349,24 @@ impl<'ir> AsmBuilder<'ir> {
}
},
};
ok((), Vec::new(), Vec::new())
}

fn resolve_ptr(&self, ptr_val: &Value) -> CompileResult<Pointer> {
match &self.context.values[ptr_val.0].value {
ValueDatum::Instruction(Instruction::GetPointer(ptr)) => {
ok(*ptr, Vec::new(), Vec::new())
}
_otherwise => err(
Vec::new(),
vec![CompileError::Internal(
"Pointer arg for load/store is not a get_ptr instruction.",
ptr_val
.get_span(self.context)
.unwrap_or_else(Self::empty_span),
)],
),
}
}

fn value_to_register(&mut self, value: &Value) -> VirtualRegister {
Expand Down
24 changes: 12 additions & 12 deletions sway-core/src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,10 +981,11 @@ impl FnCompiler {
.get(name)
.and_then(|local_name| self.function.get_local_ptr(context, local_name))
{
Ok(if ptr.is_struct_ptr(context) {
self.current_block.ins(context).get_ptr(ptr, span_md_idx)
let ptr_val = self.current_block.ins(context).get_ptr(ptr, span_md_idx);
Ok(if ptr.is_aggregate_ptr(context) {
ptr_val
} else {
self.current_block.ins(context).load(ptr, span_md_idx)
self.current_block.ins(context).load(ptr_val, span_md_idx)
})
} else if let Some(val) = self.function.get_arg(context, name) {
Ok(val)
Expand Down Expand Up @@ -1038,9 +1039,10 @@ impl FnCompiler {
.new_local_ptr(context, local_name, return_type, is_mutable.into(), None)
.map_err(|ir_error| ir_error.to_string())?;

let ptr_val = self.current_block.ins(context).get_ptr(ptr, span_md_idx);
self.current_block
.ins(context)
.store(ptr, init_val, span_md_idx);
.store(ptr_val, init_val, span_md_idx);
Ok(init_val)
}

Expand Down Expand Up @@ -1089,7 +1091,7 @@ impl FnCompiler {
span_md_idx: Option<MetadataIndex>,
) -> Result<Value, String> {
let name = ast_reassignment.lhs[0].name.as_str();
let ptr_val = self
let ptr = self
.function
.get_local_ptr(context, name)
.ok_or(format!("variable not found: {}", name))?;
Expand All @@ -1098,6 +1100,7 @@ impl FnCompiler {

if ast_reassignment.lhs.len() == 1 {
// A non-aggregate; use a `store`.
let ptr_val = self.current_block.ins(context).get_ptr(ptr, span_md_idx);
self.current_block
.ins(context)
.store(ptr_val, reassign_val, span_md_idx);
Expand All @@ -1107,7 +1110,7 @@ impl FnCompiler {
let field_idcs = ast_reassignment.lhs[1..]
.iter()
.fold(
Ok((Vec::new(), *ptr_val.get_type(context))),
Ok((Vec::new(), *ptr.get_type(context))),
|acc, field_name| {
// Make sure we have an aggregate to index into.
acc.and_then(|(mut fld_idcs, ty)| match ty {
Expand Down Expand Up @@ -1140,19 +1143,16 @@ impl FnCompiler {
)?
.0;

let ty = match ptr_val.get_type(context) {
let ty = match ptr.get_type(context) {
Type::Struct(aggregate) => *aggregate,
_otherwise => {
return Err("Reassignment with multiple accessors to non-aggregate.".into())
}
};

let get_ptr_val = self
.current_block
.ins(context)
.get_ptr(ptr_val, span_md_idx);
let ptr_val = self.current_block.ins(context).get_ptr(ptr, span_md_idx);
self.current_block.ins(context).insert_value(
get_ptr_val,
ptr_val,
ty,
reassign_val,
field_idcs,
Expand Down
2 changes: 2 additions & 0 deletions sway-core/tests/ir_to_asm/bigger_asm_block.asm
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ lw $ds $is 1
add $$ds $$ds $is
move $r2 $sp ; save locals base register
cfei i32 ; allocate 32 bytes for all locals
addi $r0 $r2 i0 ; get_ptr
lw $r1 data_0 ; literal instantiation
addi $r0 $r2 i0 ; get store offset
mcpi $r0 $r1 i32 ; store value
addi $r0 $r2 i0 ; get_ptr
addi $r2 $r2 i0 ; load address
lw $r1 data_1 ; literal instantiation
addi $r0 $zero i32 ; asm block
Expand Down
16 changes: 9 additions & 7 deletions sway-core/tests/ir_to_asm/bigger_asm_block.ir
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ script {
local ptr b256 a

entry:
v0 = const b256 0x0202020202020202020202020202020202020202020202020202020202020202
store v0, ptr b256 a
v1 = load ptr b256 a
v2 = const b256 0x0303030303030303030303030303030303030303030303030303030303030303
v3 = asm(lhs: v1, rhs: v2, sz, res) -> res {
v0 = get_ptr ptr b256 a
v1 = const b256 0x0202020202020202020202020202020202020202020202020202020202020202
store v1, ptr v0
v2 = get_ptr ptr b256 a
v3 = load ptr v2
v4 = const b256 0x0303030303030303030303030303030303030303030303030303030303030303
v5 = asm(lhs: v3, rhs: v4, sz, res) -> res {
addi sz zero i32
meq res lhs rhs sz
}
br block0

block0:
v4 = phi(entry: v3)
ret bool v4
v6 = phi(entry: v5)
ret bool v6
}
}
31 changes: 18 additions & 13 deletions sway-core/tests/ir_to_asm/let_reassign_while_loop.ir
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
script {
fn main() -> bool {
local ptr bool a
local mut ptr bool a

entry:
v0 = const bool true
store v0, ptr bool a
v0 = get_ptr mut ptr bool a
v1 = const bool true
store v1, ptr v0
br while

while:
v1 = load ptr bool a
cbr v1, while_body, end_while
v2 = get_ptr mut ptr bool a
v3 = load ptr v2
cbr v3, while_body, end_while

while_body:
v2 = load ptr bool a
cbr v2, block0, block1
v4 = get_ptr mut ptr bool a
v5 = load ptr v4
cbr v5, block0, block1

block0:
v3 = phi(while_body: v2)
v4 = const bool false
v6 = phi(while_body: v5)
v7 = const bool false
br block1

block1:
v5 = phi(while_body: v2, block0: v4)
store v5, ptr bool a
v8 = phi(while_body: v5, block0: v7)
v9 = get_ptr mut ptr bool a
store v8, ptr v9
br while

end_while:
v6 = load ptr bool a
ret bool v6
v10 = get_ptr mut ptr bool a
v11 = load ptr v10
ret bool v11
}
}
2 changes: 1 addition & 1 deletion sway-core/tests/ir_to_asm/mutable_struct.asm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ lw $r0 data_0 ; literal instantiation
sw $r1 $r0 i0 ; insert_value @ 0
lw $r0 data_1 ; literal instantiation
sw $r1 $r0 i1 ; insert_value @ 1
addi $r0 $r2 i0 ; get_ptr
addi $r0 $r2 i0 ; get store offset
mcpi $r0 $r1 i16 ; store value
addi $r1 $r2 i0 ; get_ptr
Expand All @@ -21,7 +22,6 @@ sw $r1 $r0 i0 ; insert_value @ 0
addi $r0 $r2 i0 ; get_ptr
lw $r0 $r0 i1 ; extract_value @ 1
ret $r0
noop ; word-alignment of data section
.data:
data_0 .u64 0x28
data_1 .u64 0x02
Expand Down
14 changes: 7 additions & 7 deletions sway-core/tests/ir_to_asm/mutable_struct.ir
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ script {
v2 = insert_value v0, { u64, u64 }, v1, 0
v3 = const u64 2
v4 = insert_value v2, { u64, u64 }, v3, 1
store v4, mut ptr { u64, u64 } record
v5 = get_ptr mut ptr { u64, u64 } record
v6 = const u64 50
v7 = insert_value v5, { u64, u64 }, v6, 0
v8 = get_ptr mut ptr { u64, u64 } record
v9 = extract_value v8, { u64, u64 }, 1
ret u64 v9
store v4, ptr v5
v6 = get_ptr mut ptr { u64, u64 } record
v7 = const u64 50
v8 = insert_value v6, { u64, u64 }, v7, 0
v9 = get_ptr mut ptr { u64, u64 } record
v10 = extract_value v9, { u64, u64 }, 1
ret u64 v10
}
}

4 changes: 3 additions & 1 deletion sway-core/tests/ir_to_asm/simple_array.asm
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ lw $r0 data_4 ; literal instantiation
muli $r0 $r0 i8 ; insert_element relative offset
add $r0 $r2 $r0 ; insert_element absolute offset
sw $r0 $r1 i0 ; insert_element
addi $r0 $r3 i0 ; get_ptr
addi $r0 $r3 i0 ; get store offset
mcpi $r0 $r2 i24 ; store value
addi $r1 $r3 i0 ; load address
addi $r1 $r3 i0 ; get_ptr
lw $r0 data_3 ; literal instantiation
muli $r0 $r0 i8 ; extract_element relative offset
add $r0 $r1 $r0 ; extract_element absolute offset
lw $r0 $r0 i0 ; extract_element
ret $r0
noop ; word-alignment of data section
.data:
data_0 .bool 0x00
data_1 .u64 0x00
Expand Down
11 changes: 6 additions & 5 deletions sway-core/tests/ir_to_asm/simple_array.ir
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ script {
v7 = const bool false
v8 = const u64 2
v9 = insert_element v6, [bool; 3], v7, v8
store v9, ptr [bool; 3] a
v10 = load ptr [bool; 3] a
v11 = const u64 1
v12 = extract_element v10, [bool; 3], v11
ret bool v12
v10 = get_ptr ptr [bool; 3] a
store v9, ptr v10
v11 = get_ptr ptr [bool; 3] a
v12 = const u64 1
v13 = extract_element v11, [bool; 3], v12
ret bool v13
}
}
2 changes: 1 addition & 1 deletion sway-core/tests/ir_to_asm/simple_enum.asm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ move $r1 $sp ; save register for temporary stack value
cfei i16 ; allocate 16 bytes for temporary struct
lw $r0 data_0 ; literal instantiation
sw $r1 $r0 i0 ; insert_value @ 0
addi $r0 $r2 i0 ; get_ptr
addi $r0 $r2 i0 ; get store offset
mcpi $r0 $r1 i16 ; store value
addi $r0 $r2 i0 ; get_ptr
Expand All @@ -23,7 +24,6 @@ lw $r0 data_3 ; literal instantiation
sw $r1 $r0 i1 ; insert_value @ 1
lw $r0 data_1 ; literal instantiation
ret $zero ; returning unit as zero
noop ; word-alignment of data section
.data:
data_0 .u64 0x01
data_1 .bool 0x00
Expand Down
Loading

0 comments on commit 142156f

Please sign in to comment.