Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,7 +1535,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, operand)
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
| Rvalue::ShallowInitBox(operand, _ /*ty*/)
| Rvalue::StaticallyKnown(operand) => {
self.consume_operand(location, (operand, span), state)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, operand)
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
| Rvalue::ShallowInitBox(operand, _ /*ty*/)
| Rvalue::StaticallyKnown(operand) => self.consume_operand(location, operand),

&Rvalue::CopyForDeref(place) => {
let op = &Operand::Copy(place);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _)
| Rvalue::StaticallyKnown(_) => {}
}
}

Expand Down Expand Up @@ -2209,7 +2210,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::CopyForDeref(..)
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..)
| Rvalue::WrapUnsafeBinder(..) => None,
| Rvalue::WrapUnsafeBinder(..)
| Rvalue::StaticallyKnown(..) => None,

Rvalue::Aggregate(aggregate, _) => match **aggregate {
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,15 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
let operand = codegen_operand(fx, operand);
lval.write_cvalue_transmute(fx, operand);
}
Rvalue::StaticallyKnown(_) => {
// Cranelift doesn't have an exquivalent for this. Just
// return `false` unconditionally.
let val = CValue::by_val(
fx.bcx.ins().iconst(types::I8, i64::from(false)),
fx.layout_of(fx.tcx.types.bool),
);
lval.write_cvalue(fx, val);
}
}
}
StatementKind::StorageLive(_)
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.gcc_checked_binop(oop, typ, lhs, rhs)
}

fn is_constant(&mut self, val: Self::Value) -> Self::Value {
let builtin = self.context.get_builtin_function("__builtin_constant_p");
let res = self.context.new_call(None, builtin, &[val]);
self.icmp(IntPredicate::IntEQ, res, self.const_i32(0))
}

fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> {
let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes());
// TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial.
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}
sym::is_val_statically_known => {
let a = args[0].immediate();
let builtin = self.context.get_builtin_function("__builtin_constant_p");
let res = self.context.new_call(None, builtin, &[a]);
self.icmp(IntPredicate::IntEQ, res, self.const_i32(0))
}
sym::catch_unwind => {
try_intrinsic(
self,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
}

fn is_constant(&mut self, val: Self::Value) -> Self::Value {
self.call_intrinsic("llvm.is.constant", &[self.cx.val_ty(val)], &[val])
}

/* Miscellaneous instructions */
fn memcpy(
&mut self,
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,17 +198,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
codegen_autodiff(self, tcx, instance, args, result);
return Ok(());
}
sym::is_val_statically_known => {
if let OperandValue::Immediate(imm) = args[0].val {
self.call_intrinsic(
"llvm.is.constant",
&[args[0].layout.immediate_llvm_type(self.cx)],
&[imm],
)
} else {
self.const_bool(false)
}
}
sym::select_unpredictable => {
let cond = args[0].immediate();
assert_eq!(args[1].layout, args[2].layout);
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let layout = bx.cx().layout_of(binder_ty);
OperandRef { val: operand.val, layout }
}
mir::Rvalue::StaticallyKnown(ref operand) => {
let operand = self.codegen_operand(bx, operand);
let val = match operand.val {
// This would need to insert some loads for the type. That's
// unlikely to be profitable, so just collapse to `false`.
OperandValue::Ref(..) => bx.const_bool(false),
OperandValue::Immediate(val) => bx.is_constant(val),
OperandValue::Pair(lval, rval) => {
let l = bx.is_constant(lval);
let r = bx.is_constant(rval);
bx.and(l, r)
}
// A zero-sized value is always constant, so the backend
// knows everything there is to know about it.
OperandValue::ZeroSized => bx.const_bool(true),
};
OperandRef {
val: OperandValue::Immediate(val),
layout: bx.cx().layout_of(bx.tcx().types.bool),
}
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,15 @@ pub trait BuilderMethods<'a, 'tcx>:
self.assume(is_null);
}

/// Returns whether `val` has a value known at compile-time.
///
/// Defaults to always returning `false`, since returning `true` might trick
/// the program into performing costly checks that only make sense at
/// compile-time.
fn is_constant(&mut self, _val: Self::Value) -> Self::Value {
self.const_bool(false)
}

fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::WrapUnsafeBinder(..) => {
// Unsafe binders are always trivial to create.
}

Rvalue::StaticallyKnown(..) => {
// We can always choose a value for this.
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ where
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_, operand)
| Rvalue::Cast(_, operand, _)
| Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
| Rvalue::ShallowInitBox(operand, _)
| Rvalue::StaticallyKnown(operand) => in_operand::<Q, _>(cx, in_local, operand),

Rvalue::BinaryOp(_, box (lhs, rhs)) => {
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ where
| mir::Rvalue::UnaryOp(..)
| mir::Rvalue::Discriminant(..)
| mir::Rvalue::Aggregate(..)
| mir::Rvalue::WrapUnsafeBinder(..) => {}
| mir::Rvalue::WrapUnsafeBinder(..)
| mir::Rvalue::StaticallyKnown(..) => {}
}
}

Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,12 +548,6 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
ecx.write_pointer(ptr, dest)?;
}

