debuginfo: Use LocalRef to simplify reference debuginfos
If the `LocalRef` is `LocalRef::Place`, we can refer to it directly, because the local of place is an indirect pointer. Such a statement is `_1 = &(_2.1)`. If the `LocalRef` is `LocalRef::Operand`, the `OperandRef` should provide the pointer of the reference. Such a statement is `_1 = &((*_2).1)`. But there is a special case that hasn't been handled, scalar pairs like `(&[i32; 16], i32)`.
This commit is contained in:
@@ -259,8 +259,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
&self,
|
&self,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
local: mir::Local,
|
local: mir::Local,
|
||||||
base: PlaceValue<Bx::Value>,
|
base: PlaceRef<'tcx, Bx::Value>,
|
||||||
layout: TyAndLayout<'tcx>,
|
|
||||||
projection: &[mir::PlaceElem<'tcx>],
|
projection: &[mir::PlaceElem<'tcx>],
|
||||||
) {
|
) {
|
||||||
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
|
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: _ } =
|
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() {
|
for var in vars.iter() {
|
||||||
let Some(dbg_var) = var.dbg_var else {
|
let Some(dbg_var) = var.dbg_var else {
|
||||||
continue;
|
continue;
|
||||||
@@ -285,7 +284,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
bx.dbg_var_value(
|
bx.dbg_var_value(
|
||||||
dbg_var,
|
dbg_var,
|
||||||
dbg_loc,
|
dbg_loc,
|
||||||
base.llval,
|
base.val.llval,
|
||||||
direct_offset,
|
direct_offset,
|
||||||
&indirect_offsets,
|
&indirect_offsets,
|
||||||
&var.fragment,
|
&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 layout = bx.cx().layout_of(ty);
|
||||||
let to_backend_ty = bx.cx().immediate_backend_type(layout);
|
let to_backend_ty = bx.cx().immediate_backend_type(layout);
|
||||||
let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), 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,
|
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo};
|
use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::span_bug;
|
||||||
use rustc_target::callconv::PassMode;
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::{FunctionCx, LocalRef};
|
use super::{FunctionCx, LocalRef};
|
||||||
use crate::common::TypeKind;
|
|
||||||
use crate::mir::place::PlaceRef;
|
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
|
|
||||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
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 {
|
match debuginfo {
|
||||||
StmtDebugInfo::AssignRef(dest, place) => {
|
StmtDebugInfo::AssignRef(dest, place) => {
|
||||||
let local_ref = match self.locals[place.local] {
|
let local_ref = match self.locals[place.local] {
|
||||||
LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => {
|
// For an rvalue like `&(_1.1)`, when `BackendRepr` is `BackendRepr::Memory`, we allocate a block of memory to this place.
|
||||||
Some(place_ref)
|
// 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
|
// For an rvalue like `&1`, when `BackendRepr` is `BackendRepr::Scalar`,
|
||||||
.val
|
// we cannot get the address.
|
||||||
.try_pointer_parts()
|
// N.B. `non_ssa_locals` returns that this is an SSA local.
|
||||||
.map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)),
|
LocalRef::Operand(_) => None,
|
||||||
LocalRef::PendingOperand => None,
|
LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => None,
|
||||||
}
|
}
|
||||||
.filter(|place_ref| {
|
.filter(|(_, projection)| {
|
||||||
// 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) &&
|
|
||||||
// Drop unsupported projections.
|
// Drop unsupported projections.
|
||||||
place.projection.iter().all(|p| p.can_use_in_debuginfo()) &&
|
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
|
|
||||||
});
|
});
|
||||||
if let Some(local_ref) = local_ref {
|
if let Some((base, projection)) = local_ref {
|
||||||
let (base_layout, projection) = if place.is_indirect_first_projection() {
|
self.debug_new_val_to_local(bx, *dest, base, 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);
|
|
||||||
} else {
|
} 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);
|
self.debug_poison_to_local(bx, *dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,249 @@
|
|||||||
//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled
|
//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled
|
||||||
//@ revisions: CODEGEN OPTIMIZED
|
//@ revisions: CODEGEN OPTIMIZED
|
||||||
//@[CODEGEN] compile-flags: -Cno-prepopulate-passes
|
//@[CODEGEN] compile-flags: -Cno-prepopulate-passes
|
||||||
|
//@ only-64bit
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![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)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -16,23 +256,7 @@ pub struct Bar<'a> {
|
|||||||
foo: &'a Foo,
|
foo: &'a Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[unsafe(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]
|
|
||||||
pub fn dead_first(dead_first_foo: &Foo) -> &i32 {
|
pub fn dead_first(dead_first_foo: &Foo) -> &i32 {
|
||||||
// CHECK-LABEL: def {{.*}} ptr @dead_first
|
// CHECK-LABEL: def {{.*}} ptr @dead_first
|
||||||
// CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]])
|
// CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]])
|
||||||
@@ -47,32 +271,9 @@ pub fn dead_first(dead_first_foo: &Foo) -> &i32 {
|
|||||||
dead_first_v0
|
dead_first_v0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[unsafe(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]
|
|
||||||
pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo {
|
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-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]])
|
||||||
// CHECK: #dbg_declare(ptr [[ARG_fragment_v1]]
|
// CHECK: #dbg_declare(ptr [[ARG_fragment_v1]]
|
||||||
// CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]]
|
// 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
|
fragment_v2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[unsafe(no_mangle)]
|
||||||
pub fn deref(bar: Bar) -> i32 {
|
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.
|
// We are unable to represent dereference within this expression.
|
||||||
// CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression()
|
// CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression()
|
||||||
let deref_dead = &bar.foo.2;
|
let deref_dead = &bar.foo.2;
|
||||||
bar.a
|
bar.a
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[unsafe(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]
|
|
||||||
fn index(slice: &[i32; 4], idx: usize) -> i32 {
|
fn index(slice: &[i32; 4], idx: usize) -> i32 {
|
||||||
// CHECK-LABEL: define{{.*}} i32 @index
|
// CHECK-LABEL: define{{.*}} i32 @index
|
||||||
// CHECK: bb1:
|
// CHECK: call void @opaque_fn()
|
||||||
// CHECK-NEXT: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression()
|
opaque_fn();
|
||||||
// CODEGEN: bb3:
|
// CHECK: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression()
|
||||||
// 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()
|
|
||||||
let index_from_var = &slice[idx];
|
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 {
|
let [ref const_index_from_start, .., ref const_index_from_end] = slice[..] else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
slice[0]
|
slice[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "Rust" {
|
// CHECK-DAG: [[ref_local_var_scalar]] = !DILocalVariable(name: "ref_local_var_scalar"
|
||||||
safe fn opaque_inner(_: *const core::ffi::c_void);
|
// 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"
|
||||||
|
|
||||||
#[inline(never)]
|
// CHECK-DAG: [[ref_zst]] = !DILocalVariable(name: "ref_zst"
|
||||||
pub fn opaque_use<T>(p: &T) {
|
// CHECK-DAG: [[ref_zst_ref]] = !DILocalVariable(name: "ref_zst_ref"
|
||||||
opaque_inner(&raw const p as *const _);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
// CHECK-DAG: [[ref_scalar]] = !DILocalVariable(name: "ref_scalar"
|
||||||
pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 {
|
// CHECK-DAG: [[ref_scalar_ref]] = !DILocalVariable(name: "ref_scalar_ref"
|
||||||
// CHECK-LABEL: define{{.*}} i32 @non_arg_ref
|
// CHECK-DAG: [[ref_0_array_ref]] = !DILocalVariable(name: "ref_0_array_ref"
|
||||||
// CHECK: #dbg_value(ptr %non_arg_ref_scalar, [[VAR_non_arg_ref_scalar_ref:![0-9]+]], !DIExpression()
|
// CHECK-DAG: [[ref_1_array_ref]] = !DILocalVariable(name: "ref_1_array_ref"
|
||||||
// CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref:![0-9]+]], !DIExpression()
|
// CHECK-DAG: [[ref_1_aggregate_4xi8_ref]] = !DILocalVariable(name: "ref_1_aggregate_4xi8_ref"
|
||||||
// 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;
|
// CHECK-DAG: [[ref_aggregate_4xi8]] = !DILocalVariable(name: "ref_aggregate_4xi8"
|
||||||
let non_arg_ref_foo = foo;
|
// CHECK-DAG: [[ref_0_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_aggregate_4xi8"
|
||||||
opaque_use(&non_arg_ref_scalar);
|
|
||||||
opaque_use(&non_arg_ref_foo);
|
// CHECK-DAG: [[ref_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_tuple_sliceref_scalar"
|
||||||
let non_arg_ref_scalar_ref = &non_arg_ref_scalar;
|
// CHECK-DAG: [[ref_1_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_1_tuple_sliceref_scalar"
|
||||||
let non_arg_ref_foo_ref = &non_arg_ref_foo;
|
// CHECK-DAG: [[ref_1_array]] = !DILocalVariable(name: "ref_1_array"
|
||||||
let non_arg_ref_foo_ref_2 = &non_arg_ref_foo.2;
|
// CHECK-DAG: [[ref_1_typle_i32_i64_i8]] = !DILocalVariable(name: "ref_1_typle_i32_i64_i8"
|
||||||
*a
|
// 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"
|
||||||
|
|
||||||
// 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: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo"
|
||||||
// CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0"
|
// 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_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_start]] = !DILocalVariable(name: "const_index_from_start"
|
||||||
// CHECK-DAG: [[VAR_const_index_from_end]] = !DILocalVariable(name: "const_index_from_end"
|
// 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"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user