[llvm] 2da67e8 - [Assignment Tracking][18/*] Account for assignment tracking in LICM

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 15 04:25:02 PST 2022


Author: OCHyams
Date: 2022-11-15T12:24:16Z
New Revision: 2da67e8053c7320ed8774830b8fe1c0c4d7e7ebb

URL: https://github.com/llvm/llvm-project/commit/2da67e8053c7320ed8774830b8fe1c0c4d7e7ebb
DIFF: https://github.com/llvm/llvm-project/commit/2da67e8053c7320ed8774830b8fe1c0c4d7e7ebb.diff

LOG: [Assignment Tracking][18/*] Account for assignment tracking in LICM

The Assignment Tracking debug-info feature is outlined in this RFC:

https://discourse.llvm.org/t/
rfc-assignment-tracking-a-better-way-of-specifying-variable-locations-in-ir

Merge DIAssignID attachments on stores that are merged and sunk out of
loops. The store may be sunk into multiple exit blocks, and in this case all
the copies of the store get the same DIAssignID.

Reviewed By: jmorse

Differential Revision: https://reviews.llvm.org/D133313

Added: 
    llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll
    llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll

Modified: 
    llvm/lib/Transforms/Scalar/LICM.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 001937cc1670..e6869b078108 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -1789,6 +1789,7 @@ class LoopPromoter : public LoadAndStorePromoter {
   AAMDNodes AATags;
   ICFLoopSafetyInfo &SafetyInfo;
   bool CanInsertStoresInExitBlocks;
+  ArrayRef<const Instruction *> Uses;
 
   // We're about to add a use of V in a loop exit block.  Insert an LCSSA phi
   // (if legal) if doing so would add an out-of-loop use to an instruction
@@ -1821,7 +1822,7 @@ class LoopPromoter : public LoadAndStorePromoter {
         PredCache(PIC), MSSAU(MSSAU), LI(li), DL(std::move(dl)),
         Alignment(Alignment), UnorderedAtomic(UnorderedAtomic), AATags(AATags),
         SafetyInfo(SafetyInfo),
-        CanInsertStoresInExitBlocks(CanInsertStoresInExitBlocks) {}
+        CanInsertStoresInExitBlocks(CanInsertStoresInExitBlocks), Uses(Insts) {}
 
   bool isInstInList(Instruction *I,
                     const SmallVectorImpl<Instruction *> &) const override {
@@ -1838,6 +1839,7 @@ class LoopPromoter : public LoadAndStorePromoter {
     // store of the live-out values that feed them.  Since we've already told
     // the SSA updater about the defs in the loop and the preheader
     // definition, it is all set and we can start using it.
+    DIAssignID *NewID = nullptr;
     for (unsigned i = 0, e = LoopExitBlocks.size(); i != e; ++i) {
       BasicBlock *ExitBlock = LoopExitBlocks[i];
       Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock);
@@ -1849,6 +1851,21 @@ class LoopPromoter : public LoadAndStorePromoter {
         NewSI->setOrdering(AtomicOrdering::Unordered);
       NewSI->setAlignment(Alignment);
       NewSI->setDebugLoc(DL);
+      // Attach DIAssignID metadata to the new store, generating it on the
+      // first loop iteration.
+      if (i == 0) {
+        // NewSI will have its DIAssignID set here if there are any stores in
+        // Uses with a DIAssignID attachment. This merged ID will then be
+        // attached to the other inserted stores (in the branch below).
+        NewSI->mergeDIAssignID(Uses);
+        NewID = cast_or_null<DIAssignID>(
+            NewSI->getMetadata(LLVMContext::MD_DIAssignID));
+      } else {
+        // Attach the DIAssignID (or nullptr) merged from Uses in the branch
+        // above.
+        NewSI->setMetadata(LLVMContext::MD_DIAssignID, NewID);
+      }
+
       if (AATags)
         NewSI->setAAMetadata(AATags);
 

diff  --git a/llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll
new file mode 100644
index 000000000000..a80f767def4b
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll
@@ -0,0 +1,105 @@
+; RUN: opt -licm %s -S -experimental-assignment-tracking | FileCheck %s
+
+;; Ensure that we correctly merge the DIAssignID's from the sunk stores, add it
+;; to the new new store instruction, and update the dbg.assign intrinsics using
+;; them to use it instead.
+
+;; Generated from the following, with some changes to the IR by hand:
+;; $ cat test.c
+;; void b(int c) {
+;;   esc(&c);
+;;   for (; c;  c++) // NOTE: I've added another store to c in the loop by hand.
+;;   ;
+;; }
+;; $ clang -O2 -Xclang -disable-llvm-passes -g -emit-llvm -S -o a.ll
+;; $ opt -passes=declare-to-assign,sroa,instcombine,simplifycfg,loop-simplify,lcssa,loop-rotate a.ll
+
+; CHECK-LABEL: for.inc:
+;; Check that the stores have actually been removed from this block, otherwise
+;; this test is useless.
+; CHECK-NOT: store i32 %inc, ptr %c.addr
+;; Check that the two dbg.assigns now have the same (merged) !DIAssingID ID.
+; CHECK: call void @llvm.dbg.assign(metadata i32 %inc, metadata ![[VAR_C:[0-9]+]], metadata !DIExpression(), metadata ![[ID:[0-9]+]], metadata ptr %c.addr, metadata !DIExpression()), !dbg
+; CHECK-NOT: store i32 %inc, ptr %c.addr
+; CHECK: call void @llvm.dbg.assign(metadata i32 %inc, metadata ![[VAR_C]], metadata !DIExpression(), metadata ![[ID]], metadata ptr %c.addr, metadata !DIExpression()), !dbg
+
+; CHECK-LABEL: for.cond.for.end_crit_edge:
+; CHECK-NEXT: %[[PHI:.*]] = phi i32 [ %inc, %for.inc ]
+; CHECK-NEXT: store i32 %[[PHI]], ptr %c.addr{{.*}}, !DIAssignID ![[ID]]
+; CHECK-NOT:  {{.*}}llvm.dbg{{.*}}
+; CHECK-NEXT: br label %for.end
+
+; CHECK: ![[VAR_C]] = !DILocalVariable(name: "c",
+
+define dso_local void @b(i32 %c) !dbg !7 {
+entry:
+  %c.addr = alloca i32, align 4
+  store i32 %c, ptr %c.addr, align 4, !DIAssignID !36
+  call void @llvm.dbg.assign(metadata i32 %c, metadata !12, metadata !DIExpression(), metadata !36, metadata ptr %c.addr, metadata !DIExpression()), !dbg !13
+  call void @esc(ptr nonnull %c.addr), !dbg !18
+  %0 = load i32, ptr %c.addr, align 4, !dbg !19
+  %tobool.not1 = icmp eq i32 %0, 0, !dbg !22
+  br i1 %tobool.not1, label %for.end, label %for.inc.lr.ph, !dbg !22
+
+for.inc.lr.ph:                                    ; preds = %entry
+  br label %for.inc, !dbg !22
+
+for.inc:                                          ; preds = %for.inc.lr.ph, %for.inc
+  %1 = load i32, ptr %c.addr, align 4, !dbg !23
+  %inc = add nsw i32 %1, 1, !dbg !23
+  store i32 %inc, ptr %c.addr, align 4, !dbg !23, !DIAssignID !38
+  call void @llvm.dbg.assign(metadata i32 %inc, metadata !12, metadata !DIExpression(), metadata !38, metadata ptr %c.addr, metadata !DIExpression()), !dbg !13
+  ;; The following store and dbg.assign intrinsics are copies of those above,
+  ;; with a new DIAssignID.
+  store i32 %inc, ptr %c.addr, align 4, !dbg !23, !DIAssignID !37
+  call void @llvm.dbg.assign(metadata i32 %inc, metadata !12, metadata !DIExpression(), metadata !37, metadata ptr %c.addr, metadata !DIExpression()), !dbg !13
+  %2 = load i32, ptr %c.addr, align 4, !dbg !19
+  %tobool.not = icmp eq i32 %2, 0, !dbg !22
+  br i1 %tobool.not, label %for.cond.for.end_crit_edge, label %for.inc, !dbg !22, !llvm.loop !24
+
+for.cond.for.end_crit_edge:                       ; preds = %for.inc
+  br label %for.end, !dbg !22
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry
+  ret void, !dbg !27
+}
+
+
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
+declare !dbg !28 dso_local void @esc(ptr)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 12.0.0"}
+!7 = distinct !DISubprogram(name: "b", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "c", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+!13 = !DILocation(line: 0, scope: !7)
+!18 = !DILocation(line: 3, column: 3, scope: !7)
+!19 = !DILocation(line: 4, column: 10, scope: !20)
+!20 = distinct !DILexicalBlock(scope: !21, file: !1, line: 4, column: 3)
+!21 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 3)
+!22 = !DILocation(line: 4, column: 3, scope: !21)
+!23 = !DILocation(line: 4, column: 15, scope: !20)
+!24 = distinct !{!24, !22, !25, !26}
+!25 = !DILocation(line: 5, column: 3, scope: !21)
+!26 = !{!"llvm.loop.mustprogress"}
+!27 = !DILocation(line: 6, column: 1, scope: !7)
+!28 = !DISubprogram(name: "esc", scope: !1, file: !1, line: 1, type: !29, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
+!29 = !DISubroutineType(types: !30)
+!30 = !{null, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!36 = distinct !DIAssignID()
+!37 = distinct !DIAssignID()
+!38 = distinct !DIAssignID()

diff  --git a/llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll
new file mode 100644
index 000000000000..ef39d66e6dec
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll
@@ -0,0 +1,180 @@
+; RUN: opt %s -S -licm -o - -experimental-assignment-tracking | FileCheck %s
+
+;; $ cat test.c
+;; int b, c, d;
+;; void e();
+;; void f(int *g) { *g = b; }
+;; void i() {
+;;   int h, a;
+;;   for (;;) {
+;;     e();
+;;     a = 1;
+;;     if (h) {
+;;       if (d)
+;;         continue;
+;;       h = c;
+;;     }
+;;     f(&a);
+;;   }
+;; }
+;; Generated by getting the IR before LICM in:
+;; $ clang  -c  -O2 -g  test.c -fno-unroll-loops -fno-vectorize -fno-inline -Xclang -fexperimental-assignment-tracking -o -
+
+;;       entry
+;;         |
+;;         v
+;; *---->for.cond.outer
+;; |       |
+;; |       v
+;; |  +->for.cond-----+
+;; |  |    |          |
+;; |  |    v          |
+;; |  +--if.then      |
+;; |       |          |
+;; |       v          v
+;; |     if.end     if.end3.loopexit
+;; |       |          |
+;; |       v          |
+;; +-----if.end3 <----+
+;;
+;; The store in for.cond is sunk into the inner-loop exits if.end and if.end3.loopexit.
+;;
+;; Check that a store sunk into multiple exits retains its (their) dbg.assign,
+;; and that the new stores share the same DIAssignID.
+
+; CHECK-LABEL: for.cond:
+; CHECK: call void @llvm.dbg.assign(metadata i32 1, metadata ![[var:[0-9]+]], metadata !DIExpression(), metadata ![[id:[0-9]+]], metadata ptr %a, metadata !DIExpression()), !dbg
+
+; CHECK-LABEL: if.end:
+; CHECK-NEXT: store i32 1, ptr %a, align 1,{{.*}}!DIAssignID ![[id]]
+
+; CHECK-LABEL: if.end3.loopexit:
+; CHECK-NEXT: store i32 1, ptr %a, align 1,{{.*}}!DIAssignID ![[id]]
+
+; CHECK-DAG: ![[var]] = !DILocalVariable(name: "a",
+
+ at b = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+ at d = dso_local local_unnamed_addr global i32 0, align 4, !dbg !9
+ at c = dso_local local_unnamed_addr global i32 0, align 4, !dbg !6
+
+define dso_local void @f(ptr nocapture %g) local_unnamed_addr #0 !dbg !15 {
+entry:
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !20, metadata !DIExpression(), metadata !21, metadata ptr undef, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.assign(metadata ptr %g, metadata !20, metadata !DIExpression(), metadata !23, metadata ptr undef, metadata !DIExpression()), !dbg !22
+  %0 = load i32, ptr @b, align 4, !dbg !24
+  store i32 %0, ptr %g, align 4, !dbg !29
+  ret void, !dbg !30
+}
+
+define dso_local void @i() local_unnamed_addr #2 !dbg !31 {
+entry:
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !35, metadata !DIExpression(), metadata !37, metadata ptr undef, metadata !DIExpression()), !dbg !38
+  %a = alloca i32, align 4, !DIAssignID !39
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !36, metadata !DIExpression(), metadata !39, metadata ptr %a, metadata !DIExpression()), !dbg !38
+  call void @llvm.lifetime.start.p0i8(i64 4, ptr nonnull %a) #5, !dbg !40
+  br label %for.cond.outer, !dbg !41
+
+for.cond.outer:                                   ; preds = %if.end3, %entry
+  %h.0.ph = phi i32 [ %h.1, %if.end3 ], [ undef, %entry ]
+  br label %for.cond, !dbg !42
+
+for.cond:                                         ; preds = %for.cond.outer, %if.then
+  call void @llvm.dbg.value(metadata i32 %h.0.ph, metadata !35, metadata !DIExpression()), !dbg !38
+  tail call void (...) @e() #5, !dbg !44
+  store i32 1, ptr %a, align 4, !dbg !47, !DIAssignID !48
+  call void @llvm.dbg.assign(metadata i32 1, metadata !36, metadata !DIExpression(), metadata !48, metadata ptr %a, metadata !DIExpression()), !dbg !38
+  %tobool.not = icmp eq i32 %h.0.ph, 0, !dbg !49
+  br i1 %tobool.not, label %if.end3.loopexit, label %if.then, !dbg !51
+
+if.then:                                          ; preds = %for.cond
+  %0 = load i32, ptr @d, align 4, !dbg !52
+  %tobool1.not = icmp eq i32 %0, 0, !dbg !52
+  br i1 %tobool1.not, label %if.end, label %for.cond, !dbg !55, !llvm.loop !56
+
+if.end:                                           ; preds = %if.then
+  %1 = load i32, ptr @c, align 4, !dbg !59
+  call void @llvm.dbg.assign(metadata i32 %1, metadata !35, metadata !DIExpression(), metadata !60, metadata ptr undef, metadata !DIExpression()), !dbg !38
+  br label %if.end3, !dbg !61
+
+if.end3.loopexit:                                 ; preds = %for.cond
+  br label %if.end3, !dbg !62
+
+if.end3:                                          ; preds = %if.end3.loopexit, %if.end
+  %h.1 = phi i32 [ %1, %if.end ], [ 0, %if.end3.loopexit ]
+  call void @llvm.dbg.value(metadata i32 %h.1, metadata !35, metadata !DIExpression()), !dbg !38
+  call void @f(ptr nonnull %a), !dbg !62
+  br label %for.cond.outer, !dbg !63, !llvm.loop !56
+}
+
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1
+declare void @llvm.lifetime.start.p0i8(i64 immarg, ptr nocapture) #3
+declare !dbg !64 dso_local void @e(...) local_unnamed_addr #4
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/")
+!4 = !{}
+!5 = !{!0, !6, !9}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
+!10 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!11 = !{i32 7, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 12.0.0"}
+!15 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19)
+!16 = !DISubroutineType(types: !17)
+!17 = !{null, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64)
+!19 = !{!20}
+!20 = !DILocalVariable(name: "g", arg: 1, scope: !15, file: !3, line: 3, type: !18)
+!21 = distinct !DIAssignID()
+!22 = !DILocation(line: 0, scope: !15)
+!23 = distinct !DIAssignID()
+!24 = !DILocation(line: 3, column: 23, scope: !15)
+!29 = !DILocation(line: 3, column: 21, scope: !15)
+!30 = !DILocation(line: 3, column: 26, scope: !15)
+!31 = distinct !DISubprogram(name: "i", scope: !3, file: !3, line: 4, type: !32, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!32 = !DISubroutineType(types: !33)
+!33 = !{null}
+!34 = !{!35, !36}
+!35 = !DILocalVariable(name: "h", scope: !31, file: !3, line: 5, type: !8)
+!36 = !DILocalVariable(name: "a", scope: !31, file: !3, line: 5, type: !8)
+!37 = distinct !DIAssignID()
+!38 = !DILocation(line: 0, scope: !31)
+!39 = distinct !DIAssignID()
+!40 = !DILocation(line: 5, column: 3, scope: !31)
+!41 = !DILocation(line: 6, column: 3, scope: !31)
+!42 = !DILocation(line: 6, column: 3, scope: !43)
+!43 = distinct !DILexicalBlock(scope: !31, file: !3, line: 6, column: 3)
+!44 = !DILocation(line: 7, column: 5, scope: !45)
+!45 = distinct !DILexicalBlock(scope: !46, file: !3, line: 6, column: 12)
+!46 = distinct !DILexicalBlock(scope: !43, file: !3, line: 6, column: 3)
+!47 = !DILocation(line: 8, column: 7, scope: !45)
+!48 = distinct !DIAssignID()
+!49 = !DILocation(line: 9, column: 9, scope: !50)
+!50 = distinct !DILexicalBlock(scope: !45, file: !3, line: 9, column: 9)
+!51 = !DILocation(line: 9, column: 9, scope: !45)
+!52 = !DILocation(line: 10, column: 11, scope: !53)
+!53 = distinct !DILexicalBlock(scope: !54, file: !3, line: 10, column: 11)
+!54 = distinct !DILexicalBlock(scope: !50, file: !3, line: 9, column: 12)
+!55 = !DILocation(line: 10, column: 11, scope: !54)
+!56 = distinct !{!56, !42, !57, !58}
+!57 = !DILocation(line: 15, column: 3, scope: !43)
+!58 = !{!"llvm.loop.unroll.disable"}
+!59 = !DILocation(line: 12, column: 11, scope: !54)
+!60 = distinct !DIAssignID()
+!61 = !DILocation(line: 13, column: 5, scope: !54)
+!62 = !DILocation(line: 14, column: 5, scope: !45)
+!63 = !DILocation(line: 6, column: 3, scope: !46)
+!64 = !DISubprogram(name: "e", scope: !3, file: !3, line: 2, type: !65, spFlags: DISPFlagOptimized, retainedNodes: !4)
+!65 = !DISubroutineType(types: !66)
+!66 = !{null, null}


        


More information about the llvm-commits mailing list