From 30331828cb9e694b59c9325dce7c1f25dac3e80e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 16 Mar 2023 14:56:02 +0100 Subject: [PATCH] Use poison instead of undef In cases where it is legal, we should prefer poison values over undef values. This replaces undef with poison for aggregate construction and for uninhabited types. There are more places where we can likely use poison, but I wanted to stay conservative to start with. In particular the aggregate case is important for newer LLVM versions, which are not able to handle an undef base value during early optimization due to poison-propagation concerns. --- compiler/rustc_codegen_gcc/src/common.rs | 5 +++++ compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 4 ++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/place.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/consts.rs | 1 + tests/codegen/adjustments.rs | 2 +- 9 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 76fc7bd222e..ac04b61a306 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -73,6 +73,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } + fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { + // No distinction between undef and poison. + self.const_undef(typ) + } + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { self.gcc_int(typ, int) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0f33b985489..580451ba265 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -990,7 +990,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false); - let mut exn = self.const_undef(ty); + let mut exn = self.const_poison(ty); exn = self.insert_value(exn, exn0, 0); exn = self.insert_value(exn, exn1, 1); unsafe { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b0a9a30ab46..efa0c13226e 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -130,6 +130,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetUndef(t) } } + fn const_poison(&self, t: &'ll Type) -> &'ll Value { + unsafe { llvm::LLVMGetPoison(t) } + } + fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { unsafe { llvm::LLVMConstInt(t, i as u64, True) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 509cb0fef56..9e5265188b5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1069,6 +1069,7 @@ extern "C" { // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; pub fn LLVMGetUndef(Ty: &Type) -> &Value; + pub fn LLVMGetPoison(Ty: &Type) -> &Value; // Operations on metadata pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 34a5b638d7e..25721f75583 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ) -> OperandRef<'tcx, V> { assert!(layout.is_zst()); OperandRef { - val: OperandValue::Immediate(bx.const_undef(bx.immediate_backend_type(layout))), + val: OperandValue::Immediate(bx.const_poison(bx.immediate_backend_type(layout))), layout, } } @@ -145,7 +145,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llty = bx.cx().backend_type(self.layout); debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); // Reconstruct the immediate aggregate. - let mut llpair = bx.cx().const_undef(llty); + let mut llpair = bx.cx().const_poison(llty); let imm_a = bx.from_immediate(a); let imm_b = bx.from_immediate(b); llpair = bx.insert_value(llpair, imm_a, 0); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index cf02f59f67b..f6523a448e3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let cast_to_size = cast_to_layout.layout.size(); let cast_to = bx.cx().immediate_backend_type(cast_to_layout); if self.layout.abi.is_uninhabited() { - return bx.cx().const_undef(cast_to); + return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { Variants::Single { index } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 13c4fa132d8..74b9ff7eace 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -295,7 +295,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(bx.cx().is_backend_immediate(cast)); let ll_t_out = bx.cx().immediate_backend_type(cast); if operand.layout.abi.is_uninhabited() { - let val = OperandValue::Immediate(bx.cx().const_undef(ll_t_out)); + let val = OperandValue::Immediate(bx.cx().const_poison(ll_t_out)); return OperandRef { val, layout: cast }; } let r_t_in = diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index fdc7a30e841..61906302779 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -8,6 +8,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; fn const_undef(&self, t: Self::Type) -> Self::Value; + fn const_poison(&self, t: Self::Type) -> Self::Value; fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value; fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value; diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs index 6d224751752..b53a68a5588 100644 --- a/tests/codegen/adjustments.rs +++ b/tests/codegen/adjustments.rs @@ -13,7 +13,7 @@ pub fn helper(_: usize) { pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { // We used to generate an extra alloca and memcpy for the block's trailing expression value, so // check that we copy directly to the return value slot -// CHECK: %0 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } undef, {{\[0 x i8\]\*|ptr}} %x.0, 0 +// CHECK: %0 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } poison, {{\[0 x i8\]\*|ptr}} %x.0, 0 // CHECK: %1 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %0, [[USIZE]] %x.1, 1 // CHECK: ret { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %1 { x }