Skip to content

Commit a8a5d1e

Browse files
committed
Fix test and perform removals after fixpoint
1 parent c559dfa commit a8a5d1e

2 files changed

Lines changed: 47 additions & 43 deletions

File tree

‎zjit/src/hir.rs‎

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6743,6 +6743,13 @@ impl Function {
67436743
// The cache is pruned when loads and stores can alias between objects.
67446744
let mut cached_insns: Vec<HashMap<Key, InsnId>> = vec![HashMap::new(); cfi.num_blocks];
67456745

6746+
// An available expression is an expression that has already been computed with values that have not changed since the last computation.
6747+
// In this case, available expressions == redundant loads and stores
6748+
// To compute the available expressions, we need to know which expressions have been evaluated, and when effectful operations interrupt the optimization.
6749+
// This information is stored in cached_insns and is used to populate available_expressions.
6750+
// Once the fixpoint loop is finished, we elide all available expressions, concluding the load store forwarding pass.
6751+
let mut available_expressions: InsnSet = InsnSet::with_capacity(self.insns.len());
6752+
67466753
loop {
67476754
for (rpo_index, &block_id) in rpo.iter().enumerate() {
67486755
// Set block_cache equal to the intersection of cached insns of all predecessors
@@ -6767,22 +6774,17 @@ impl Function {
67676774

67686775
}
67696776
};
6770-
let old_insns = std::mem::take(&mut self.blocks[block_id].insns);
6771-
let mut new_insns = Vec::with_capacity(old_insns.len());
6772-
for insn_id in old_insns {
6773-
let replacement_insn: InsnId = match self.resolve(insn_id).insn(self) {
6777+
let insns = std::mem::take(&mut self.blocks[block_id].insns);
6778+
for insn_id in insns.iter() {
6779+
match self.resolve(*insn_id).insn(self) {
67746780
&Insn::StoreField { recv, offset, val, .. } => {
67756781
let key = Key { id: self.chase_insn(recv), offset };
67766782
let heap_entry = block_cache.get(&key).copied();
6777-
// TODO(Jacob): Switch from actual to partial equality
67786783
if Some(val) == heap_entry {
6779-
// If the value is already stored, short circuit and don't add an instruction to the block
6780-
continue
6784+
available_expressions.insert(*insn_id);
67816785
}
6782-
// TODO(Jacob): Add type based alias analysis to avoid removing so many entries
67836786
block_cache.retain(|key, _| key.offset != offset);
67846787
block_cache.insert(key, val);
6785-
insn_id
67866788
},
67876789
&Insn::LoadField { recv, offset, return_type, .. } => {
67886790
let key = Key { id: self.chase_insn(recv), offset };
@@ -6803,38 +6805,32 @@ impl Function {
68036805
if can_forward_cached_insn {
68046806
// If the value is stored already, we should short circuit.
68056807
// However, we need to replace insn_id with its representative in the SSA union.
6806-
self.make_equal_to(insn_id, cached_insn);
6807-
continue
6808+
self.make_equal_to(*insn_id, cached_insn);
6809+
available_expressions.insert(*insn_id);
68086810
}
68096811
}
68106812
Entry::Vacant(entry) => {
68116813
// If the value has not been accessed, cache a copy to optimize future loads or stores.
6812-
entry.insert(insn_id);
6814+
entry.insert(*insn_id);
68136815
}
68146816
}
6815-
insn_id
68166817
}
68176818
&Insn::WriteBarrier { .. } => {
68186819
// Currently, WriteBarrier write effects are Allocator and Memory when we'd really like them to be flags.
68196820
// We don't use LoadField for mark bits so we can ignore them for now.
68206821
// But flags does not exist in our effects abstract heap modeling and we don't want to add special casing to effects.
68216822
// This special casing in this pass here should be removed once we refine our effects system to provide greater granularity for WriteBarrier.
6822-
// TODO: use type based alias analysis
68236823
let offset = RUBY_OFFSET_RBASIC_FLAGS;
68246824
block_cache.retain(|key, _| key.offset != offset);
6825-
insn_id
68266825
},
68276826
insn => {
68286827
if insn.effects_of().includes(Effect::write(abstract_heaps::Memory)) {
68296828
block_cache.clear();
68306829
}
6831-
insn_id
68326830
}
68336831
};
6834-
new_insns.push(replacement_insn);
68356832
}
6836-
6837-
self.blocks[block_id].insns = new_insns;
6833+
self.blocks[block_id].insns = insns;
68386834

68396835
if cached_insns[block_id] == block_cache {
68406836
changed = false;
@@ -6848,6 +6844,10 @@ impl Function {
68486844
break;
68496845
}
68506846
}
6847+
6848+
for &block_id in rpo {
6849+
self.blocks[block_id].insns.retain(|&insn_id| !available_expressions.get(insn_id));
6850+
}
68516851
}
68526852

68536853
/// Fold a binary operator on fixnums.

‎zjit/src/hir/opt_tests.rs‎

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26253,7 +26253,8 @@ mod hir_opt_tests {
2625326253
def read(val)
2625426254
even = val.even?
2625526255
a = @value
26256-
even ? a : @value + 1
26256+
b = even ? 0 : 1
26257+
a + b
2625726258
end
2625826259
end
2625926260

@@ -26274,34 +26275,37 @@ mod hir_opt_tests {
2627426275
Jump bb3(v1, v3)
2627526276
bb2():
2627626277
EntryPoint JIT(0)
26277-
v8:BasicObject = LoadArg :self@0
26278-
v9:BasicObject = LoadArg :val@1
26279-
Jump bb3(v8, v9)
26280-
bb3(v13:BasicObject, v14:BasicObject):
26281-
v74:NilClass = Const Value(nil)
26282-
v73:NilClass = Const Value(nil)
26278+
v9:BasicObject = LoadArg :self@0
26279+
v10:BasicObject = LoadArg :val@1
26280+
Jump bb3(v9, v10)
26281+
bb3(v15:BasicObject, v16:BasicObject):
26282+
v85:NilClass = Const Value(nil)
26283+
v84:NilClass = Const Value(nil)
26284+
v83:NilClass = Const Value(nil)
2628326285
PatchPoint MethodRedefined(Integer@0x1008, even?@0x1010, cme:0x1018)
26284-
v67:Fixnum = GuardType v14, Fixnum recompile
26285-
v68:BoolExact = InvokeBuiltin leaf <inline_expr>, v67
26286+
v77:Fixnum = GuardType v16, Fixnum recompile
26287+
v78:BoolExact = InvokeBuiltin leaf <inline_expr>, v77
2628626288
PatchPoint NoEPEscape(read)
26287-
v27:HeapBasicObject = GuardType v13, HeapBasicObject
26288-
v28:CShape = LoadField v27, :shape_id@0x1040
26289-
v29:CShape[0x1041] = GuardBitEquals v28, CShape(0x1041) recompile
26290-
v30:BasicObject = LoadField v27, :@value@0x1042
26291-
v37:CBool = Test v68
26292-
v38:FalseClass = RefineType v68, Falsy
26293-
CondBranch v37, bb5(), bb4()
26294-
bb5():
26295-
v40:TrueClass = RefineType v68, Truthy
26296-
CheckInterrupts
26297-
Return v30
26289+
v30:HeapBasicObject = GuardType v15, HeapBasicObject
26290+
v31:CShape = LoadField v30, :shape_id@0x1040
26291+
v32:CShape[0x1041] = GuardBitEquals v31, CShape(0x1041) recompile
26292+
v33:BasicObject = LoadField v30, :@value@0x1042
26293+
v40:CBool = Test v78
26294+
v41:FalseClass = RefineType v78, Falsy
26295+
CondBranch v40, bb6(), bb4()
26296+
bb6():
26297+
v43:TrueClass = RefineType v78, Truthy
26298+
v45:Fixnum[0] = Const Value(0)
26299+
Jump bb5(v43, v45)
2629826300
bb4():
26299-
v57:Fixnum[1] = Const Value(1)
26301+
v55:Fixnum[1] = Const Value(1)
26302+
Jump bb5(v41, v55)
26303+
bb5(v59:BoolExact, v62:Fixnum):
2630026304
PatchPoint MethodRedefined(Integer@0x1008, +@0x1043, cme:0x1048)
26301-
v71:Fixnum = GuardType v30, Fixnum recompile
26302-
v72:Fixnum = FixnumAdd v71, v57
26305+
v81:Fixnum = GuardType v33, Fixnum recompile
26306+
v82:Fixnum = FixnumAdd v81, v62
2630326307
CheckInterrupts
26304-
Return v72
26308+
Return v82
2630526309
"
2630626310
);
2630726311
}

0 commit comments

Comments
 (0)