// The intrinsic represents whether the value is known to the optimizer (LLVM).
// We're not doing any optimizations here, so there is no optimizer that could know the value.
// (We know the value here in the machine of course, but this is the runtime of that code,
// not the optimization stage.)
sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?,

// We handle these here since Miri does not want to have them.
sym::assert_inhabited
| sym::assert_zero_valid
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_const_eval/src/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@ pub trait Machine<'tcx>: Sized {
a
}

/// Computes the result of `is_val_statically_known`.
///
/// The default implementation always returns `false`, but this could also
/// non-deterministically choose a value (miri does that to fully explore
/// the possible AM executions).
fn is_val_statically_known(
_ecx: &InterpCx<'tcx, Self>,
_val: &OpTy<'tcx, Self::Provenance>,
) -> InterpResult<'tcx, bool> {
interp_ok(false)
}

/// Called before a basic block terminator is executed.
#[inline]
fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let op = self.eval_operand(op, None)?;
self.copy_op_allow_transmute(&op, &dest)?;
}

StaticallyKnown(ref op) => {
let op = self.eval_operand(op, None)?;
let known = M::is_val_statically_known(self, &op)?;
self.write_scalar(Scalar::from_bool(known), &dest)?;
}
}

trace!("{:?}", self.dump_place(&dest));
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
WrapUnsafeBinder(ref op, ty) => {
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
}

StaticallyKnown(ref op) => {
write!(fmt, "StaticallyKnown({op:?})")
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,8 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true,
| Rvalue::WrapUnsafeBinder(_, _)
| Rvalue::StaticallyKnown(_) => true,
}
}

Expand Down Expand Up @@ -772,6 +773,7 @@ impl<'tcx> Rvalue<'tcx> {
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
Rvalue::WrapUnsafeBinder(_, ty) => ty,
Rvalue::StaticallyKnown(_) => tcx.types.bool,
}
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,13 @@ pub enum Rvalue<'tcx> {

/// Wraps a value in an unsafe binder.
WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>),

/// Yields a boolean that indicates whether the value of the operand is
/// known during optimization.
///
/// From an operational semantics perspective, the result is
/// non-deterministically chosen.
StaticallyKnown(Operand<'tcx>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this will still evaluate the Operand for UB side-effects?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at least it might. Skipping it should be sound though, right? And miri should detect the UB because const-eval calls eval_operand...

}

#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,10 @@ macro_rules! make_mir_visitor {
self.visit_operand(op, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}

Rvalue::StaticallyKnown(op) => {
self.visit_operand(op, location);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ where
| Rvalue::Discriminant(..)
| Rvalue::Aggregate(..)
| Rvalue::CopyForDeref(..)
| Rvalue::WrapUnsafeBinder(..) => {}
| Rvalue::WrapUnsafeBinder(..)
| Rvalue::StaticallyKnown(..) => {}
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_dataflow/src/move_paths/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| Rvalue::Cast(_, ref operand, _)
| Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand)
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
| Rvalue::WrapUnsafeBinder(ref operand, _)
| Rvalue::StaticallyKnown(ref operand) => self.gather_operand(operand),
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
self.gather_operand(lhs);
self.gather_operand(rhs);
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_mir_transform/src/dataflow_const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,16 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx))
}
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
Rvalue::StaticallyKnown(op) => {
match self.eval_operand(op, state) {
// The constant value of the argument is known to this pass
// and can be used for further optimizations. Collapsing to
// `true` is thus likely to be profitable.
FlatSet::Elem(_) => FlatSet::Elem(Scalar::from_bool(true)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
}
Rvalue::Use(operand) => return self.handle_operand(operand, state),
Rvalue::CopyForDeref(place) => {
return self.handle_operand(&Operand::Copy(*place), state);
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
Value::Discriminant(place)
}
Rvalue::StaticallyKnown(ref mut arg_op) => {
return self.simplify_statically_known(arg_op, location);
}

// Unsupported values.
Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None,
Expand Down Expand Up @@ -1440,6 +1443,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
Some(self.insert(self.tcx.types.usize, Value::Len(inner)))
}

fn simplify_statically_known(
&mut self,
arg_op: &mut Operand<'tcx>,
location: Location,
) -> Option<VnIndex> {
let value = self.simplify_operand(arg_op, location)?;
match self.evaluated[value] {
// `Rvalue::StaticallyKnown` intentionally does not have a
// corresponding `Value` variant in order to preserve as many
// distinct `StaticallyKnown`s as possible – other passes may
// learn more information that allows them to optimize patterns
// that this pass does not recognize.
None => None,
// This pass knows the constant value of the argument and can use
// that for further optimizations. Thus collapsing this to `true`
// is likely to be profitable.
Some(_) => Some(self.insert_bool(true)),
}
}

fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_mir_transform/src/known_panics_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
| Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(..)
| Rvalue::WrapUnsafeBinder(..) => {}
| Rvalue::WrapUnsafeBinder(..)
| Rvalue::StaticallyKnown(..) => {}
}

// FIXME we need to revisit this for #67176
Expand Down Expand Up @@ -685,6 +686,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
})?;
imm.into()
}

StaticallyKnown(..) => return None,
};
trace!(?val);

Expand Down
Loading
Loading