Treat undef bytes as equal to any other byte
This commit is contained in:
parent
964c58a7d9
commit
dfa4c01b2e
6 changed files with 40 additions and 7 deletions
|
@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
|||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::place::PlaceRef;
|
||||
|
@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// If `v` is an integer constant whose value is just a single byte repeated N times,
|
||||
// emit a `memset` filling the entire `dest` with that byte.
|
||||
let try_init_all_same = |bx: &mut Bx, v| {
|
||||
let start = dest.val.llval;
|
||||
let size = bx.const_usize(dest.layout.size.bytes());
|
||||
|
@ -117,13 +119,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
false
|
||||
};
|
||||
|
||||
trace!(?cg_elem.val);
|
||||
match cg_elem.val {
|
||||
OperandValue::Immediate(v) => {
|
||||
if try_init_all_same(bx, v) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
OperandValue::Pair(a, b) => {
|
||||
let a_is_undef = bx.cx().is_undef(a);
|
||||
match (a_is_undef, bx.cx().is_undef(b)) {
|
||||
// Can happen for uninit unions
|
||||
(true, true) => {
|
||||
// FIXME: can we produce better output here?
|
||||
}
|
||||
(false, true) | (true, false) => {
|
||||
let val = if a_is_undef { b } else { a };
|
||||
if try_init_all_same(bx, val) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
(false, false) => {
|
||||
// FIXME: if both are the same value, use try_init_all_same
|
||||
}
|
||||
}
|
||||
}
|
||||
OperandValue::ZeroSized => unreachable!("checked above"),
|
||||
OperandValue::Ref(..) => {}
|
||||
}
|
||||
|
||||
let count = self
|
||||
|
|
|
@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
|
|||
/// Generate an uninitialized value (matching uninitialized memory in MIR).
|
||||
/// Whether memory is initialized or not is tracked byte-for-byte.
|
||||
fn const_undef(&self, t: Self::Type) -> Self::Value;
|
||||
fn is_undef(&self, v: Self::Value) -> bool;
|
||||
/// Generate a fake value. Poison always affects the entire value, even if just a single byte is
|
||||
/// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code
|
||||
/// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue