blob: 214e3908609e2feb60b8482e9a2d5f2d534c6fdd [file] [log] [blame] [edit]
//@ compile-flags: -Z annotate-moves=8 -Copt-level=0 -g
//
// This test verifies that function call and return instructions use the correct debug scopes
// when passing/returning large values. The actual move/copy operations may be annotated,
// but the CALL and RETURN instructions themselves should reference the source location,
// NOT have an inlinedAt scope pointing to compiler_move/compiler_copy.
#![crate_type = "lib"]
#[derive(Clone, Copy)]
pub struct LargeStruct {
pub data: [u64; 20], // 160 bytes
}
#[derive(Clone, Copy)]
pub struct MediumStruct {
pub data: [u64; 5], // 40 bytes
}
pub struct SmallStruct {
pub x: u32, // 4 bytes
}
// ============================================================================
// Test 1: Single argument call
// ============================================================================
// CHECK-LABEL: call_arg_scope::test_call_with_single_arg
pub fn test_call_with_single_arg(s: LargeStruct) {
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CALL1_ARG_LOC:]]
// CHECK: call {{.*}}@{{.*}}helper_single{{.*}}({{.*}}){{.*}}, !dbg ![[#CALL1_LOC:]]
helper_single(s);
}
#[inline(never)]
fn helper_single(_s: LargeStruct) {}
// ============================================================================
// Test 2: Multiple arguments of different types
// ============================================================================
// CHECK-LABEL: call_arg_scope::test_call_with_multiple_args
pub fn test_call_with_multiple_args(large: LargeStruct, medium: MediumStruct, small: SmallStruct) {
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CALL2_ARG1_LOC:]]
// CHECK: call void @llvm.memcpy{{.*}}, !dbg ![[#CALL2_ARG2_LOC:]]
// CHECK: call {{.*}}@{{.*}}helper_multiple{{.*}}({{.*}}){{.*}}, !dbg ![[#CALL2_LOC:]]
helper_multiple(large, medium, small);
}
#[inline(never)]
fn helper_multiple(_l: LargeStruct, _m: MediumStruct, _s: SmallStruct) {}
// ============================================================================
// Test 3: Return value
// ============================================================================
// CHECK-LABEL: call_arg_scope::test_return_large_value
pub fn test_return_large_value() -> LargeStruct {
let s = LargeStruct { data: [42; 20] };
// CHECK: ret {{.*}}, !dbg ![[#RET1_LOC:]]
s
}
// ============================================================================
// Test 4: Calling a function that returns a large value
// ============================================================================
// CHECK-LABEL: call_arg_scope::test_call_returning_large
pub fn test_call_returning_large() {
// CHECK: call {{.*}}@{{.*}}make_large_struct{{.*}}({{.*}}){{.*}}, !dbg ![[#CALL3_LOC:]]
let _result = make_large_struct();
}
#[inline(never)]
fn make_large_struct() -> LargeStruct {
LargeStruct { data: [1; 20] }
}
// ============================================================================
// Test 5: Mixed scenario - passing and returning large values
// ============================================================================
// CHECK-LABEL: call_arg_scope::test_mixed_call
pub fn test_mixed_call(input: LargeStruct) -> LargeStruct {
// CHECK: call {{.*}}@{{.*}}transform_large{{.*}}({{.*}}){{.*}}, !dbg ![[#CALL4_LOC:]]
transform_large(input)
}
#[inline(never)]
fn transform_large(mut s: LargeStruct) -> LargeStruct {
s.data[0] += 1;
s
}
// CHECK-DAG: ![[#CALL1_ARG_LOC]] = !DILocation({{.*}}scope: ![[#CALL1_ARG_SCOPE:]]
// CHECK-DAG: ![[#CALL1_ARG_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<call_arg_scope::LargeStruct,{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CALL1_LOC]] = !DILocation({{.*}}scope: ![[#CALL1_SCOPE:]]
// CHECK-DAG: ![[#CALL1_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "test_call_with_single_arg"
// CHECK-DAG: ![[#CALL2_ARG1_LOC]] = !DILocation({{.*}}scope: ![[#CALL2_ARG1_SCOPE:]]
// CHECK-DAG: ![[#CALL2_ARG1_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<call_arg_scope::LargeStruct,{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CALL2_ARG2_LOC]] = !DILocation({{.*}}scope: ![[#CALL2_ARG2_SCOPE:]]
// CHECK-DAG: ![[#CALL2_ARG2_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "compiler_copy<call_arg_scope::MediumStruct,{{ *[0-9]+}}>"
// CHECK-DAG: ![[#CALL2_LOC]] = !DILocation({{.*}}scope: ![[#CALL2_SCOPE:]]
// CHECK-DAG: ![[#CALL2_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "test_call_with_multiple_args"
// CHECK-DAG: ![[#CALL3_LOC]] = !DILocation({{.*}}scope: ![[#CALL3_SCOPE:]]
// CHECK-DAG: ![[#CALL3_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "test_call_returning_large"
// CHECK-DAG: ![[#CALL4_LOC]] = !DILocation({{.*}}scope: ![[#CALL4_SCOPE:]]
// CHECK-DAG: ![[#CALL4_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "test_mixed_call"
// CHECK-DAG: ![[#RET1_LOC]] = !DILocation({{.*}}scope: ![[#RET1_SCOPE:]]
// CHECK-DAG: ![[#RET1_SCOPE]] = {{(distinct )?}}!DISubprogram(name: "test_return_large_value"