Skip to content

Commit 7b24347

Browse files
committed
Auto merge of rust-lang#116012 - cjgillot:gvn-const, r=<try>
Implement constant propagation on top of MIR SSA analysis This implements the idea I proposed in rust-lang#110719 (comment) Based on rust-lang#109597 The value numbering "GVN" pass formulates each rvalue that appears in MIR with an abstract form (the `Value` enum), and assigns an integer `VnIndex` to each. This abstract form can be used to deduplicate values, reusing an earlier local that holds the same value instead of recomputing. This part is proposed in rust-lang#109597. From this abstract representation, we can perform more involved simplifications, for example in rust-lang#111344. With the abstract representation `Value`, we can also attempt to evaluate each to a constant using the interpreter. This builds a `VnIndex -> OpTy` map. From this map, we can opportunistically replace an operand or a rvalue with a constant if their value has an associated `OpTy`. The most relevant commit is [Evaluated computed values to constants.](rust-lang@2767c49)" r? `@oli-obk`
2 parents 0237aa3 + 81d5ac4 commit 7b24347

File tree

252 files changed

+9265
-2284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

252 files changed

+9265
-2284
lines changed

Diff for: compiler/rustc_codegen_ssa/src/mir/operand.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
135135
assert_eq!(alloc_align, layout.align.abi);
136136

137137
let read_scalar = |start, size, s: abi::Scalar, ty| {
138-
let val = alloc
139-
.0
140-
.read_scalar(
141-
bx,
142-
alloc_range(start, size),
143-
/*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)),
144-
)
145-
.unwrap();
146-
bx.scalar_to_backend(val, s, ty)
138+
match alloc.0.read_scalar(
139+
bx,
140+
alloc_range(start, size),
141+
/*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)),
142+
) {
143+
Ok(val) => bx.scalar_to_backend(val, s, ty),
144+
Err(_) => bx.const_poison(ty),
145+
}
147146
};
148147

149148
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
@@ -156,18 +155,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
156155
Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => {
157156
let size = s.size(bx);
158157
assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
159-
let val = read_scalar(Size::ZERO, size, s, bx.type_ptr());
158+
let val = read_scalar(offset, size, s, bx.backend_type(layout));
160159
OperandRef { val: OperandValue::Immediate(val), layout }
161160
}
162161
Abi::ScalarPair(
163162
a @ abi::Scalar::Initialized { .. },
164163
b @ abi::Scalar::Initialized { .. },
165164
) => {
166165
let (a_size, b_size) = (a.size(bx), b.size(bx));
167-
let b_offset = a_size.align_to(b.align(bx).abi);
166+
let b_offset = (offset + a_size).align_to(b.align(bx).abi);
168167
assert!(b_offset.bytes() > 0);
169168
let a_val = read_scalar(
170-
Size::ZERO,
169+
offset,
171170
a_size,
172171
a,
173172
bx.scalar_pair_element_backend_type(layout, 0, true),

Diff for: compiler/rustc_const_eval/src/interpret/discriminant.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Functions for reading and writing discriminants of multi-variant layouts (enums and generators).
22
3-
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
4-
use rustc_middle::{mir, ty};
3+
use rustc_middle::mir;
4+
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
5+
use rustc_middle::ty::{self, Ty};
56
use rustc_target::abi::{self, TagEncoding};
67
use rustc_target::abi::{VariantIdx, Variants};
78

@@ -244,11 +245,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
244245

245246
pub fn discriminant_for_variant(
246247
&self,
247-
layout: TyAndLayout<'tcx>,
248+
ty: Ty<'tcx>,
248249
variant: VariantIdx,
249250
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
250-
let discr_layout = self.layout_of(layout.ty.discriminant_ty(*self.tcx))?;
251-
let discr_value = match layout.ty.discriminant_for_variant(*self.tcx, variant) {
251+
let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?;
252+
let discr_value = match ty.discriminant_for_variant(*self.tcx, variant) {
252253
Some(discr) => {
253254
// This type actually has discriminants.
254255
assert_eq!(discr.ty, discr_layout.ty);

Diff for: compiler/rustc_const_eval/src/interpret/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
219219
sym::discriminant_value => {
220220
let place = self.deref_pointer(&args[0])?;
221221
let variant = self.read_discriminant(&place)?;
222-
let discr = self.discriminant_for_variant(place.layout, variant)?;
222+
let discr = self.discriminant_for_variant(place.layout.ty, variant)?;
223223
self.write_immediate(*discr, dest)?;
224224
}
225225
sym::exact_div => {

Diff for: compiler/rustc_const_eval/src/interpret/operand.rs

+10
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
163163
ImmTy { imm: val.into(), layout }
164164
}
165165

166+
#[inline]
167+
pub fn from_scalar_pair(a: Scalar<Prov>, b: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
168+
debug_assert!(
169+
matches!(layout.abi, Abi::ScalarPair(..)),
170+
"`ImmTy::from_scalar_pair` on non-scalar-pair layout"
171+
);
172+
let imm = Immediate::ScalarPair(a, b);
173+
ImmTy { imm, layout }
174+
}
175+
166176
#[inline(always)]
167177
pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
168178
debug_assert!(

Diff for: compiler/rustc_const_eval/src/interpret/step.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
300300
Discriminant(place) => {
301301
let op = self.eval_place_to_op(place, None)?;
302302
let variant = self.read_discriminant(&op)?;
303-
let discr = self.discriminant_for_variant(op.layout, variant)?;
303+
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
304304
self.write_immediate(*discr, &dest)?;
305305
}
306306
}

Diff for: compiler/rustc_middle/src/mir/consts.rs

+12
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,18 @@ impl<'tcx> ConstValue<'tcx> {
172172
let end = end.try_into().unwrap();
173173
Some(data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end))
174174
}
175+
176+
pub fn has_provenance(&self, tcx: TyCtxt<'tcx>, size: Size) -> bool {
177+
let (alloc, start, end) = match *self {
178+
ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false,
179+
ConstValue::Scalar(Scalar::Ptr(..)) => return true,
180+
ConstValue::Slice { data, meta } => (data, Size::ZERO, Size::from_bytes(meta)),
181+
ConstValue::Indirect { alloc_id, offset } => {
182+
(tcx.global_alloc(alloc_id).unwrap_memory(), offset, offset + size)
183+
}
184+
};
185+
!alloc.inner().provenance().range_empty(super::AllocRange::from(start..end), &tcx)
186+
}
175187
}
176188

177189
///////////////////////////////////////////////////////////////////////////

Diff for: compiler/rustc_middle/src/mir/syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ pub enum AggregateKind<'tcx> {
13331333
Generator(DefId, GenericArgsRef<'tcx>, hir::Movability),
13341334
}
13351335

1336-
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
1336+
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
13371337
pub enum NullOp<'tcx> {
13381338
/// Returns the size of a value of that type
13391339
SizeOf,

0 commit comments

Comments
 (0)