Skip to content

Commit c3b8306

Browse files
committed
Use an interpreter in jump threading.
1 parent 396af32 commit c3b8306

File tree

3 files changed

+165
-127
lines changed

3 files changed

+165
-127
lines changed

compiler/rustc_mir_transform/src/jump_threading.rs

+74-24
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,19 @@
3636
//! cost by `MAX_COST`.
3737
3838
use rustc_arena::DroplessArena;
39+
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
3940
use rustc_data_structures::fx::FxHashSet;
4041
use rustc_index::bit_set::BitSet;
4142
use rustc_index::IndexVec;
43+
use rustc_middle::mir::interpret::Scalar;
4244
use rustc_middle::mir::visit::Visitor;
4345
use rustc_middle::mir::*;
44-
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
46+
use rustc_middle::ty::{self, ScalarInt, TyCtxt};
4547
use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem};
48+
use rustc_span::DUMMY_SP;
4649

4750
use crate::cost_checker::CostChecker;
51+
use crate::dataflow_const_prop::DummyMachine;
4852

4953
pub struct JumpThreading;
5054

@@ -70,6 +74,7 @@ impl<'tcx> MirPass<'tcx> for JumpThreading {
7074
let mut finder = TOFinder {
7175
tcx,
7276
param_env,
77+
ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
7378
body,
7479
arena: &arena,
7580
map: &map,
@@ -141,6 +146,7 @@ struct ThreadingOpportunity {
141146
struct TOFinder<'tcx, 'a> {
142147
tcx: TyCtxt<'tcx>,
143148
param_env: ty::ParamEnv<'tcx>,
149+
ecx: InterpCx<'tcx, 'tcx, DummyMachine>,
144150
body: &'a Body<'tcx>,
145151
map: &'a Map,
146152
loop_headers: &'a BitSet<BasicBlock>,
@@ -328,25 +334,75 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
328334
}
329335

330336
#[instrument(level = "trace", skip(self))]
331-
fn process_operand(
337+
fn process_immediate(
332338
&mut self,
333339
bb: BasicBlock,
334340
lhs: PlaceIndex,
335-
rhs: &Operand<'tcx>,
341+
rhs: ImmTy<'tcx>,
336342
state: &mut State<ConditionSet<'a>>,
337343
) -> Option<!> {
338344
let register_opportunity = |c: Condition| {
339345
debug!(?bb, ?c.target, "register");
340346
self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target })
341347
};
342348

349+
let conditions = state.try_get_idx(lhs, self.map)?;
350+
if let Immediate::Scalar(Scalar::Int(int)) = *rhs {
351+
conditions.iter_matches(int).for_each(register_opportunity);
352+
}
353+
354+
None
355+
}
356+
357+
#[instrument(level = "trace", skip(self))]
358+
fn process_operand(
359+
&mut self,
360+
bb: BasicBlock,
361+
lhs: PlaceIndex,
362+
rhs: &Operand<'tcx>,
363+
state: &mut State<ConditionSet<'a>>,
364+
) -> Option<!> {
343365
match rhs {
344366
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
345367
Operand::Constant(constant) => {
346-
let conditions = state.try_get_idx(lhs, self.map)?;
347-
let constant =
348-
constant.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()?;
349-
conditions.iter_matches(constant).for_each(register_opportunity);
368+
let constant = self.ecx.eval_mir_constant(&constant.const_, None, None).ok()?;
369+
self.map.for_each_projection_value(
370+
lhs,
371+
constant,
372+
&mut |elem, op| match elem {
373+
TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
374+
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
375+
TrackElem::Discriminant => {
376+
let variant = self.ecx.read_discriminant(op).ok()?;
377+
let discr_value =
378+
self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?;
379+
Some(discr_value.into())
380+
}
381+
TrackElem::DerefLen => {
382+
let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into();
383+
let len_usize = op.len(&self.ecx).ok()?;
384+
let layout = self
385+
.tcx
386+
.layout_of(self.param_env.and(self.tcx.types.usize))
387+
.unwrap();
388+
Some(ImmTy::from_uint(len_usize, layout).into())
389+
}
390+
},
391+
&mut |place, op| {
392+
if let Some(conditions) = state.try_get_idx(place, self.map)
393+
&& let Ok(imm) = self.ecx.read_immediate_raw(op)
394+
&& let Some(imm) = imm.right()
395+
&& let Immediate::Scalar(Scalar::Int(int)) = *imm
396+
{
397+
conditions.iter_matches(int).for_each(|c: Condition| {
398+
self.opportunities.push(ThreadingOpportunity {
399+
chain: vec![bb],
400+
target: c.target,
401+
})
402+
})
403+
}
404+
},
405+
);
350406
}
351407
// Transfer the conditions on the copied rhs.
352408
Operand::Move(rhs) | Operand::Copy(rhs) => {
@@ -373,26 +429,14 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
373429
// Below, `lhs` is the return value of `mutated_statement`,
374430
// the place to which `conditions` apply.
375431

376-
let discriminant_for_variant = |enum_ty: Ty<'tcx>, variant_index| {
377-
let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
378-
let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
379-
let scalar = ScalarInt::try_from_uint(discr.val, discr_layout.size)?;
380-
Some(Operand::const_from_scalar(
381-
self.tcx,
382-
discr.ty,
383-
scalar.into(),
384-
rustc_span::DUMMY_SP,
385-
))
386-
};
387-
388432
match &stmt.kind {
389433
// If we expect `discriminant(place) ?= A`,
390434
// we have an opportunity if `variant_index ?= A`.
391435
StatementKind::SetDiscriminant { box place, variant_index } => {
392436
let discr_target = self.map.find_discr(place.as_ref())?;
393437
let enum_ty = place.ty(self.body, self.tcx).ty;
394-
let discr = discriminant_for_variant(enum_ty, *variant_index)?;
395-
self.process_operand(bb, discr_target, &discr, state)?;
438+
let discr = self.ecx.discriminant_for_variant(enum_ty, *variant_index).ok()?;
439+
self.process_immediate(bb, discr_target, discr, state)?;
396440
}
397441
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
398442
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(
@@ -422,10 +466,16 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
422466
AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => {
423467
if let Some(discr_target) =
424468
self.map.apply(lhs, TrackElem::Discriminant)
425-
&& let Some(discr_value) =
426-
discriminant_for_variant(agg_ty, *variant_index)
469+
&& let Ok(discr_value) = self
470+
.ecx
471+
.discriminant_for_variant(agg_ty, *variant_index)
427472
{
428-
self.process_operand(bb, discr_target, &discr_value, state);
473+
self.process_immediate(
474+
bb,
475+
discr_target,
476+
discr_value,
477+
state,
478+
);
429479
}
430480
self.map.apply(lhs, TrackElem::Variant(*variant_index))?
431481
}

tests/coverage/partial_eq.cov-map

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ Number of file 0 mappings: 2
2525
- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
2626

2727
Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
28-
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
28+
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
2929
Number of files: 1
3030
- file 0 => global file 1
3131
Number of expressions: 4
3232
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
33-
- expression 1 operands: lhs = Zero, rhs = Counter(2)
33+
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
3434
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
35-
- expression 3 operands: lhs = Zero, rhs = Counter(4)
35+
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
3636
Number of file 0 mappings: 2
3737
- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
3838
- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
39-
= ((Zero + c2) + ((Zero + c4) + c5))
39+
= ((c1 + c2) + ((c3 + c4) + c5))
4040

4141
Function name: <partial_eq::Version as core::fmt::Debug>::fmt
4242
Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]

0 commit comments

Comments
 (0)