Skip to content

Commit d3a0053

Browse files
committed
Refactor dead_load_with_context so we can capture pre- and post-instruction offsets.
x64 movq instructions are usually 3 bytes but grow to 4 when the source reg is R12 (or RSP). We'll need to know which at each callsite so we can both identify MMU-driven epoch interrupts (beginning offset) and resume at the right location (ending offset). Also... * Store the dead load's result to r10, which we're clobbering anyway, to save a reg. * Remove the x64_dead_load_with_context layer.
1 parent d080776 commit d3a0053

6 files changed

Lines changed: 39 additions & 29 deletions

File tree

cranelift/codegen/src/isa/x64/inst.isle

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@
194194
(offset i64)
195195
(distance RelocDistance))
196196

197-
(DeadLoadWithContext (load_ptr Gpr)
197+
(DeadLoadWithContext (dst WritableGpr)
198+
(load_ptr Gpr)
198199
(context Gpr))
199200

200201
;; =========================================
@@ -1345,12 +1346,6 @@
13451346
(rule (return_call_unknown info)
13461347
(SideEffectNoResult.Inst (MInst.ReturnCallUnknown info)))
13471348

1348-
;; Helper for creating `DeadLoadWithContext` instructions.
1349-
(decl x64_dead_load_with_context (Gpr Gpr) SideEffectNoResult)
1350-
(rule (x64_dead_load_with_context load_ptr context)
1351-
(SideEffectNoResult.Inst (MInst.DeadLoadWithContext load_ptr
1352-
context)))
1353-
13541349
;;;; Helpers for emitting stack switches ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13551350

13561351
(decl x64_stack_switch_basic (Gpr Gpr Gpr) Gpr)

cranelift/codegen/src/isa/x64/inst/emit.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,19 @@ pub(crate) fn emit(
645645
sink.bind_label(resume, state.ctrl_plane_mut());
646646
}
647647

648-
Inst::DeadLoadWithContext { .. } => {
649-
// The ISLE has already emitted the dead load. Put the address of
650-
// this instruction aside so we can later distinguish whether a
651-
// segfault is its fault.
648+
Inst::DeadLoadWithContext { dst, load_ptr, .. } => {
649+
let start = sink.cur_offset();
650+
651+
// Since we're clobbering r10 anyway to store the original return
652+
// address, we also use it as a destination for the dead load rather
653+
// than sucking up another reg:
654+
let load_ptr_addr = SyntheticAmode::real(Amode::imm_reg(0, **load_ptr));
655+
asm::inst::movq_rm::new(*dst, load_ptr_addr).emit(sink, info, state);
656+
657+
let end = sink.cur_offset();
658+
659+
// Put the address of this instruction aside so we can later
660+
// distinguish whether a segfault is its fault.
652661
sink.add_epoch_check();
653662
}
654663

cranelift/codegen/src/isa/x64/inst/mod.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! This module defines x86_64-specific machine instruction types.
22
33
pub use emit_state::EmitState;
4-
use regalloc2::PRegSet;
54

65
use crate::binemit::{Addend, CodeOffset, Reloc};
76
use crate::ir::{ExternalName, LibCall, TrapCode, Type, types};
@@ -673,10 +672,15 @@ impl PrettyPrint for Inst {
673672
)
674673
}
675674

676-
Inst::DeadLoadWithContext { load_ptr, context } => {
675+
Inst::DeadLoadWithContext {
676+
dst,
677+
load_ptr,
678+
context,
679+
} => {
680+
let dst = pretty_print_reg(*dst.to_reg(), 8);
677681
let load_ptr = pretty_print_reg(**load_ptr, 8);
678682
let context = pretty_print_reg(**context, 8);
679-
format!("dead_load_with_context {load_ptr}, {context}")
683+
format!("dead_load_with_context {dst}, {load_ptr}, {context}")
680684
}
681685

682686
Inst::JmpKnown { dst } => {
@@ -1053,7 +1057,11 @@ fn x64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) {
10531057
collector.reg_clobbers(clobbers);
10541058
}
10551059

1056-
Inst::DeadLoadWithContext { load_ptr, context } => {
1060+
Inst::DeadLoadWithContext {
1061+
dst,
1062+
load_ptr,
1063+
context,
1064+
} => {
10571065
// load_ptr is an input param.
10581066
collector.reg_use(load_ptr);
10591067
// Demand context (vmctx) go into RDI.
@@ -1063,7 +1071,10 @@ fn x64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) {
10631071
// address (which we're overwriting with that of the epoch-ending
10641072
// stub). Picking r10 because it's caller-saved but otherwise
10651073
// arbitrarily.
1066-
collector.reg_clobbers(PRegSet::empty().with(regs::gpr_preg(asm::gpr::enc::R10)));
1074+
//
1075+
// Also def it so we can use it as the destination of the dead load
1076+
// rather than consuming another arbitrary reg.
1077+
collector.reg_fixed_def(dst, regs::r10());
10671078
}
10681079

10691080
Inst::ReturnCallKnown { info } => {

cranelift/codegen/src/isa/x64/lower.isle

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,18 +3581,13 @@
35813581
;;;; Rules for `dead_load_with_context` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35823582

35833583
(rule (lower (dead_load_with_context load_ptr context))
3584-
(let (
3585-
;; Put vmctx into rdi. TODO: Do we have to shove context in a different reg first? The type system seems happy to allow it without.
3586-
;; Actually, I suspect we don't even need to do this move; because we use reg_fixed_use() to constrain the `context` arg of DeadLoadWithContext to RDI, I hypothesize regalloc will insert any MOV needed to make that so. It is, after all, in the business of inserting MOVs for spills.
3587-
;; (_ SideEffectNoResult (mov_to_preg (preg_rdi) context))
3588-
3589-
;; Load from load_ptr to perhaps trigger a trap.
3590-
;; TODO: May be able to change x64_load to higher-level "load", from codegen/meta/src/shared/instructions.rs.
3591-
(_ Gpr (x64_load $I64 (to_amode (mem_flags_aligned_read_only)
3584+
(let ((load_ptr Gpr (put_in_gpr load_ptr))
3585+
(context Gpr (put_in_gpr context))
3586+
(dst WritableGpr (temp_writable_gpr))
3587+
(_ Unit (emit_side_effect (SideEffectNoResult.Inst
3588+
(MInst.DeadLoadWithContext dst
35923589
load_ptr
3593-
(zero_offset))
3594-
(ExtKind.None)))
3595-
(_ Unit (emit_side_effect (x64_dead_load_with_context load_ptr context))))
3590+
context)))))
35963591
(output_none)))
35973592

35983593
;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;

tests/disas/epoch-interruption-mmu-compile-loop.wat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
;; movq %rsp, %rbp
1515
;; movq 8(%rdi), %r8
1616
;; movq 0x10(%r8), %r8
17-
;; movq (%r8), %r9
17+
;; movq (%r8), %r10
1818
;; movq (%r8), %r10
1919
;; jmp 0xf

tests/disas/epoch-interruption-mmu-compile.wat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
;; movq %rsp, %rbp
1212
;; movq 8(%rdi), %rdx
1313
;; movq 0x10(%rdx), %rdx
14-
;; movq (%rdx), %r8
14+
;; movq (%rdx), %r10
1515
;; movq %rbp, %rsp
1616
;; popq %rbp
1717
;; retq

0 commit comments

Comments
 (0)