Skip to content

Commit fa9cef5

Browse files
Only guard loop metadata that has non-debug info in it (llvm#118825)
This PR is motivated by a mismatch we discovered between compilation results with vs. without `-g3`. We noticed this when compiling SPEC2017 testcases. The specific instance we saw is fixed in this PR by modifying a guard (see below), but it is likely similar instances exist elsewhere in the codebase. The specific case fixed in this PR manifests itself in the `SimplifyCFG` pass doing different things depending on whether DebugInfo is generated or not. At the end of this comment, there is reduced example code that shows the behavior in question. The differing behavior has two root causes: 1. Commit llvm@c07e19b adds loop metadata including debug locations to loops that otherwise would not have loop metadata 2. Commit llvm@ac28efa6c100 adds a guard to a simplification action in `SImplifyCFG` that prevents it from simplifying away loop metadata So, the change in 2. does not consider that when compiling with debug symbols, loops that otherwise would not have metadata that needs preserving, now have debug locations in their loop metadata. Thus, with `-g3`, `SimplifyCFG` behaves differently than without it. The larger issue is that while debug info is not supposed to influence the final compilation result, commits like 1. blur the line between what is and is not debug info, and not all optimization passes account for this. This PR does not address that and rather just modifies this particular guard in order to restore equivalent behavior between debug and non-debug builds in this one instance. --- Here is a reduced version of a file from `f526.blender_r` that showcases the behavior in question: ```C struct LinkNode; typedef struct LinkNode { struct LinkNode *next; void *link; } LinkNode; void do_projectpaint_thread_ph_v_state() { int *ps = do_projectpaint_thread_ph_v_state; LinkNode *node; while (do_projectpaint_thread_ph_v_state) for (node = ps; node; node = node->next) ; } ``` Compiling this with and without DebugInfo, and then disassembling the results, leads to different outcomes (tested on SystemZ and X86). The reason for this is that the `SimplifyCFG` pass does different things in either case.
1 parent 54665f5 commit fa9cef5

File tree

4 files changed

+106
-22
lines changed

4 files changed

+106
-22
lines changed

llvm/include/llvm/IR/Instruction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,10 @@ class Instruction : public User,
367367
/// Return true if this instruction has any metadata attached to it.
368368
bool hasMetadata() const { return DbgLoc || Value::hasMetadata(); }
369369

370+
// Return true if this instruction contains loop metadata other than
371+
// a debug location
372+
bool hasNonDebugLocLoopMetadata() const;
373+
370374
/// Return true if this instruction has metadata attached to it other than a
371375
/// debug location.
372376
bool hasMetadataOtherThanDebugLoc() const { return Value::hasMetadata(); }

llvm/lib/IR/Instruction.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212

1313
#include "llvm/IR/Instruction.h"
1414
#include "llvm/ADT/DenseSet.h"
15+
#include "llvm/ADT/STLExtras.h"
1516
#include "llvm/IR/AttributeMask.h"
1617
#include "llvm/IR/Attributes.h"
1718
#include "llvm/IR/Constants.h"
1819
#include "llvm/IR/InstrTypes.h"
1920
#include "llvm/IR/Instructions.h"
2021
#include "llvm/IR/IntrinsicInst.h"
2122
#include "llvm/IR/Intrinsics.h"
23+
#include "llvm/IR/LLVMContext.h"
2224
#include "llvm/IR/MemoryModelRelaxationAnnotations.h"
2325
#include "llvm/IR/Module.h"
2426
#include "llvm/IR/Operator.h"
@@ -461,6 +463,29 @@ bool Instruction::hasPoisonGeneratingMetadata() const {
461463
hasMetadata(LLVMContext::MD_align);
462464
}
463465

466+
bool Instruction::hasNonDebugLocLoopMetadata() const {
467+
// If there is no loop metadata at all, we also don't have
468+
// non-debug loop metadata, obviously.
469+
if (!hasMetadata(LLVMContext::MD_loop))
470+
return false;
471+
472+
// If we do have loop metadata, retrieve it.
473+
MDNode *LoopMD = getMetadata(LLVMContext::MD_loop);
474+
475+
// Check if the existing operands are debug locations. This loop
476+
// should terminate after at most three iterations. Skip
477+
// the first item because it is a self-reference.
478+
for (const MDOperand &Op : llvm::drop_begin(LoopMD->operands())) {
479+
// check for debug location type by attempting a cast.
480+
if (!dyn_cast<DILocation>(Op)) {
481+
return true;
482+
}
483+
}
484+
485+
// If we get here, then all we have is debug locations in the loop metadata.
486+
return false;
487+
}
488+
464489
void Instruction::dropPoisonGeneratingMetadata() {
465490
eraseMetadata(LLVMContext::MD_range);
466491
eraseMetadata(LLVMContext::MD_nonnull);

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,10 +1279,10 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
12791279
// | for.body <---- (md2)
12801280
// |_______| |______|
12811281
if (Instruction *TI = BB->getTerminator())
1282-
if (TI->hasMetadata(LLVMContext::MD_loop))
1282+
if (TI->hasNonDebugLocLoopMetadata())
12831283
for (BasicBlock *Pred : predecessors(BB))
12841284
if (Instruction *PredTI = Pred->getTerminator())
1285-
if (PredTI->hasMetadata(LLVMContext::MD_loop))
1285+
if (PredTI->hasNonDebugLocLoopMetadata())
12861286
return false;
12871287

12881288
if (BBKillable)
@@ -1345,12 +1345,15 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
13451345
}
13461346
}
13471347

1348-
// If the unconditional branch we replaced contains llvm.loop metadata, we
1349-
// add the metadata to the branch instructions in the predecessors.
1348+
// If the unconditional branch we replaced contains non-debug llvm.loop
1349+
// metadata, we add the metadata to the branch instructions in the
1350+
// predecessors.
13501351
if (Instruction *TI = BB->getTerminator())
1351-
if (MDNode *LoopMD = TI->getMetadata(LLVMContext::MD_loop))
1352+
if (TI->hasNonDebugLocLoopMetadata()) {
1353+
MDNode *LoopMD = TI->getMetadata(LLVMContext::MD_loop);
13521354
for (BasicBlock *Pred : predecessors(BB))
13531355
Pred->getTerminator()->setMetadata(LLVMContext::MD_loop, LoopMD);
1356+
}
13541357

13551358
if (BBKillable) {
13561359
// Everything that jumped to BB now goes to Succ.

llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ if.then: ; preds = %while.body
2828
br label %if.end
2929

3030
; CHECK: if.then:
31-
; CHECK: br label %while.cond, !llvm.loop !0
31+
; CHECK: br label %while.cond, !llvm.loop !1
3232

3333
if.else: ; preds = %while.body
3434
%4 = load i32, ptr %count, align 4
@@ -37,10 +37,10 @@ if.else: ; preds = %while.body
3737
br label %if.end
3838

3939
; CHECK: if.else:
40-
; CHECK: br label %while.cond, !llvm.loop !0
40+
; CHECK: br label %while.cond, !llvm.loop !1
4141

4242
if.end: ; preds = %if.else, %if.then
43-
br label %while.cond, !llvm.loop !0
43+
br label %while.cond, !llvm.loop !1
4444

4545
while.end: ; preds = %while.cond
4646
ret void
@@ -74,7 +74,7 @@ entry:
7474
br label %while.cond
7575

7676
while.cond.loopexit: ; preds = %for.body
77-
br label %while.cond, !llvm.loop !2
77+
br label %while.cond, !llvm.loop !3
7878

7979
while.cond: ; preds = %while.cond.loopexit, %entry
8080
%i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ]
@@ -96,22 +96,74 @@ for.body: ; preds = %while.body, %for.bo
9696
%1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0)
9797
%inc = add nuw nsw i32 %k.07, 1
9898
%cmp1 = icmp ult i32 %inc, 5
99-
br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !4
99+
br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5
100100

101101
while.end: ; preds = %while.cond
102102
%sum.0.lcssa = phi i32 [ %sum.0, %while.cond ]
103103
ret i32 %sum.0.lcssa
104104
}
105105

