| //@ 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" |