x64: Only branch once in br_table (#5850)
This uses the `cmov`, which was previously necessary for Spectre mitigation, to clamp the table index instead of zeroing it. By then placing the default target as the last entry in the table, we can use just one branch instruction in all cases. Since there isn't a bounds-check branch any more, this sequence no longer needs Spectre mitigation. And since we don't need to be careful about preserving flags, half the instructions can be removed from this pseudoinstruction and emitted as regular instructions instead. This is a net savings of three bytes in the encoding of x64's br_table pseudoinstruction. The generated code can sometimes be longer overall because the blocks are emitted in a slightly different order. My benchmark results show a very small effect on runtime performance with this change. The spidermonkey benchmark in Sightglass runs "1.01x faster" than main by instructions retired, but with no significant difference in CPU cycles. I think that means it rarely hit the default case in any br_table instructions it executed. The pulldown-cmark benchmark in Sightglass runs "1.01x faster" than main by CPU cycles, but main runs "1.00x faster" by instructions retired. I think that means this benchmark hit the default case a significant amount of the time, so it executes a few more instructions per br_table, but maybe the branches were predicted better.
This commit is contained in:
@@ -2923,7 +2923,14 @@
|
||||
;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower_branch (br_table idx @ (value_type ty) _) (jump_table_targets default_target jt_targets))
|
||||
(emit_side_effect (jmp_table_seq ty idx default_target jt_targets)))
|
||||
(let ((size OperandSize (raw_operand_size_of_type ty))
|
||||
(jt_size u32 (jump_table_size jt_targets))
|
||||
(size_reg Reg (imm ty (u32_as_u64 jt_size)))
|
||||
(idx_reg Gpr (extend_to_gpr idx $I64 (ExtendKind.Zero)))
|
||||
(clamped_idx Reg (with_flags_reg
|
||||
(x64_cmp size size_reg idx_reg)
|
||||
(cmove ty (CC.B) idx_reg size_reg))))
|
||||
(emit_side_effect (jmp_table_seq ty clamped_idx default_target jt_targets))))
|
||||
|
||||
;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user