106-
!0 = distinct !{!0, !1}
107-
!1 = !{!"llvm.loop.distribute.enable", i1 true}
108-
!2 = distinct !{!2, !3}
109-
!3 = !{!"llvm.loop.mustprogress"}
110-
!4 = distinct !{!4, !3, !5}
111-
!5 = !{!"llvm.loop.unroll.enable"}
112-
; CHECK: !0 = distinct !{!0, !1}
113-
; CHECK: !1 = !{!"llvm.loop.distribute.enable", i1 true}
114-
; CHECK: !2 = distinct !{!2, !3}
115-
; CHECK: !3 = !{!"llvm.loop.mustprogress"}
116-
; CHECK: !4 = distinct !{!4, !3, !5}
117-
; CHECK: !5 = !{!"llvm.loop.unroll.enable"}
106+
; Test that the condition tested above does not trigger when the loop metadata consists only of debug locations,
107+
; i.e.the empty loop latch `while.cond.loopexit` *will* be folded into its successor if its
108+
; predecessor blocks are also loop latches and any loop metadata attached to it consists of debug information.
109+
;
110+
define i32 @test3(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) !dbg !7 {
111+
entry:
112+
br label %while.cond
113+
114+
;CHECK-LABEL: @test3(
115+
;CHECK-NOT: while.cond.loopexit
116+
while.cond.loopexit: ; preds = %for.body
117+
br label %while.cond, !llvm.loop !10
118+
119+
while.cond: ; preds = %while.cond.loopexit, %entry
120+
%i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ]
121+
%sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ]
122+
%sub = sub nsw i32 %b, %i.0
123+
%cmp = icmp sgt i32 %sub, %remainder
124+
br i1 %cmp, label %while.body, label %while.end
125+
126+
while.body: ; preds = %while.cond
127+
%add = add nsw i32 %i.0, %step
128+
br label %for.body
129+
130+
for.body: ; preds = %while.body, %for.body
131+
%k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ]
132+
%add2 = add nsw i32 %k.07, %add
133+
%idxprom = sext i32 %add2 to i64
134+
%arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom
135+
%0 = load i32, ptr %arrayidx, align 4
136+
%1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0)
137+
%inc = add nuw nsw i32 %k.07, 1
138+
%cmp1 = icmp ult i32 %inc, 5
139+
br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5
140+
141+
while.end: ; preds = %while.cond
142+
%sum.0.lcssa = phi i32 [ %sum.0, %while.cond ]
143+
ret i32 %sum.0.lcssa
144+
}
145+
146+
!llvm.module.flags = !{!0}
147+
148+
!0 = !{i32 2, !"Debug Info Version", i32 3}
149+
!1 = distinct !{!1, !2}
150+
!2 = !{!"llvm.loop.distribute.enable", i1 true}
151+
!3 = distinct !{!3, !4}
152+
!4 = !{!"llvm.loop.mustprogress"}
153+
!5 = distinct !{!5, !4, !6}
154+
!6 = !{!"llvm.loop.unroll.enable"}
155+
!7 = distinct !DISubprogram(name: "test3", scope: !8, file: !8, spFlags: DISPFlagDefinition, unit: !9)
156+
!8 = !DIFile(filename: "preserve-llvm-loop-metadata.ll", directory: "/")
157+
!9 = distinct !DICompileUnit(language: DW_LANG_C99, file: !8, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug)
158+
!10 = distinct !{!10, !11, !13}
159+
!11 = !DILocation(line: 8, column: 4, scope: !12)
160+
!12 = distinct !DILexicalBlock(scope: !7, file: !8, line: 8, column: 2)
161+
!13 = !DILocation(line: 9, column: 23, scope: !12)
162+
163+
; CHECK: !1 = distinct !{!1, !2}
164+
; CHECK: !2 = !{!"llvm.loop.distribute.enable", i1 true}
165+
; CHECK: !3 = distinct !{!3, !4}
166+
; CHECK: !4 = !{!"llvm.loop.mustprogress"}
167+
; CHECK: !5 = distinct !{!5, !4, !6}
168+
; CHECK: !6 = !{!"llvm.loop.unroll.enable"}
169+
; CHECK-NOT: !10 = distinct !{!10, !11, !13}

0 commit comments

Comments
 (0)