1; RUN: opt -passes=inline %s -S -o - \ 2; RUN: | FileCheck %s 3; RUN: opt --try-experimental-debuginfo-iterators -passes=inline %s -S -o - \ 4; RUN: | FileCheck %s 5 6;; $ cat test.cpp 7;; __attribute__((always_inline)) 8;; static void a(int* p2, int v2) { *p2 = v2; } 9;; 10;; __attribute__((always_inline)) 11;; void b(int* p1, int v1) { a(p1, v1); } 12;; 13;; int f1() { 14;; int f1_local; 15;; a(&f1_local, 1); 16;; return f1_local; 17;; } 18;; 19;; int f2() { 20;; int f2_local[2]; 21;; a(f2_local, 2); 22;; return f2_local[0]; 23;; } 24;; 25;; int f3() { 26;; int f3_local[2]; 27;; a(f3_local + 1, 3); 28;; return f3_local[1]; 29;; } 30;; 31;; int f4(int f4_param) { 32;; a(&f4_param, 4); 33;; return f4_param; 34;; } 35;; 36;; int f5(int f5_param) { 37;; int &f5_alias = f5_param; 38;; a(&f5_alias, 5); 39;; return f5_param; 40;; } 41;; 42;; int f6() { 43;; int f6_local; 44;; b(&f6_local, 6); 45;; return f6_local; 46;; } 47;; 48;; IR generated with: 49;; $ clang++ -Xclang -disable-llvm-passes test.cpp -g -O2 -o - -S -emit-llvm \ 50;; | opt -passes=declare-to-assign,sroa -o - -S 51;; 52;; Check that inlined stores are tracked as assignments. FileCheck directives 53;; inline. 54 55source_filename = "test.cpp" 56define dso_local void @_Z1bPii(ptr %p1, i32 %v1) #0 !dbg !7 { 57entry: 58 call void @llvm.dbg.assign(metadata i1 undef, metadata !13, metadata !DIExpression(), metadata !15, metadata ptr undef, metadata !DIExpression()), !dbg !16 59 call void @llvm.dbg.assign(metadata i1 undef, metadata !14, metadata !DIExpression(), metadata !17, metadata ptr undef, metadata !DIExpression()), !dbg !16 60 call void @llvm.dbg.assign(metadata ptr %p1, metadata !13, metadata !DIExpression(), metadata !18, metadata ptr undef, metadata !DIExpression()), !dbg !16 61 call void @llvm.dbg.assign(metadata i32 %v1, metadata !14, metadata !DIExpression(), metadata !19, metadata ptr undef, metadata !DIExpression()), !dbg !16 62 call void @_ZL1aPii(ptr %p1, i32 %v1), !dbg !20 63 ret void, !dbg !21 64} 65 66define internal void @_ZL1aPii(ptr %p2, i32 %v2) #2 !dbg !22 { 67entry: 68 call void @llvm.dbg.assign(metadata i1 undef, metadata !24, metadata !DIExpression(), metadata !26, metadata ptr undef, metadata !DIExpression()), !dbg !27 69 call void @llvm.dbg.assign(metadata i1 undef, metadata !25, metadata !DIExpression(), metadata !28, metadata ptr undef, metadata !DIExpression()), !dbg !27 70 call void @llvm.dbg.assign(metadata ptr %p2, metadata !24, metadata !DIExpression(), metadata !29, metadata ptr undef, metadata !DIExpression()), !dbg !27 71 call void @llvm.dbg.assign(metadata i32 %v2, metadata !25, metadata !DIExpression(), metadata !30, metadata ptr undef, metadata !DIExpression()), !dbg !27 72 store i32 %v2, ptr %p2, align 4, !dbg !31 73 ret void, !dbg !36 74} 75 76;; Store directly to local with one level of inlining. Also record f1_dbg to 77;; check that the dbg.assign gets the correct scope after inlining. This check 78;; isn't repeated for the other functions. 79;; int f1() { 80;; int f1_local; 81;; a(&f1_local, 1); 82;; return f1_local; 83;; } 84;; 85; CHECK-LABEL: define dso_local i32 @_Z2f1v() 86; CHECK: store i32 1, ptr %f1_local, align 4,{{.*}} !DIAssignID ![[ID_1:[0-9]+]] 87; CHECK-NEXT: #dbg_assign(i32 1, ![[f1_local:[0-9]+]], !DIExpression(), ![[ID_1]], ptr %f1_local, !DIExpression(), ![[f1_dbg:[0-9]+]] 88define dso_local i32 @_Z2f1v() #3 !dbg !37 { 89entry: 90 %f1_local = alloca i32, align 4, !DIAssignID !42 91 call void @llvm.dbg.assign(metadata i1 undef, metadata !41, metadata !DIExpression(), metadata !42, metadata ptr %f1_local, metadata !DIExpression()), !dbg !43 92 %0 = bitcast ptr %f1_local to ptr, !dbg !44 93 call void @llvm.lifetime.start.p0(i64 4, ptr %0) #5, !dbg !44 94 call void @_ZL1aPii(ptr %f1_local, i32 1), !dbg !45 95 %1 = load i32, ptr %f1_local, align 4, !dbg !46 96 %2 = bitcast ptr %f1_local to ptr, !dbg !47 97 call void @llvm.lifetime.end.p0(i64 4, ptr %2) #5, !dbg !47 98 ret i32 %1, !dbg !48 99} 100 101;; Store directly to fragment of local at its base address. 102;; int f2() { 103;; int f2_local[2]; 104;; a(f2_local, 2); 105;; return f2_local[0]; 106;; } 107;; 108; CHECK-LABEL: define dso_local i32 @_Z2f2v() 109; CHECK: store i32 2, ptr %arraydecay, align 4,{{.*}} !DIAssignID ![[ID_2:[0-9]+]] 110; CHECK-NEXT: #dbg_assign(i32 2, ![[f2_local:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 32), ![[ID_2]], ptr %arraydecay, !DIExpression(), 111define dso_local i32 @_Z2f2v() #3 !dbg !49 { 112entry: 113 %f2_local = alloca [2 x i32], align 4, !DIAssignID !55 114 call void @llvm.dbg.assign(metadata i1 undef, metadata !51, metadata !DIExpression(), metadata !55, metadata ptr %f2_local, metadata !DIExpression()), !dbg !56 115 %0 = bitcast ptr %f2_local to ptr, !dbg !57 116 call void @llvm.lifetime.start.p0(i64 8, ptr %0) #5, !dbg !57 117 %arraydecay = getelementptr inbounds [2 x i32], ptr %f2_local, i64 0, i64 0, !dbg !58 118 call void @_ZL1aPii(ptr %arraydecay, i32 2), !dbg !59 119 %arrayidx = getelementptr inbounds [2 x i32], ptr %f2_local, i64 0, i64 0, !dbg !60 120 %1 = load i32, ptr %arrayidx, align 4, !dbg !60 121 %2 = bitcast ptr %f2_local to ptr, !dbg !61 122 call void @llvm.lifetime.end.p0(i64 8, ptr %2) #5, !dbg !61 123 ret i32 %1, !dbg !62 124} 125 126;; Store to fragment of local using rvalue offset as argument. 127;; int f3() { 128;; int f3_local[2]; 129;; a(f3_local + 1, 3); 130;; return f3_local[1]; 131;; } 132; CHECK-LABEL: define dso_local i32 @_Z2f3v() 133; CHECK: store i32 3, ptr %add.ptr, align 4,{{.*}} !DIAssignID ![[ID_3:[0-9]+]] 134; CHECK-NEXT: #dbg_assign(i32 3, ![[f3_local:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 32), ![[ID_3]], ptr %add.ptr, !DIExpression(), 135define dso_local i32 @_Z2f3v() #3 !dbg !63 { 136entry: 137 %f3_local = alloca [2 x i32], align 4, !DIAssignID !66 138 call void @llvm.dbg.assign(metadata i1 undef, metadata !65, metadata !DIExpression(), metadata !66, metadata ptr %f3_local, metadata !DIExpression()), !dbg !67 139 %0 = bitcast ptr %f3_local to ptr, !dbg !68 140 call void @llvm.lifetime.start.p0(i64 8, ptr %0) #5, !dbg !68 141 %arraydecay = getelementptr inbounds [2 x i32], ptr %f3_local, i64 0, i64 0, !dbg !69 142 %add.ptr = getelementptr inbounds i32, ptr %arraydecay, i64 1, !dbg !70 143 call void @_ZL1aPii(ptr %add.ptr, i32 3), !dbg !71 144 %arrayidx = getelementptr inbounds [2 x i32], ptr %f3_local, i64 0, i64 1, !dbg !72 145 %1 = load i32, ptr %arrayidx, align 4, !dbg !72 146 %2 = bitcast ptr %f3_local to ptr, !dbg !73 147 call void @llvm.lifetime.end.p0(i64 8, ptr %2) #5, !dbg !73 148 ret i32 %1, !dbg !74 149} 150 151;; Store to parameter directly. 152;; int f4(int f4_param) { 153;; a(&f4_param, 4); 154;; return f4_param; 155;; } 156; CHECK-LABEL: define dso_local i32 @_Z2f4i(i32 %f4_param) 157; CHECK: store i32 4, ptr %f4_param.addr, align 4,{{.*}} !DIAssignID ![[ID_4:[0-9]+]] 158; CHECK-NEXT: #dbg_assign(i32 4, ![[f4_param:[0-9]+]], !DIExpression(), ![[ID_4]], ptr %f4_param.addr, !DIExpression(), 159define dso_local i32 @_Z2f4i(i32 %f4_param) #3 !dbg !75 { 160entry: 161 %f4_param.addr = alloca i32, align 4, !DIAssignID !80 162 call void @llvm.dbg.assign(metadata i1 undef, metadata !79, metadata !DIExpression(), metadata !80, metadata ptr %f4_param.addr, metadata !DIExpression()), !dbg !81 163 store i32 %f4_param, ptr %f4_param.addr, align 4, !DIAssignID !82 164 call void @llvm.dbg.assign(metadata i32 %f4_param, metadata !79, metadata !DIExpression(), metadata !82, metadata ptr %f4_param.addr, metadata !DIExpression()), !dbg !81 165 call void @_ZL1aPii(ptr %f4_param.addr, i32 4), !dbg !83 166 %0 = load i32, ptr %f4_param.addr, align 4, !dbg !84 167 ret i32 %0, !dbg !85 168} 169 170;; Store through an alias. 171;; int f5(int f5_param) { 172;; int &f5_alias = f5_param; 173;; a(&f5_alias, 5); 174;; return f5_param; 175;; } 176; CHECK-LABEL: define dso_local i32 @_Z2f5i(i32 %f5_param) 177; CHECK: store i32 5, ptr %f5_param.addr, align 4,{{.*}}!DIAssignID ![[ID_5:[0-9]+]] 178; CHECK-NEXT: #dbg_assign(i32 5, ![[f5_param:[0-9]+]], !DIExpression(), ![[ID_5]], ptr %f5_param.addr, !DIExpression(), 179define dso_local i32 @_Z2f5i(i32 %f5_param) #3 !dbg !86 { 180entry: 181 %f5_param.addr = alloca i32, align 4, !DIAssignID !91 182 call void @llvm.dbg.assign(metadata i1 undef, metadata !88, metadata !DIExpression(), metadata !91, metadata ptr %f5_param.addr, metadata !DIExpression()), !dbg !92 183 call void @llvm.dbg.assign(metadata i1 undef, metadata !89, metadata !DIExpression(), metadata !93, metadata ptr undef, metadata !DIExpression()), !dbg !92 184 store i32 %f5_param, ptr %f5_param.addr, align 4, !DIAssignID !94 185 call void @llvm.dbg.assign(metadata i32 %f5_param, metadata !88, metadata !DIExpression(), metadata !94, metadata ptr %f5_param.addr, metadata !DIExpression()), !dbg !92 186 call void @llvm.dbg.assign(metadata ptr %f5_param.addr, metadata !89, metadata !DIExpression(), metadata !95, metadata ptr undef, metadata !DIExpression()), !dbg !92 187 call void @_ZL1aPii(ptr %f5_param.addr, i32 5), !dbg !96 188 %0 = load i32, ptr %f5_param.addr, align 4, !dbg !97 189 ret i32 %0, !dbg !98 190} 191 192;; int f6() { 193;; int f6_local; 194;; b(&f6_local, 6); 195;; return f6_local; 196;; } 197; CHECK-LABEL: define dso_local i32 @_Z2f6v() 198; CHECK: store i32 6, ptr %f6_local, align 4,{{.*}} !DIAssignID ![[ID_6:[0-9]+]] 199; CHECK-NEXT: #dbg_assign(i32 6, ![[f6_local:[0-9]+]], !DIExpression(), ![[ID_6]], ptr %f6_local, !DIExpression(), 200define dso_local i32 @_Z2f6v() #3 !dbg !99 { 201entry: 202 %f6_local = alloca i32, align 4, !DIAssignID !102 203 call void @llvm.dbg.assign(metadata i1 undef, metadata !101, metadata !DIExpression(), metadata !102, metadata ptr %f6_local, metadata !DIExpression()), !dbg !103 204 %0 = bitcast ptr %f6_local to ptr, !dbg !104 205 call void @llvm.lifetime.start.p0(i64 4, ptr %0) #5, !dbg !104 206 call void @_Z1bPii(ptr %f6_local, i32 6), !dbg !105 207 %1 = load i32, ptr %f6_local, align 4, !dbg !106 208 %2 = bitcast ptr %f6_local to ptr, !dbg !107 209 call void @llvm.lifetime.end.p0(i64 4, ptr %2) #5, !dbg !107 210 ret i32 %1, !dbg !108 211} 212 213declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) 214declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) 215declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) 216 217; CHECK-DAG: ![[f1_local]] = !DILocalVariable(name: "f1_local", 218; CHECK-DAG: ![[f2_local]] = !DILocalVariable(name: "f2_local", 219; CHECK-DAG: ![[f3_local]] = !DILocalVariable(name: "f3_local", 220; CHECK-DAG: ![[f4_param]] = !DILocalVariable(name: "f4_param", 221; CHECK-DAG: ![[f5_param]] = !DILocalVariable(name: "f5_param", 222; CHECK-DAG: ![[f6_local]] = !DILocalVariable(name: "f6_local", 223 224; CHECK-DAG: ![[f1_dbg]] = !DILocation(line: 0, scope: ![[f1_scope:[0-9]+]]) 225; CHECK-DAG: ![[f1_scope]] = distinct !DISubprogram(name: "f1", 226 227; CHECK-DAG: [[ID_1]] = distinct !DIAssignID() 228; CHECK-DAG: [[ID_2]] = distinct !DIAssignID() 229; CHECK-DAG: [[ID_3]] = distinct !DIAssignID() 230; CHECK-DAG: [[ID_4]] = distinct !DIAssignID() 231; CHECK-DAG: [[ID_5]] = distinct !DIAssignID() 232; CHECK-DAG: [[ID_6]] = distinct !DIAssignID() 233 234!llvm.dbg.cu = !{!0} 235!llvm.module.flags = !{!3, !4, !5, !1000} 236!llvm.ident = !{!6} 237 238!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) 239!1 = !DIFile(filename: "test.cpp", directory: "/") 240!2 = !{} 241!3 = !{i32 7, !"Dwarf Version", i32 4} 242!4 = !{i32 2, !"Debug Info Version", i32 3} 243!5 = !{i32 1, !"wchar_size", i32 4} 244!6 = !{!"clang version 12.0.0)"} 245!7 = distinct !DISubprogram(name: "b", linkageName: "_Z1bPii", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) 246!8 = !DISubroutineType(types: !9) 247!9 = !{null, !10, !11} 248!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) 249!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 250!12 = !{!13, !14} 251!13 = !DILocalVariable(name: "p1", arg: 1, scope: !7, file: !1, line: 5, type: !10) 252!14 = !DILocalVariable(name: "v1", arg: 2, scope: !7, file: !1, line: 5, type: !11) 253!15 = distinct !DIAssignID() 254!16 = !DILocation(line: 0, scope: !7) 255!17 = distinct !DIAssignID() 256!18 = distinct !DIAssignID() 257!19 = distinct !DIAssignID() 258!20 = !DILocation(line: 5, column: 27, scope: !7) 259!21 = !DILocation(line: 5, column: 38, scope: !7) 260!22 = distinct !DISubprogram(name: "a", linkageName: "_ZL1aPii", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !23) 261!23 = !{!24, !25} 262!24 = !DILocalVariable(name: "p2", arg: 1, scope: !22, file: !1, line: 2, type: !10) 263!25 = !DILocalVariable(name: "v2", arg: 2, scope: !22, file: !1, line: 2, type: !11) 264!26 = distinct !DIAssignID() 265!27 = !DILocation(line: 0, scope: !22) 266!28 = distinct !DIAssignID() 267!29 = distinct !DIAssignID() 268!30 = distinct !DIAssignID() 269!31 = !DILocation(line: 2, column: 38, scope: !22) 270!36 = !DILocation(line: 2, column: 44, scope: !22) 271!37 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 7, type: !38, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !40) 272!38 = !DISubroutineType(types: !39) 273!39 = !{!11} 274!40 = !{!41} 275!41 = !DILocalVariable(name: "f1_local", scope: !37, file: !1, line: 8, type: !11) 276!42 = distinct !DIAssignID() 277!43 = !DILocation(line: 0, scope: !37) 278!44 = !DILocation(line: 8, column: 3, scope: !37) 279!45 = !DILocation(line: 9, column: 3, scope: !37) 280!46 = !DILocation(line: 10, column: 10, scope: !37) 281!47 = !DILocation(line: 11, column: 1, scope: !37) 282!48 = !DILocation(line: 10, column: 3, scope: !37) 283!49 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 13, type: !38, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !50) 284!50 = !{!51} 285!51 = !DILocalVariable(name: "f2_local", scope: !49, file: !1, line: 14, type: !52) 286!52 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 64, elements: !53) 287!53 = !{!54} 288!54 = !DISubrange(count: 2) 289!55 = distinct !DIAssignID() 290!56 = !DILocation(line: 0, scope: !49) 291!57 = !DILocation(line: 14, column: 3, scope: !49) 292!58 = !DILocation(line: 15, column: 5, scope: !49) 293!59 = !DILocation(line: 15, column: 3, scope: !49) 294!60 = !DILocation(line: 16, column: 10, scope: !49) 295!61 = !DILocation(line: 17, column: 1, scope: !49) 296!62 = !DILocation(line: 16, column: 3, scope: !49) 297!63 = distinct !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !1, file: !1, line: 19, type: !38, scopeLine: 19, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !64) 298!64 = !{!65} 299!65 = !DILocalVariable(name: "f3_local", scope: !63, file: !1, line: 20, type: !52) 300!66 = distinct !DIAssignID() 301!67 = !DILocation(line: 0, scope: !63) 302!68 = !DILocation(line: 20, column: 3, scope: !63) 303!69 = !DILocation(line: 21, column: 5, scope: !63) 304!70 = !DILocation(line: 21, column: 14, scope: !63) 305!71 = !DILocation(line: 21, column: 3, scope: !63) 306!72 = !DILocation(line: 22, column: 10, scope: !63) 307!73 = !DILocation(line: 23, column: 1, scope: !63) 308!74 = !DILocation(line: 22, column: 3, scope: !63) 309!75 = distinct !DISubprogram(name: "f4", linkageName: "_Z2f4i", scope: !1, file: !1, line: 25, type: !76, scopeLine: 25, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !78) 310!76 = !DISubroutineType(types: !77) 311!77 = !{!11, !11} 312!78 = !{!79} 313!79 = !DILocalVariable(name: "f4_param", arg: 1, scope: !75, file: !1, line: 25, type: !11) 314!80 = distinct !DIAssignID() 315!81 = !DILocation(line: 0, scope: !75) 316!82 = distinct !DIAssignID() 317!83 = !DILocation(line: 26, column: 3, scope: !75) 318!84 = !DILocation(line: 27, column: 10, scope: !75) 319!85 = !DILocation(line: 27, column: 3, scope: !75) 320!86 = distinct !DISubprogram(name: "f5", linkageName: "_Z2f5i", scope: !1, file: !1, line: 30, type: !76, scopeLine: 30, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !87) 321!87 = !{!88, !89} 322!88 = !DILocalVariable(name: "f5_param", arg: 1, scope: !86, file: !1, line: 30, type: !11) 323!89 = !DILocalVariable(name: "f5_alias", scope: !86, file: !1, line: 31, type: !90) 324!90 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !11, size: 64) 325!91 = distinct !DIAssignID() 326!92 = !DILocation(line: 0, scope: !86) 327!93 = distinct !DIAssignID() 328!94 = distinct !DIAssignID() 329!95 = distinct !DIAssignID() 330!96 = !DILocation(line: 32, column: 3, scope: !86) 331!97 = !DILocation(line: 33, column: 10, scope: !86) 332!98 = !DILocation(line: 33, column: 3, scope: !86) 333!99 = distinct !DISubprogram(name: "f6", linkageName: "_Z2f6v", scope: !1, file: !1, line: 36, type: !38, scopeLine: 36, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !100) 334!100 = !{!101} 335!101 = !DILocalVariable(name: "f6_local", scope: !99, file: !1, line: 37, type: !11) 336!102 = distinct !DIAssignID() 337!103 = !DILocation(line: 0, scope: !99) 338!104 = !DILocation(line: 37, column: 3, scope: !99) 339!105 = !DILocation(line: 38, column: 3, scope: !99) 340!106 = !DILocation(line: 39, column: 10, scope: !99) 341!107 = !DILocation(line: 40, column: 1, scope: !99) 342!108 = !DILocation(line: 39, column: 3, scope: !99) 343!1000 = !{i32 7, !"debug-info-assignment-tracking", i1 true} 344