Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-introduce the single arg contract call optimisation for IR. #1272

Merged
merged 1 commit into from
Apr 17, 2022
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
227 changes: 125 additions & 102 deletions sway-core/src/asm_generation/from_ir.rs

Large diffs are not rendered by default.

142 changes: 96 additions & 46 deletions sway-core/src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,46 +822,103 @@ impl FnCompiler {
.map(|(_, expr)| self.compile_expression(context, expr))
.collect::<Result<Vec<Value>, CompileError>>()?;

// New struct type to hold the user arguments
let field_types = compiled_args
.iter()
.map(|val| val.get_type(context).unwrap())
.collect::<Vec<_>>();
let user_args_struct_aggregate = Aggregate::new_struct(context, field_types);
let user_args_val = match compiled_args.len() {
0 => Constant::get_uint(context, 64, 0, None),
1 => {
// The single arg doesn't need to be put into a struct.
let arg0 = compiled_args[0];

// We're still undecided as to whether this should be decided by type or size.
// Going with type for now.
let arg0_type = arg0.get_type(context).unwrap();
if arg0_type.is_copy_type() {
arg0
} else {
// Copy this value to a new location. This is quite inefficient but we need to
// pass by reference rather than by value. Optimisation passes can remove all
// the unnecessary copying eventually, though it feels like we're jumping
// through a bunch of hoops here (employing the single arg optimisation) for
Comment on lines +839 to +840
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otrho is letting his political opinions leak into the code again

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just an observation. No judgement. 🙂

// minimal returns.
let by_reference_arg_name = self
.lexical_map
.insert(format!("{}{}", "arg_for_", ast_name));
let by_reference_arg = self
.function
.new_local_ptr(context, by_reference_arg_name, arg0_type, false, None)
.map_err(|ir_error| {
CompileError::InternalOwned(ir_error.to_string(), Span::empty())
})?;

let arg0_ptr = self.current_block.ins(context).get_ptr(
by_reference_arg,
arg0_type,
0,
None,
);
self.current_block.ins(context).store(arg0_ptr, arg0, None);

// NOTE: Here we're fetching the original stack pointer, cast to u64.
self.current_block.ins(context).get_ptr(
by_reference_arg,
Type::Uint(64),
0,
span_md_idx,
)
}
}
_ => {
// New struct type to hold the user arguments bundled together.
let field_types = compiled_args
.iter()
.map(|val| val.get_type(context).unwrap())
.collect::<Vec<_>>();
let user_args_struct_aggregate = Aggregate::new_struct(context, field_types);

// New local pointer for the struct to hold all user arguments
let user_args_struct_local_name = self
.lexical_map
.insert(format!("{}{}", "args_struct_for_", ast_name));
let user_args_struct_ptr = self
.function
.new_local_ptr(
context,
user_args_struct_local_name,
Type::Struct(user_args_struct_aggregate),
true,
None,
)
.map_err(|ir_error| {
CompileError::InternalOwned(ir_error.to_string(), Span::empty())
})?;

// New local pointer for the struct to hold all user arguments
let alias_user_args_struct_local_name = self
.lexical_map
.insert(format!("{}{}", "args_struct_for_", ast_name));
let user_args_struct_ptr = self
.function
.new_local_ptr(
context,
alias_user_args_struct_local_name,
Type::Struct(user_args_struct_aggregate),
true,
None,
)
.map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::empty()))?;
// Initialise each of the fields in the user args struct.
compiled_args.into_iter().enumerate().fold(
self.current_block.ins(context).get_ptr(
user_args_struct_ptr,
Type::Struct(user_args_struct_aggregate),
0,
span_md_idx,
),
|user_args_struct_ptr_val, (insert_idx, insert_val)| {
self.current_block.ins(context).insert_value(
user_args_struct_ptr_val,
user_args_struct_aggregate,
insert_val,
vec![insert_idx as u64],
span_md_idx,
)
},
);

// Initialise each of the fields in the user args struct.
compiled_args.into_iter().enumerate().fold(
self.current_block.ins(context).get_ptr(
user_args_struct_ptr,
Type::Struct(user_args_struct_aggregate),
0,
span_md_idx,
),
|user_args_struct_ptr_val, (insert_idx, insert_val)| {
self.current_block.ins(context).insert_value(
user_args_struct_ptr_val,
user_args_struct_aggregate,
insert_val,
vec![insert_idx as u64],
// NOTE: Here we're fetching the original stack pointer, cast to u64.
self.current_block.ins(context).get_ptr(
user_args_struct_ptr,
Type::Uint(64),
0,
span_md_idx,
)
},
);
}
};

// Now handle the contract address and the selector. The contract address is just
// as B256 while the selector is a [u8; 4] which we have to convert to a U64.
Expand Down Expand Up @@ -900,19 +957,12 @@ impl FnCompiler {
span_md_idx,
);

// Insert the pointer to the user args struct.
//
// NOTE: Here we're inserting the original stack pointer, cast to u64.
let user_args_struct_addr_val = self.current_block.ins(context).get_ptr(
user_args_struct_ptr,
Type::Uint(64),
0,
span_md_idx,
);
// Insert the user args value.

