2025-07-19 18:49:47 +08:00
|
|
|
//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled
|
2025-06-18 22:04:48 +08:00
|
|
|
//@ revisions: CODEGEN OPTIMIZED
|
|
|
|
|
//@[CODEGEN] compile-flags: -Cno-prepopulate-passes
|
|
|
|
|
// ignore-tidy-linelength
|
|
|
|
|
|
|
|
|
|
#![crate_type = "lib"]
|
|
|
|
|
|
|
|
|
|
#[repr(C)]
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
pub struct Foo(i32, i64, i32);
|
|
|
|
|
|
2025-07-19 18:49:47 +08:00
|
|
|
#[repr(C)]
|
|
|
|
|
pub struct Bar<'a> {
|
|
|
|
|
a: i32,
|
|
|
|
|
b: i64,
|
|
|
|
|
foo: &'a Foo,
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 22:04:48 +08:00
|
|
|
#[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 {
|
|
|
|
|
// CHECK-LABEL: def {{.*}} ptr @dead_first
|
|
|
|
|
// CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]])
|
|
|
|
|
// CODEGEN: #dbg_declare(ptr %dead_first_foo.dbg.spill, [[ARG_dead_first_foo:![0-9]+]], !DIExpression()
|
|
|
|
|
// OPTIMIZED: #dbg_value(ptr %dead_first_foo, [[ARG_dead_first_foo:![0-9]+]], !DIExpression()
|
|
|
|
|
// CHECK: #dbg_value(ptr %dead_first_foo, [[VAR_dead_first_v0:![0-9]+]], !DIExpression()
|
|
|
|
|
// CHECK: %dead_first_v0 = getelementptr{{.*}} i8, ptr %dead_first_foo, i64 16
|
|
|
|
|
// CODEGEN: #dbg_declare(ptr %dead_first_v0.dbg.spill, [[VAR_dead_first_v0]], !DIExpression()
|
|
|
|
|
// OPTIMIZED: #dbg_value(ptr %dead_first_v0, [[VAR_dead_first_v0]], !DIExpression()
|
|
|
|
|
let mut dead_first_v0 = &dead_first_foo.0;
|
|
|
|
|
dead_first_v0 = &dead_first_foo.2;
|
|
|
|
|
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]
|
|
|
|
|
pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo {
|
|
|
|
|
// CHECK-LABEL: define 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]]
|
|
|
|
|
// CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v2]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
|
|
|
|
|
// CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v1]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
|
|
|
|
|
let fragment_f = || {
|
|
|
|
|
fragment_v2 = fragment_v1;
|
|
|
|
|
};
|
|
|
|
|
fragment_v2 = fragment_v1;
|
|
|
|
|
fragment_v2
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 18:49:47 +08:00
|
|
|
#[no_mangle]
|
|
|
|
|
pub fn deref(bar: Bar) -> i32 {
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 22:04:48 +08:00
|
|
|
#[no_mangle]
|
|
|
|
|
pub fn tuple(foo: (i32, &Foo)) -> i32 {
|
|
|
|
|
// CHECK-LABEL: define{{.*}} i32 @tuple
|
2025-07-19 18:49:47 +08:00
|
|
|
// Although there is no dereference here, there is a dereference in the MIR.
|
|
|
|
|
// CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression()
|
2025-06-18 22:04:48 +08:00
|
|
|
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 {
|
|
|
|
|
// 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()
|
|
|
|
|
let index_from_var = &slice[idx];
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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"
|
2025-07-19 18:49:47 +08:00
|
|
|
// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead"
|
2025-06-18 22:04:48 +08:00
|
|
|
// 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_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"
|