Cranelift: Deduplicate ABI signatures during lowering (#4829)

* Cranelift: Deduplicate ABI signatures during lowering

This commit creates the `SigSet` type which interns and deduplicates the ABI
signatures that we create from `ir::Signature`s. The ABI signatures are now
referred to indirectly via a `Sig` (which is a `cranelift_entity` ID), and we
pass around a `SigSet` to anything that needs to access the actual underlying
`SigData` (which is what `ABISig` used to be).

I had to change a couple methods to return a `SmallInstVec` instead of emitting
directly to work around what would otherwise be shared and exclusive borrows of
the lowering context overlapping. I don't expect any of these to heap allocate
in practice.

This does not remove the often-unnecessary allocations caused by
`ensure_struct_return_ptr_is_returned`. That is left for follow up work.

This also opens the door for further shuffling of signature data into more
efficient representations in the future, now that we have `SigSet` to store it
all in one place and it is threaded through all the code. We could potentially
move each signature's parameter and return vectors into one big vector shared
between all signatures, for example, which could cut down on allocations and
shrink the size of `SigData` since those `SmallVec`s have pretty large inline
capacity.

Overall, this refactoring gives a 1-7% speedup for compilation on
`pulldown-cmark`:

```
compilation :: cycles :: benchmarks/pulldown-cmark/benchmark.wasm

  Δ = 8754213.66 ± 7526266.23 (confidence = 99%)

  dedupe.so is 1.01x to 1.07x faster than main.so!

  [191003295 234620642.20 280597986] dedupe.so
  [197626699 243374855.86 321816763] main.so

compilation :: cycles :: benchmarks/bz2/benchmark.wasm

  No difference in performance.

  [170406200 194299792.68 253001201] dedupe.so
  [172071888 193230743.11 223608329] main.so

compilation :: cycles :: benchmarks/spidermonkey/benchmark.wasm

  No difference in performance.

  [3870997347 4437735062.59 5216007266] dedupe.so
  [4019924063 4424595349.24 4965088931] main.so
```

* Use full path instead of import to avoid warnings in some build configurations

Warnings will then cause CI to fail.

* Move `SigSet` into `VCode`
This commit is contained in:
Nick Fitzgerald
2022-08-31 13:39:32 -07:00
committed by GitHub
parent 62c5af68b5
commit f18a1f1488
15 changed files with 455 additions and 196 deletions

View File

@@ -4060,7 +4060,7 @@
;; Direct call to an in-range function.
(rule (lower (call (func_ref_data sig_ref name (reloc_distance_near)) args))
(let ((abi ABISig (abi_sig sig_ref))
(let ((abi Sig (abi_sig sig_ref))
(_ Unit (abi_accumulate_outgoing_args_size abi))
(_ InstOutput (lower_call_args abi (range 0 (abi_num_args abi)) args))
(_ InstOutput (side_effect (abi_call abi name (Opcode.Call)))))
@@ -4068,7 +4068,7 @@
;; Direct call to an out-of-range function (implicitly via pointer).
(rule (lower (call (func_ref_data sig_ref name _) args))
(let ((abi ABISig (abi_sig sig_ref))
(let ((abi Sig (abi_sig sig_ref))
(_ Unit (abi_accumulate_outgoing_args_size abi))
(_ InstOutput (lower_call_args abi (range 0 (abi_num_args abi)) args))
(target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0)))
@@ -4077,7 +4077,7 @@
;; Indirect call.
(rule (lower (call_indirect sig_ref ptr args))
(let ((abi ABISig (abi_sig sig_ref))
(let ((abi Sig (abi_sig sig_ref))
(target Reg (put_in_reg ptr))
(_ Unit (abi_accumulate_outgoing_args_size abi))
(_ InstOutput (lower_call_args abi (range 0 (abi_num_args abi)) args))
@@ -4085,14 +4085,14 @@
(lower_call_rets abi (range 0 (abi_num_rets abi)) (output_builder_new))))
;; Lower function arguments.
(decl lower_call_args (ABISig Range ValueSlice) InstOutput)
(decl lower_call_args (Sig Range ValueSlice) InstOutput)
(rule (lower_call_args abi range args)
(let ((_ InstOutput (lower_call_args_buffer abi range args))
(_ InstOutput (lower_call_args_slots abi range args)))
(lower_call_ret_arg abi)))
;; Lower function arguments (part 1): prepare buffer copies.
(decl lower_call_args_buffer (ABISig Range ValueSlice) InstOutput)
(decl lower_call_args_buffer (Sig Range ValueSlice) InstOutput)
(rule (lower_call_args_buffer abi (range_empty) _) (output_none))
(rule (lower_call_args_buffer abi (range_unwrap head tail) args)
(let ((_ InstOutput (copy_to_buffer 0 (abi_get_arg abi head)
@@ -4100,7 +4100,7 @@
(lower_call_args_buffer abi tail args)))
;; Lower function arguments (part 2): set up registers / stack slots.
(decl lower_call_args_slots (ABISig Range ValueSlice) InstOutput)
(decl lower_call_args_slots (Sig Range ValueSlice) InstOutput)
(rule (lower_call_args_slots abi (range_empty) _) (output_none))
(rule (lower_call_args_slots abi (range_unwrap head tail) args)
(let ((_ Unit (copy_to_arg (abi_lane_order abi)
@@ -4109,7 +4109,7 @@
(lower_call_args_slots abi tail args)))
;; Lower function arguments (part 3): implicit return-area pointer.
(decl lower_call_ret_arg (ABISig) InstOutput)
(decl lower_call_ret_arg (Sig) InstOutput)
(rule (lower_call_ret_arg (abi_no_ret_arg)) (output_none))
(rule (lower_call_ret_arg abi @ (abi_ret_arg (abi_arg_only_slot slot)))
(let ((ret_arg Reg (load_addr (memarg_stack_off (abi_sized_stack_arg_space abi) 0)))
@@ -4117,7 +4117,7 @@
(output_none)))
;; Lower function return values by collecting them from registers / stack slots.
(decl lower_call_rets (ABISig Range InstOutputBuilder) InstOutput)
(decl lower_call_rets (Sig Range InstOutputBuilder) InstOutput)
(rule (lower_call_rets abi (range_empty) builder) (output_builder_finish builder))
(rule (lower_call_rets abi (range_unwrap head tail) builder)
(let ((ret ValueRegs (copy_from_arg (abi_lane_order abi)