ra_struct_val = self.current_block.ins(context).insert_value(
ra_struct_val,
ra_struct_aggregate,
user_args_struct_addr_val,
user_args_val,
vec![2],
span_md_idx,
);
Expand Down
2 changes: 0 additions & 2 deletions sway-core/tests/ir_to_asm/nested_single_word_struct.asm
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ eq $r0 $r1 $r0 ; function selector comparison
jnei $zero $r0 i11 ; jump to selected function
rvrt $zero ; revert if no selectors matched
lw $r0 $fp i74 ; Base register for method parameter
addi $r0 $r0 i0 ; Get address for arg input1
addi $r0 $r0 i0 ; extract address
lw $r0 $r0 i0 ; extract_value @ 0
ret $r0
noop ; word-alignment of data section
.data:
data_0 .u32 0x495d4a23
24 changes: 11 additions & 13 deletions sway-core/tests/ir_to_asm/simple_contract.asm
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ DATA_SECTION_OFFSET[0..32]
DATA_SECTION_OFFSET[32..64]
lw $ds $is 1
add $$ds $$ds $is
lw $r1 $fp i73 ; load input function selector
lw $r0 data_2 ; load fn selector for comparison
eq $r0 $r1 $r0 ; function selector comparison
jnei $zero $r0 i17 ; jump to selected function
lw $r0 data_3 ; load fn selector for comparison
eq $r0 $r1 $r0 ; function selector comparison
jnei $zero $r0 i20 ; jump to selected function
lw $r0 data_4 ; load fn selector for comparison
eq $r0 $r1 $r0 ; function selector comparison
jnei $zero $r0 i24 ; jump to selected function
lw $r0 $fp i73 ; load input function selector
lw $r1 data_2 ; load fn selector for comparison
eq $r1 $r0 $r1 ; function selector comparison
jnei $zero $r1 i17 ; jump to selected function
lw $r1 data_3 ; load fn selector for comparison
eq $r1 $r0 $r1 ; function selector comparison
jnei $zero $r1 i19 ; jump to selected function
lw $r1 data_4 ; load fn selector for comparison
eq $r0 $r0 $r1 ; function selector comparison
jnei $zero $r0 i22 ; jump to selected function
rvrt $zero ; revert if no selectors matched
lw $r0 $fp i74 ; Base register for method parameter
lw $r0 $r0 i0 ; Get arg val
ret $r0
lw $r0 $fp i74 ; Base register for method parameter
addi $r1 $r0 i0 ; Get address for arg val
lw $r1 $fp i74 ; Base register for method parameter
lw $r0 data_0 ; loading size for RETD
retd $r1 $r0
lw $r1 $fp i74 ; Base register for method parameter
Expand Down
112 changes: 54 additions & 58 deletions sway-core/tests/sway_to_ir/simple_contract_call.ir
Original file line number Diff line number Diff line change
@@ -1,78 +1,74 @@
script {
fn main() -> u64 {
local ptr u64 a
local mut ptr { b256 } args_struct_for_get_b256
local ptr b256 arg_for_get_b256
local mut ptr { u64, b256 } args_struct_for_get_s
local mut ptr { u64 } args_struct_for_get_u64
local ptr b256 b
local ptr { u64, b256 } s

entry:
v0 = get_ptr mut ptr { u64 } args_struct_for_get_u64, ptr { u64 }, 0, !1
v1 = const u64 1111, !2
v2 = insert_value v0, { u64 }, v1, 0, !1
v3 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !1
v4 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !3
v5 = insert_value v3, { b256, u64, u64 }, v4, 0, !1
v6 = const u64 2559618804, !1
v7 = insert_value v5, { b256, u64, u64 }, v6, 1, !1
v8 = get_ptr mut ptr { u64 } args_struct_for_get_u64, ptr u64, 0, !1
v9 = insert_value v7, { b256, u64, u64 }, v8, 2, !1
v10 = const u64 0, !4
v11 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !5
v12 = const u64 10000, !6
v13 = contract_call u64 get_u64 v9, v10, v11, v12, !1
v14 = get_ptr ptr u64 a, ptr u64, 0, !7
store v13, ptr v14, !7
v15 = get_ptr mut ptr { b256 } args_struct_for_get_b256, ptr { b256 }, 0, !8
v16 = const b256 0x3333333333333333333333333333333333333333333333333333333333333333, !9
v17 = insert_value v15, { b256 }, v16, 0, !8
v18 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !8
v19 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !10
v20 = insert_value v18, { b256, u64, u64 }, v19, 0, !8
v21 = const u64 1108491158, !8
v22 = insert_value v20, { b256, u64, u64 }, v21, 1, !8
v23 = get_ptr mut ptr { b256 } args_struct_for_get_b256, ptr u64, 0, !8
v24 = insert_value v22, { b256, u64, u64 }, v23, 2, !8
v25 = const u64 0, !11
v26 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !12
v27 = const u64 20000, !13
v28 = contract_call b256 get_b256 v24, v25, v26, v27, !8
v29 = get_ptr ptr b256 b, ptr b256, 0, !14
store v28, ptr v29, !14
v30 = get_ptr mut ptr { u64, b256 } args_struct_for_get_s, ptr { u64, b256 }, 0, !15
v31 = const u64 5555, !16
v32 = insert_value v30, { u64, b256 }, v31, 0, !15
v33 = const b256 0x5555555555555555555555555555555555555555555555555555555555555555, !17
v34 = insert_value v32, { u64, b256 }, v33, 1, !15
v35 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !15
v36 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !18
v37 = insert_value v35, { b256, u64, u64 }, v36, 0, !15
v38 = const u64 4234334249, !15
v39 = insert_value v37, { b256, u64, u64 }, v38, 1, !15
v40 = get_ptr mut ptr { u64, b256 } args_struct_for_get_s, ptr u64, 0, !15
v41 = insert_value v39, { b256, u64, u64 }, v40, 2, !15
v42 = read_register cgas, !15
v43 = const u64 0, !19
v44 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !20
v45 = contract_call { u64, b256 } get_s v41, v43, v44, v42, !15
v46 = get_ptr ptr { u64, b256 } s, ptr { u64, b256 }, 0, !21
store v45, ptr v46, !21
v47 = const u64 0, !22
ret u64 v47
v0 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !1
v1 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !2
v2 = insert_value v0, { b256, u64, u64 }, v1, 0, !1
v3 = const u64 2559618804, !1
v4 = insert_value v2, { b256, u64, u64 }, v3, 1, !1
v5 = const u64 1111, !3
v6 = insert_value v4, { b256, u64, u64 }, v5, 2, !1
v7 = const u64 0, !4
v8 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !5
v9 = const u64 10000, !6
v10 = contract_call u64 get_u64 v6, v7, v8, v9, !1
v11 = get_ptr ptr u64 a, ptr u64, 0, !7
store v10, ptr v11, !7
v12 = get_ptr ptr b256 arg_for_get_b256, ptr b256, 0
v13 = const b256 0x3333333333333333333333333333333333333333333333333333333333333333, !8
store v13, ptr v12
v14 = get_ptr ptr b256 arg_for_get_b256, ptr u64, 0, !9
v15 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !9
v16 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !10
v17 = insert_value v15, { b256, u64, u64 }, v16, 0, !9
v18 = const u64 1108491158, !9
v19 = insert_value v17, { b256, u64, u64 }, v18, 1, !9
v20 = insert_value v19, { b256, u64, u64 }, v14, 2, !9
v21 = const u64 0, !11
v22 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !12
v23 = const u64 20000, !13
v24 = contract_call b256 get_b256 v20, v21, v22, v23, !9
v25 = get_ptr ptr b256 b, ptr b256, 0, !14
store v24, ptr v25, !14
v26 = get_ptr mut ptr { u64, b256 } args_struct_for_get_s, ptr { u64, b256 }, 0, !15
v27 = const u64 5555, !16
v28 = insert_value v26, { u64, b256 }, v27, 0, !15
v29 = const b256 0x5555555555555555555555555555555555555555555555555555555555555555, !17
v30 = insert_value v28, { u64, b256 }, v29, 1, !15
v31 = get_ptr mut ptr { u64, b256 } args_struct_for_get_s, ptr u64, 0, !15
v32 = const { b256, u64, u64 } { b256 undef, u64 undef, u64 undef }, !15
v33 = const b256 0x0c1c50c2bf5ba4bb351b4249a2f5e7d86556fcb4a6ae90465ff6c86126eeb3c0, !18
v34 = insert_value v32, { b256, u64, u64 }, v33, 0, !15
v35 = const u64 4234334249, !15
v36 = insert_value v34, { b256, u64, u64 }, v35, 1, !15
v37 = insert_value v36, { b256, u64, u64 }, v31, 2, !15
v38 = read_register cgas, !15
v39 = const u64 0, !19
v40 = const b256 0x0000000000000000000000000000000000000000000000000000000000000000, !20
v41 = contract_call { u64, b256 } get_s v37, v39, v40, v38, !15
v42 = get_ptr ptr { u64, b256 } s, ptr { u64, b256 }, 0, !21
store v41, ptr v42, !21
v43 = const u64 0, !22
ret u64 v43
}
}

!0 = filepath "/path/to/simple_contract_call.sw"
!1 = span !0 301 458
!2 = span !0 453 457
!3 = span !0 0 66
!2 = span !0 0 66
!3 = span !0 453 457
!4 = span !0 333 334
!5 = span !0 354 420
!6 = span !0 435 440
!7 = span !0 293 459
!8 = span !0 473 693
!9 = span !0 626 692
!8 = span !0 626 692
!9 = span !0 473 693
!10 = span !0 0 66
!11 = span !0 506 507
!12 = span !0 527 593
Expand Down
Loading