Skip to content

Commit ac11636

Browse files
authored
Just use ir::Globals for VMStoreContext pointer in FuncEnvironment (#10526)
And let alias analysis dedupe and clean up multiple uses, instead of trying to do that manually in our Wasm-to-CLIF frontend by loading the pointer once in the entry block and trying to keep track of whether it is actually necessary to pre-declare the pointer and all that. Split off from #10503
1 parent 12195b8 commit ac11636

File tree

2 files changed

+52
-48
lines changed

2 files changed

+52
-48
lines changed

crates/cranelift/src/func_environ.rs

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use cranelift_codegen::ir::types::*;
1414
use cranelift_codegen::ir::{self, types};
1515
use cranelift_codegen::ir::{ArgumentPurpose, Function, InstBuilder, MemFlags};
1616
use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa};
17-
use cranelift_entity::packed_option::ReservedValue as _;
1817
use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap};
1918
use cranelift_frontend::FunctionBuilder;
2019
use cranelift_frontend::Variable;
@@ -118,6 +117,9 @@ pub struct FuncEnvironment<'module_environment> {
118117
/// The Cranelift global holding the vmctx address.
119118
vmctx: Option<ir::GlobalValue>,
120119

120+
/// The Cranelift global for our vmctx's `*mut VMStoreContext`.
121+
vm_store_context: Option<ir::GlobalValue>,
122+
121123
/// The PCC memory type describing the vmctx layout, if we're
122124
/// using PCC.
123125
pcc_vmctx_memtype: Option<ir::MemoryType>,
@@ -136,12 +138,6 @@ pub struct FuncEnvironment<'module_environment> {
136138
/// in `*const VMStoreContext`
137139
fuel_var: cranelift_frontend::Variable,
138140

139-
/// A function-local variable which caches the value of `*const
140-
/// VMStoreContext` for this function's vmctx argument. This pointer is stored
141-
/// in the vmctx itself, but never changes for the lifetime of the function,
142-
/// so if we load it up front we can continue to use it throughout.
143-
vmstore_context_ptr: ir::Value,
144-
145141
/// A cached epoch deadline value, when performing epoch-based
146142
/// interruption. Loaded from `VMStoreContext` and reloaded after
147143
/// any yield.
@@ -196,14 +192,14 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
196192
heaps: PrimaryMap::default(),
197193
tables: SecondaryMap::default(),
198194
vmctx: None,
195+
vm_store_context: None,
199196
pcc_vmctx_memtype: None,
200197
builtin_functions,
201198
offsets: VMOffsets::new(compiler.isa().pointer_bytes(), &translation.module),
202199
tunables,
203200
fuel_var: Variable::new(0),
204201
epoch_deadline_var: Variable::new(0),
205202
epoch_ptr_var: Variable::new(0),
206-
vmstore_context_ptr: ir::Value::reserved_value(),
207203

208204
// Start with at least one fuel being consumed because even empty
209205
// functions should consume at least some fuel.
@@ -308,22 +304,29 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
308304
}
309305
}
310306

