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
|
@ -64,6 +64,11 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||||
if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
|
if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_undef(&self, _val: RValue<'gcc>) -> bool {
|
||||||
|
// FIXME: actually check for undef
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
||||||
let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
|
let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
|
||||||
if typ.is_struct().is_some() {
|
if typ.is_struct().is_some() {
|
||||||
|
|
|
@ -126,6 +126,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||||
unsafe { llvm::LLVMGetUndef(t) }
|
unsafe { llvm::LLVMGetUndef(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_undef(&self, v: &'ll Value) -> bool {
|
||||||
|
unsafe { llvm::LLVMIsUndef(v) == True }
|
||||||
|
}
|
||||||
|
|
||||||
fn const_poison(&self, t: &'ll Type) -> &'ll Value {
|
fn const_poison(&self, t: &'ll Type) -> &'ll Value {
|
||||||
unsafe { llvm::LLVMGetPoison(t) }
|
unsafe { llvm::LLVMGetPoison(t) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -918,6 +918,7 @@ unsafe extern "C" {
|
||||||
pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
|
pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
|
||||||
|
|
||||||
// Operations on all values
|
// Operations on all values
|
||||||
|
pub fn LLVMIsUndef(Val: &Value) -> Bool;
|
||||||
pub fn LLVMTypeOf(Val: &Value) -> &Type;
|
pub fn LLVMTypeOf(Val: &Value) -> &Type;
|
||||||
pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
|
pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
|
||||||
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
|
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, mir, span_bug};
|
use rustc_middle::{bug, mir, span_bug};
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use super::operand::{OperandRef, OperandValue};
|
use super::operand::{OperandRef, OperandValue};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
|
@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
return;
|
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 try_init_all_same = |bx: &mut Bx, v| {
|
||||||
let start = dest.val.llval;
|
let start = dest.val.llval;
|
||||||
let size = bx.const_usize(dest.layout.size.bytes());
|
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
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trace!(?cg_elem.val);
|
||||||
match cg_elem.val {
|
match cg_elem.val {
|
||||||
OperandValue::Immediate(v) => {
|
OperandValue::Immediate(v) => {
|
||||||
if try_init_all_same(bx, v) {
|
if try_init_all_same(bx, v) {
|
||||||
return;
|
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
|
let count = self
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
|
||||||
/// Generate an uninitialized value (matching uninitialized memory in MIR).
|
/// Generate an uninitialized value (matching uninitialized memory in MIR).
|
||||||
/// Whether memory is initialized or not is tracked byte-for-byte.
|
/// Whether memory is initialized or not is tracked byte-for-byte.
|
||||||
fn const_undef(&self, t: Self::Type) -> Self::Value;
|
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
|
/// 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
|
/// 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
|
/// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
// CHECK-LABEL: @zero_sized_elem
|
// CHECK-LABEL: @zero_sized_elem
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn zero_sized_elem() {
|
pub fn zero_sized_elem() {
|
||||||
|
@ -76,16 +78,14 @@ pub fn u16_init_one_bytes() -> [u16; N] {
|
||||||
[const { u16::from_be_bytes([1, 1]) }; N]
|
[const { u16::from_be_bytes([1, 1]) }; N]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: undef bytes can just be initialized with the same value as the
|
|
||||||
// defined bytes, if the defines bytes are all the same.
|
|
||||||
// CHECK-LABEL: @option_none_init
|
// CHECK-LABEL: @option_none_init
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn option_none_init() -> [Option<u8>; N] {
|
pub fn option_none_init() -> [Option<u8>; N] {
|
||||||
// CHECK-NOT: select
|
// CHECK-NOT: select
|
||||||
// CHECK: br label %repeat_loop_header{{.*}}
|
// CHECK-NOT: br
|
||||||
// CHECK-NOT: switch
|
// CHECK-NOT: switch
|
||||||
// CHECK: icmp
|
// CHECK-NOT: icmp
|
||||||
// CHECK-NOT: call void @llvm.memset.p0
|
// CHECK: call void @llvm.memset.p0
|
||||||
[const { None }; N]
|
[const { None }; N]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue