diff options
-rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 9 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/statement.rs | 61 | ||||
-rw-r--r-- | tests/codegen-llvm/debuginfo-dse.rs | 405 |
3 files changed, 318 insertions, 157 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 38bb6f24b1c..0c9acf087f9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -259,8 +259,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, bx: &mut Bx, local: mir::Local, - base: PlaceValue<Bx::Value>, - layout: TyAndLayout<'tcx>, + base: PlaceRef<'tcx, Bx::Value>, projection: &[mir::PlaceElem<'tcx>], ) { let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; @@ -274,7 +273,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, projection, layout); + calculate_debuginfo_offset(bx, projection, base.layout); for var in vars.iter() { let Some(dbg_var) = var.dbg_var else { continue; @@ -285,7 +284,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.dbg_var_value( dbg_var, dbg_loc, - base.llval, + base.val.llval, direct_offset, &indirect_offsets, &var.fragment, @@ -298,7 +297,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.cx().layout_of(ty); let to_backend_ty = bx.cx().immediate_backend_type(layout); let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); - self.debug_new_val_to_local(bx, local, place_ref.val, layout, &[]); + self.debug_new_val_to_local(bx, local, place_ref, &[]); } /// Apply debuginfo and/or name, after creating the `alloca` for a local, diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 80f4f0fcda1..88590b6271b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,11 +1,8 @@ -use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo}; -use rustc_middle::{bug, span_bug}; -use rustc_target::callconv::PassMode; +use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo}; +use rustc_middle::span_bug; use tracing::instrument; use super::{FunctionCx, LocalRef}; -use crate::common::TypeKind; -use crate::mir::place::PlaceRef; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -110,48 +107,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match debuginfo { StmtDebugInfo::AssignRef(dest, place) => { let local_ref = match self.locals[place.local] { - LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { - Some(place_ref) + // For an rvalue like `&(_1.1)`, when `BackendRepr` is `BackendRepr::Memory`, we allocate a block of memory to this place. + // The place is an indirect pointer, we can refer to it directly. + LocalRef::Place(place_ref) => Some((place_ref, place.projection.as_slice())), + // For an rvalue like `&((*_1).1)`, we are calculating the address of `_1.1`. + // The deref projection is no-op here. + LocalRef::Operand(operand_ref) if place.is_indirect_first_projection() => { + Some((operand_ref.deref(bx.cx()), &place.projection[1..])) } - LocalRef::Operand(operand_ref) => operand_ref - .val - .try_pointer_parts() - .map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)), - LocalRef::PendingOperand => None, + // For an rvalue like `&1`, when `BackendRepr` is `BackendRepr::Scalar`, + // we cannot get the address. + // N.B. `non_ssa_locals` returns that this is an SSA local. + LocalRef::Operand(_) => None, + LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => None, } - .filter(|place_ref| { - // For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is - // llval. - let local_ref_pass_mode = place.as_local().and_then(|local| { - if local == RETURN_PLACE { - None - } else { - self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode) - } - }); - matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) && + .filter(|(_, projection)| { // Drop unsupported projections. - place.projection.iter().all(|p| p.can_use_in_debuginfo()) && - // Only pointers can be calculated addresses. - bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer + projection.iter().all(|p| p.can_use_in_debuginfo()) }); - if let Some(local_ref) = local_ref { - let (base_layout, projection) = if place.is_indirect_first_projection() { - // For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so - // we should drop the deref projection. - let projected_ty = local_ref - .layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref)); - let layout = bx.cx().layout_of(projected_ty); - (layout, &place.projection[1..]) - } else { - (local_ref.layout, place.projection.as_slice()) - }; - self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection); + if let Some((base, projection)) = local_ref { + self.debug_new_val_to_local(bx, *dest, base, projection); } else { - // If the address cannot be computed, use poison to indicate that the value has been optimized out. + // If the address cannot be calculated, use poison to indicate that the value has been optimized out. self.debug_poison_to_local(bx, *dest); } } diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs index 78e145a3cdf..fd0c9f1c676 100644 --- a/tests/codegen-llvm/debuginfo-dse.rs +++ b/tests/codegen-llvm/debuginfo-dse.rs @@ -1,9 +1,249 @@ //@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled //@ revisions: CODEGEN OPTIMIZED //@[CODEGEN] compile-flags: -Cno-prepopulate-passes +//@ only-64bit // ignore-tidy-linelength #![crate_type = "lib"] +#![feature(repr_simd, rustc_attrs)] + +// The pass mode is direct and the backend represent is scalar. +type Scalar = i32; // scalar(i32) +type Scalar_Ref = &'static i32; // scalar(ptr) + +// The pass modes are pair and the backend represents are scalar pair. +type Tuple_Scalar_Scalar = (i32, i32); +struct Tuple_Ref_Scalar(&'static i32, i32); +struct Tuple_ArrayRef_Scalar(&'static [i32; 16], i32); // pair(ptr, i32) +impl Default for Tuple_ArrayRef_Scalar { + fn default() -> Tuple_ArrayRef_Scalar { + Tuple_ArrayRef_Scalar(&[0; 16], 0) + } +} +struct Tuple_Scalar_ArrayRef(i32, &'static [i32; 16]); // pair(i32, ptr) +impl Default for Tuple_Scalar_ArrayRef { + fn default() -> Tuple_Scalar_ArrayRef { + Tuple_Scalar_ArrayRef(0, &[0; 16]) + } +} +// The pass mode is indirect and the backend represent is memory. +type Tuple_SliceRef_Scalar = (&'static [i32], i32); + +// The pass mode is pair and the backend represent is scalar pair. +type SliceRef = &'static [i32]; // pair(ptr, i32) +// The pass mode is indirect and the backend represent is memory. +type Array = [i32; 16]; +// The pass mode is direct and the backend represent is scalar. +type ArrayRef = &'static [i32; 16]; + +// The pass mode is indirect and the backend represent is memory. +type Typle_i32_i64_i8 = (i32, i64, i8); +// The pass mode is indirect and the backend represent is memory. +#[repr(C)] +struct Aggregate_i32_Array_i8(i32, &'static [i32; 16], i8); + +type ZST = (); + +impl Default for Aggregate_i32_Array_i8 { + fn default() -> Aggregate_i32_Array_i8 { + Aggregate_i32_Array_i8(0, &[0; 16], 0) + } +} +// The pass mode is cast and the backend represent is scalar. +#[derive(Default)] +struct Aggregate_4xi8(i8, i8, i8, i8); // scalar(i32) + +// The pass mode is indirect and the backend represent is simd vector. +#[repr(simd)] +struct Simd_i32x4([i32; 4]); + +unsafe extern "Rust" { + #[rustc_nounwind] + safe fn opaque_fn(); + #[rustc_nounwind] + safe fn opaque_ptr(_: *const core::ffi::c_void); +} + +#[inline(never)] +#[rustc_nounwind] +fn opaque_use<T>(p: &T) { + opaque_ptr(&raw const p as *const _); +} + +#[inline(never)] +#[rustc_nounwind] +fn opaque_read<T: Default>() -> T { + core::hint::black_box(T::default()) +} + +#[unsafe(no_mangle)] +fn local_var() { + // CHECK-LABEL: define{{( dso_local)?}} void @local_var + let local_var_scalar: Scalar = opaque_read(); + opaque_use(&local_var_scalar); + let dead_local_var_scalar: Scalar = opaque_read(); + let local_var_aggregate_4xi8: Aggregate_4xi8 = opaque_read(); + opaque_use(&local_var_aggregate_4xi8); + let local_var_aggregate_i32_array_i8: Aggregate_i32_Array_i8 = opaque_read(); + opaque_use(&local_var_aggregate_i32_array_i8); + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr %local_var_scalar, [[ref_local_var_scalar:![0-9]+]], !DIExpression() + let ref_local_var_scalar = &local_var_scalar; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_dead_local_var_scalar:![0-9]+]], !DIExpression() + let ref_dead_local_var_scalar = &dead_local_var_scalar; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_local_var_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_0_local_var_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_0_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.0; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_2_local_var_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 2, DW_OP_stack_value) + let ref_2_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.2; + // This introduces an extra load instruction. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression() + let ref_1_1_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.1[1]; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_i32_array_i8, [[ref_2_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_2_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.2; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +#[unsafe(no_mangle)] +fn zst(zst: ZST, zst_ref: &ZST) { + // CHECK-LABEL: define{{( dso_local)?}} void @zst + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst:![0-9]+]], !DIExpression() + let ref_zst = &zst; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst_ref:![0-9]+]], !DIExpression() + let ref_zst_ref = &zst_ref; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// It only makes sense if the argument is a reference and it refer to projections. +#[unsafe(no_mangle)] +fn direct( + scalar: Scalar, + scalar_ref: Scalar_Ref, + array_ref: ArrayRef, + aggregate_4xi8_ref: &Aggregate_4xi8, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @direct + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar:![0-9]+]], !DIExpression() + let ref_scalar = &scalar; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar_ref:![0-9]+]], !DIExpression() + let ref_scalar_ref = &scalar_ref; + // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_0_array_ref:![0-9]+]], !DIExpression() + let ref_0_array_ref = &array_ref[0]; + // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_1_array_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_array_ref = &array_ref[1]; + // CHECK-NEXT: #dbg_value(ptr %aggregate_4xi8_ref, [[ref_1_aggregate_4xi8_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + let ref_1_aggregate_4xi8_ref = &aggregate_4xi8_ref.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// Arguments are passed through registers, the final values are poison. +#[unsafe(no_mangle)] +fn cast(aggregate_4xi8: Aggregate_4xi8) { + // CHECK-LABEL: define{{( dso_local)?}} void @cast(i32 %0) + // CHECK: call void @opaque_fn() + opaque_fn(); + // The temporary allocated variable is eliminated. + // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression() + // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_aggregate_4xi8 = &aggregate_4xi8; + // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + let ref_0_aggregate_4xi8 = &aggregate_4xi8.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// Arguments are passed indirectly via a pointer. +// The reference of argument is the pointer itself. +#[unsafe(no_mangle)] +fn indirect( + tuple_sliceref_scalar: Tuple_SliceRef_Scalar, + array: Array, + typle_i32_i64_i8: Typle_i32_i64_i8, + simd_i32x4: Simd_i32x4, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @indirect + // CHECK-SAME: (ptr{{.*}} %tuple_sliceref_scalar, ptr{{.*}} %array, ptr{{.*}} %typle_i32_i64_i8, ptr{{.*}} %simd_i32x4) + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_tuple_sliceref_scalar:![0-9]+]], !DIExpression() + let ref_tuple_sliceref_scalar = &tuple_sliceref_scalar; + // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_1_tuple_sliceref_scalar:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_1_tuple_sliceref_scalar = &tuple_sliceref_scalar.1; + // CHECK-NEXT: #dbg_value(ptr %array, [[ref_1_array:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_array = &array[1]; + // CHECK-NEXT: #dbg_value(ptr %typle_i32_i64_i8, [[ref_1_typle_i32_i64_i8:![0-9]+]], !DIExpression() + let ref_1_typle_i32_i64_i8 = &typle_i32_i64_i8.1; + // CHECK-NEXT: #dbg_value(ptr %simd_i32x4, [[ref_simd_i32x4:![0-9]+]], !DIExpression() + let ref_simd_i32x4 = &simd_i32x4; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// They are different MIR statements, but they have the same LLVM IR statement due to the ABI of arguments. +// Both `direct_ref` and `indirect_byval` are passed as a pointer here. +#[unsafe(no_mangle)] +fn direct_ref_and_indirect( + direct_ref: &Aggregate_i32_Array_i8, + indirect_byval: Aggregate_i32_Array_i8, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @direct_ref_and_indirect + // CHECK-SAME: (ptr{{.*}} %direct_ref, ptr{{.*}} %indirect_byval) + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_direct_ref:![0-9]+]], !DIExpression() + let ref_direct_ref: &&Aggregate_i32_Array_i8 = &direct_ref; + // CHECK-NEXT: #dbg_value(ptr %direct_ref, [[ref_1_direct_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + let ref_1_direct_ref = &direct_ref.1; + // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_indirect_byval:![0-9]+]], !DIExpression() + let ref_indirect_byval: &Aggregate_i32_Array_i8 = &indirect_byval; + // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_1_indirect_byval:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + let ref_1_indirect_byval = &indirect_byval.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +#[unsafe(no_mangle)] +fn pair( + tuple_scalar_scalar: Tuple_Scalar_Scalar, + tuple_ref_scalar: Tuple_Ref_Scalar, + tuple_arrayref_scalar: Tuple_ArrayRef_Scalar, + tuple_scalar_arrayref: Tuple_Scalar_ArrayRef, + sliceref: SliceRef, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @pair + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_scalar_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_scalar_scalar = &tuple_scalar_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_ref_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_ref_scalar = &tuple_ref_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_ref_scalar:![0-9]+]], !DIExpression() + let ref_1_tuple_ref_scalar = &tuple_ref_scalar.1; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_arrayref_scalar = &tuple_arrayref_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.1; + // FIXME: This can be a valid value. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_0_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.0[1]; + // FIXME: This can be a valid value. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_tuple_scalar_arrayref:![0-9]+]], !DIExpression() + let ref_1_1_tuple_scalar_arrayref = &tuple_scalar_arrayref.1[1]; + // CHECK: #dbg_value(ptr %sliceref.0, [[ref_1_sliceref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_sliceref = &sliceref[1]; + // CHECK: call void @opaque_fn() + opaque_fn(); +} #[repr(C)] #[derive(Clone, Copy)] @@ -16,23 +256,7 @@ pub struct Bar<'a> { foo: &'a Foo, } -#[no_mangle] -fn r#ref(ref_foo: &Foo) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @ref - // CHECK-SAME: (ptr {{.*}} [[ARG_ref_foo:%.*]]) - // OPTIMIZED: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr poison, [[VAR_invalid_ref_of_ref_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v0:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let invalid_ref_of_ref_foo = &ref_foo; - let ref_v0 = &ref_foo.0; - let ref_v1 = &ref_foo.1; - let ref_v2 = &ref_foo.2; - ref_foo.0 -} - -#[no_mangle] +#[unsafe(no_mangle)] pub fn dead_first(dead_first_foo: &Foo) -> &i32 { // CHECK-LABEL: def {{.*}} ptr @dead_first // CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]]) @@ -47,32 +271,9 @@ pub fn dead_first(dead_first_foo: &Foo) -> &i32 { dead_first_v0 } -#[no_mangle] -fn ptr(ptr_foo: Foo) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @ptr - // CHECK-SAME: (ptr {{.*}} [[ARG_ptr_foo:%.*]]) - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[ref_ptr_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v0:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let ref_ptr_foo = &ptr_foo; - let ptr_v0 = &ptr_foo.0; - let ptr_v1 = &ptr_foo.1; - let ptr_v2 = &ptr_foo.2; - ptr_foo.2 -} - -#[no_mangle] -fn no_ptr(val: i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @no_ptr - // CODEGEN: #dbg_value(ptr poison, [[VAR_val_ref:![0-9]+]], !DIExpression() - let val_ref = &val; - val -} - -#[no_mangle] +#[unsafe(no_mangle)] pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { - // CHECK-LABEL: define void @fragment + // CHECK-LABEL: define{{( dso_local)?}} void @fragment // CHECK-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]]) // CHECK: #dbg_declare(ptr [[ARG_fragment_v1]] // CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]] @@ -85,93 +286,77 @@ pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { fragment_v2 } -#[no_mangle] +#[unsafe(no_mangle)] pub fn deref(bar: Bar) -> i32 { - // CHECK-LABEL: define {{.*}} i32 @deref + // CHECK-LABEL: define{{.*}} i32 @deref // We are unable to represent dereference within this expression. // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression() let deref_dead = &bar.foo.2; bar.a } -#[no_mangle] -pub fn tuple(foo: (i32, &Foo)) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @tuple - // Although there is no dereference here, there is a dereference in the MIR. - // CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression() - let tuple_dead = &foo.1.2; - foo.1.0 -} - -pub struct ZST; - -#[no_mangle] -pub fn zst(zst: ZST, v: &i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @zst - // CHECK: #dbg_value(ptr poison, [[VAR_zst_ref:![0-9]+]], !DIExpression() - let zst_ref = &zst; - *v -} - -#[no_mangle] +#[unsafe(no_mangle)] fn index(slice: &[i32; 4], idx: usize) -> i32 { // CHECK-LABEL: define{{.*}} i32 @index - // CHECK: bb1: - // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression() - // CODEGEN: bb3: - // CHECK-NEXT: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression() + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression() let index_from_var = &slice[idx]; + // CHECK: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression() + // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression() let [ref const_index_from_start, .., ref const_index_from_end] = slice[..] else { return 0; }; slice[0] } -unsafe extern "Rust" { - safe fn opaque_inner(_: *const core::ffi::c_void); -} +// CHECK-DAG: [[ref_local_var_scalar]] = !DILocalVariable(name: "ref_local_var_scalar" +// CHECK-DAG: [[ref_dead_local_var_scalar]] = !DILocalVariable(name: "ref_dead_local_var_scalar" +// CHECK-DAG: [[ref_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_0_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_2_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_1_1_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_1_1_local_var_aggregate_i32_array_i8" +// CHECK-DAG: [[ref_2_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_i32_array_i8" + +// CHECK-DAG: [[ref_zst]] = !DILocalVariable(name: "ref_zst" +// CHECK-DAG: [[ref_zst_ref]] = !DILocalVariable(name: "ref_zst_ref" + +// CHECK-DAG: [[ref_scalar]] = !DILocalVariable(name: "ref_scalar" +// CHECK-DAG: [[ref_scalar_ref]] = !DILocalVariable(name: "ref_scalar_ref" +// CHECK-DAG: [[ref_0_array_ref]] = !DILocalVariable(name: "ref_0_array_ref" +// CHECK-DAG: [[ref_1_array_ref]] = !DILocalVariable(name: "ref_1_array_ref" +// CHECK-DAG: [[ref_1_aggregate_4xi8_ref]] = !DILocalVariable(name: "ref_1_aggregate_4xi8_ref" + +// CHECK-DAG: [[ref_aggregate_4xi8]] = !DILocalVariable(name: "ref_aggregate_4xi8" +// CHECK-DAG: [[ref_0_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_aggregate_4xi8" + +// CHECK-DAG: [[ref_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_tuple_sliceref_scalar" +// CHECK-DAG: [[ref_1_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_1_tuple_sliceref_scalar" +// CHECK-DAG: [[ref_1_array]] = !DILocalVariable(name: "ref_1_array" +// CHECK-DAG: [[ref_1_typle_i32_i64_i8]] = !DILocalVariable(name: "ref_1_typle_i32_i64_i8" +// CHECK-DAG: [[ref_simd_i32x4]] = !DILocalVariable(name: "ref_simd_i32x4" + +// CHECK-DAG: [[ref_direct_ref]] = !DILocalVariable(name: "ref_direct_ref" +// CHECK-DAG: [[ref_1_direct_ref]] = !DILocalVariable(name: "ref_1_direct_ref" +// CHECK-DAG: [[ref_indirect_byval]] = !DILocalVariable(name: "ref_indirect_byval" +// CHECK-DAG: [[ref_1_indirect_byval]] = !DILocalVariable(name: "ref_1_indirect_byval" + +// CHECK-DAG: [[ref_0_tuple_scalar_scalar]] = !DILocalVariable(name: "ref_0_tuple_scalar_scalar" +// CHECK-DAG: [[ref_0_tuple_ref_scalar]] = !DILocalVariable(name: "ref_0_tuple_ref_scalar" +// CHECK-DAG: [[ref_1_tuple_ref_scalar]] = !DILocalVariable(name: "ref_1_tuple_ref_scalar" +// CHECK-DAG: [[ref_0_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_1_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_0_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_1_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_1_1_tuple_scalar_arrayref]] = !DILocalVariable(name: "ref_1_1_tuple_scalar_arrayref" +// CHECK-DAG: [[ref_1_sliceref]] = !DILocalVariable(name: "ref_1_sliceref" -#[inline(never)] -pub fn opaque_use<T>(p: &T) { - opaque_inner(&raw const p as *const _); -} - -#[no_mangle] -pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @non_arg_ref - // CHECK: #dbg_value(ptr %non_arg_ref_scalar, [[VAR_non_arg_ref_scalar_ref:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref_2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let non_arg_ref_scalar = scalar; - let non_arg_ref_foo = foo; - opaque_use(&non_arg_ref_scalar); - opaque_use(&non_arg_ref_foo); - let non_arg_ref_scalar_ref = &non_arg_ref_scalar; - let non_arg_ref_foo_ref = &non_arg_ref_foo; - let non_arg_ref_foo_ref_2 = &non_arg_ref_foo.2; - *a -} - -// CHECK-DAG: [[VAR_invalid_ref_of_ref_foo]] = !DILocalVariable(name: "invalid_ref_of_ref_foo" -// OPTIMIZED-DAG: [[VAR_ref_foo]] = !DILocalVariable(name: "ref_foo" -// CHECK-DAG: [[VAR_ref_v0]] = !DILocalVariable(name: "ref_v0" -// CHECK-DAG: [[VAR_ref_v1]] = !DILocalVariable(name: "ref_v1" -// CHECK-DAG: [[VAR_ref_v2]] = !DILocalVariable(name: "ref_v2" -// CHECK-DAG: [[ref_ptr_foo]] = !DILocalVariable(name: "ref_ptr_foo" -// CHECK-DAG: [[VAR_ptr_v0]] = !DILocalVariable(name: "ptr_v0" -// CHECK-DAG: [[VAR_ptr_v1]] = !DILocalVariable(name: "ptr_v1" -// CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2" -// CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" -// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" -// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" -// CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" // CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo" // CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0" + +// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" + +// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" + // CHECK-DAG: [[VAR_index_from_var]] = !DILocalVariable(name: "index_from_var" // CHECK-DAG: [[VAR_const_index_from_start]] = !DILocalVariable(name: "const_index_from_start" // CHECK-DAG: [[VAR_const_index_from_end]] = !DILocalVariable(name: "const_index_from_end" -// CHECK-DAG: [[VAR_zst_ref]] = !DILocalVariable(name: "zst_ref" -// CHECK-DAG: [[VAR_non_arg_ref_scalar_ref]] = !DILocalVariable(name: "non_arg_ref_scalar_ref" -// CHECK-DAG: [[VAR_non_arg_ref_foo_ref]] = !DILocalVariable(name: "non_arg_ref_foo_ref" -// CHECK-DAG: [[VAR_non_arg_ref_foo_ref_2]] = !DILocalVariable(name: "non_arg_ref_foo_ref_2" |