311-
fn declare_vmstore_context_ptr(&mut self, builder: &mut FunctionBuilder<'_>) {
312-
// We load the `*const VMStoreContext` value stored within vmctx at the
313-
// head of the function and reuse the same value across the entire
314-
// function. This is possible since we know that the pointer never
315-
// changes for the lifetime of the function.
316-
let pointer_type = self.pointer_type();
317-
let vmctx = self.vmctx(builder.func);
318-
let base = builder.ins().global_value(pointer_type, vmctx);
319-
let offset = i32::from(self.offsets.ptr.vmctx_store_context());
320-
debug_assert!(self.vmstore_context_ptr.is_reserved_value());
321-
self.vmstore_context_ptr = builder.ins().load(
322-
pointer_type,
323-
ir::MemFlags::trusted().with_readonly().with_can_move(),
307+
/// Get or create the `ir::Global` for the `*mut VMStoreContext` in our
308+
/// `VMContext`.
309+
fn get_vmstore_context_ptr_global(&mut self, func: &mut ir::Function) -> ir::GlobalValue {
310+
if let Some(ptr) = self.vm_store_context {
311+
return ptr;
312+
}
313+
314+
let offset = self.offsets.ptr.vmctx_store_context();
315+
let base = self.vmctx(func);
316+
let ptr = func.create_global_value(ir::GlobalValueData::Load {
324317
base,
325-
offset,
326-
);
318+
offset: Offset32::new(offset.into()),
319+
global_type: self.pointer_type(),
320+
flags: ir::MemFlags::trusted().with_readonly().with_can_move(),
321+
});
322+
self.vm_store_context = Some(ptr);
323+
ptr
324+
}
325+
326+
/// Get the `*mut VMStoreContext` value for our `VMContext`.
327+
fn get_vmstore_context_ptr(&mut self, builder: &mut FunctionBuilder) -> ir::Value {
328+
let global = self.get_vmstore_context_ptr_global(&mut builder.func);
329+
builder.ins().global_value(self.pointer_type(), global)
327330
}
328331

329332
fn fuel_function_entry(&mut self, builder: &mut FunctionBuilder<'_>) {
@@ -471,7 +474,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
471474

472475
/// Loads the fuel consumption value from `VMStoreContext` into `self.fuel_var`
473476
fn fuel_load_into_var(&mut self, builder: &mut FunctionBuilder<'_>) {
474-
let (addr, offset) = self.fuel_addr_offset();
477+
let (addr, offset) = self.fuel_addr_offset(builder);
475478
let fuel = builder
476479
.ins()
477480
.load(ir::types::I64, ir::MemFlags::trusted(), addr, offset);
@@ -481,7 +484,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
481484
/// Stores the fuel consumption value from `self.fuel_var` into
482485
/// `VMStoreContext`.
483486
fn fuel_save_from_var(&mut self, builder: &mut FunctionBuilder<'_>) {
484-
let (addr, offset) = self.fuel_addr_offset();
487+
let (addr, offset) = self.fuel_addr_offset(builder);
485488
let fuel_consumed = builder.use_var(self.fuel_var);
486489
builder
487490
.ins()
@@ -490,10 +493,13 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
490493

491494
/// Returns the `(address, offset)` of the fuel consumption within
492495
/// `VMStoreContext`, used to perform loads/stores later.
493-
fn fuel_addr_offset(&mut self) -> (ir::Value, ir::immediates::Offset32) {
494-
debug_assert!(!self.vmstore_context_ptr.is_reserved_value());
496+
fn fuel_addr_offset(
497+
&mut self,
498+
builder: &mut FunctionBuilder<'_>,
499+
) -> (ir::Value, ir::immediates::Offset32) {
500+
let vmstore_ctx = self.get_vmstore_context_ptr(builder);
495501
(
496-
self.vmstore_context_ptr,
502+
vmstore_ctx,
497503
i32::from(self.offsets.ptr.vmstore_context_fuel_consumed()).into(),
498504
)
499505
}
@@ -678,10 +684,11 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
678684
// We keep the deadline cached in a register to speed the checks
679685
// in the common case (between epoch ticks) but we want to do a
680686
// precise check here by reloading the cache first.
687+
let vmstore_ctx = self.get_vmstore_context_ptr(builder);
681688
let deadline = builder.ins().load(
682689
ir::types::I64,
683690
ir::MemFlags::trusted(),
684-
self.vmstore_context_ptr,
691+
vmstore_ctx,
685692
ir::immediates::Offset32::new(self.offsets.ptr.vmstore_context_epoch_deadline() as i32),
686693
);
687694
builder.def_var(self.epoch_deadline_var, deadline);
@@ -3098,15 +3105,11 @@ impl FuncEnvironment<'_> {
30983105
self.conditionally_trap(builder, overflow, ir::TrapCode::STACK_OVERFLOW);
30993106
}
31003107

3101-
// If the `vmstore_context_ptr` variable will get used then we
3102-
// initialize it here.
3103-
if self.tunables.consume_fuel || self.tunables.epoch_interruption {
3104-
self.declare_vmstore_context_ptr(builder);
3105-
}
31063108
// Additionally we initialize `fuel_var` if it will get used.
31073109
if self.tunables.consume_fuel {
31083110
self.fuel_function_entry(builder);
31093111
}
3112+
31103113
// Initialize `epoch_var` with the current epoch.
31113114
if self.tunables.epoch_interruption {
31123115
self.epoch_function_entry(builder);

tests/disas/epoch-interruption.wat

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,34 @@
99
;; gv1 = load.i64 notrap aligned readonly gv0+8
1010
;; gv2 = load.i64 notrap aligned gv1+16
1111
;; gv3 = vmctx
12+
;; gv4 = load.i64 notrap aligned readonly can_move gv3+8
1213
;; sig0 = (i64 vmctx) -> i64 tail
1314
;; fn0 = colocated u1:16 sig0
1415
;; stack_limit = gv2
1516
;;
1617
;; block0(v0: i64, v1: i64):
17-
;; @0016 v5 = load.i64 notrap aligned v0+32
18-
;; @0016 v6 = load.i64 notrap aligned v5
19-
;; @0016 v3 = load.i64 notrap aligned readonly can_move v0+8
20-
;; @0016 v7 = load.i64 notrap aligned v3+8
21-
;; @0016 v8 = icmp uge v6, v7
22-
;; @0016 brif v8, block3, block2(v7)
18+
;; @0016 v3 = load.i64 notrap aligned v0+32
19+
;; @0016 v4 = load.i64 notrap aligned v3
20+
;; @0016 v5 = load.i64 notrap aligned readonly can_move v0+8
21+
;; @0016 v6 = load.i64 notrap aligned v5+8
22+
;; @0016 v7 = icmp uge v4, v6
23+
;; @0016 brif v7, block3, block2(v6)
2324
;;
2425
;; block3 cold:
25-
;; @0016 v10 = call fn0(v0)
26-
;; @0016 jump block2(v10)
26+
;; @0016 v9 = call fn0(v0)
27+
;; @0016 jump block2(v9)
2728
;;
2829
;; block2(v21: i64):
2930
;; @0017 jump block4(v21)
3031
;;
31-
;; block4(v13: i64):
32-
;; @0017 v12 = load.i64 notrap aligned v5
33-
;; @0017 v14 = icmp uge v12, v13
34-
;; @0017 brif v14, block7, block6(v13)
32+
;; block4(v12: i64):
33+
;; @0017 v11 = load.i64 notrap aligned v3
34+
;; @0017 v13 = icmp uge v11, v12
35+
;; @0017 brif v13, block7, block6(v12)
3536
;;
3637
;; block7 cold:
37-
;; @0017 v15 = load.i64 notrap aligned v3+8
38-
;; @0017 v16 = icmp.i64 uge v12, v15
38+
;; @0017 v15 = load.i64 notrap aligned v5+8
39+
;; @0017 v16 = icmp.i64 uge v11, v15
3940
;; @0017 brif v16, block8, block6(v15)
4041
;;
4142
;; block8 cold:

0 commit comments

Comments
 (0)