During sinkUnusedInvariants
step in IndVarSimplify
pass, it is possible that llvm.dbg.value
is left out after loop invariant value is sunk into exit block. For example, if I debugify this test llvm-project/sink-from-preheader.ll at main · llvm/llvm-project · GitHub
opt -debugify -indvars -indvars-predicate-loops=0 -check-debugify -S llvm/test/Transforms/IndVarSimplify/sink-from-preheader.ll
It produces
; ModuleID = '../llvm-project/llvm/test/Transforms/IndVarSimplify/sink-from-preheader.ll'
source_filename = "../llvm-project/llvm/test/Transforms/IndVarSimplify/sink-from-preheader.ll"
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin10.0"
define i32 @test(i32 %a, i32 %b, i32 %N) !dbg !5 {
entry:
call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !15
br label %loop, !dbg !16
loop: ; preds = %loop, %entry
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ], !dbg !17
call void @llvm.dbg.value(metadata i32 %iv, metadata !11, metadata !DIExpression()), !dbg !17
%iv.next = add nuw nsw i32 %iv, 1, !dbg !18
call void @llvm.dbg.value(metadata i32 %iv.next, metadata !12, metadata !DIExpression()), !dbg !18
%cmp = icmp slt i32 %iv.next, %N, !dbg !19
call void @llvm.dbg.value(metadata i1 %cmp, metadata !13, metadata !DIExpression()), !dbg !19
br i1 %cmp, label %loop, label %exit, !dbg !20
exit: ; preds = %loop
%add = add i32 %a, %b, !dbg !15
ret i32 %add, !dbg !21
}
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
attributes #0 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0}
!llvm.debugify = !{!2, !3}
!llvm.module.flags = !{!4}
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "../llvm-project/llvm/test/Transforms/IndVarSimplify/sink-from-preheader.ll", directory: "/")
!2 = !{i32 7}
!3 = !{i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
!6 = !DISubroutineType(types: !7)
!7 = !{}
!8 = !{!9, !11, !12, !13}
!9 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !10)
!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
!11 = !DILocalVariable(name: "2", scope: !5, file: !1, line: 3, type: !10)
!12 = !DILocalVariable(name: "3", scope: !5, file: !1, line: 4, type: !10)
!13 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !14)
!14 = !DIBasicType(name: "ty8", size: 8, encoding: DW_ATE_unsigned)
!15 = !DILocation(line: 1, column: 1, scope: !5)
!16 = !DILocation(line: 2, column: 1, scope: !5)
!17 = !DILocation(line: 3, column: 1, scope: !5)
!18 = !DILocation(line: 4, column: 1, scope: !5)
!19 = !DILocation(line: 5, column: 1, scope: !5)
!20 = !DILocation(line: 6, column: 1, scope: !5)
!21 = !DILocation(line: 7, column: 1, scope: !5)
Even though -check-debugify
is OK with the result, I find it strange that the llvm.dbg.value
in entry
block associates the source variable with a not-yet-created value. I think it should set to “undef” and another llvm.dbg.value
should be created (a clone of the first one) after %add
in exit
block to reflect the new value.
More context:
I am facing a verifier failure in CoroSplit
pass trigged by this.
Before IndVarSimplify
:
preheader:
%shr.i.i1076 = lshr i64 %316, 24, !dbg !84650
%or.i.i1077 = or i64 %shr.i.i1076, 128, !dbg !84650
call void @llvm.dbg.value(metadata i64 %or.i.i1077, metadata !84646, metadata !DIExpression()), !dbg !84647
... ...
loop:
... ...
exit:
... ...
After IndVarSimplify
:
preheader:
%shr.i.i1076 = lshr i64 %316, 24, !dbg !84650
call void @llvm.dbg.value(metadata i64 %or.i.i1077, metadata !84646, metadata !DIExpression()), !dbg !84647
... ...
loop:
... ...
exit:
%or.i.i1077 = or i64 %shr.i.i1076, 128, !dbg !84650
... ...
After coro::buildCoroutineFrame
and spilling materializable instructions across suspension points
preheader:
... ...
%or.i.i10772788 = or i64 %shr.i.i1076, 128, !dbg !88824
%shr.i.i1076 = lshr i64 %272, 24, !dbg !88803
call void @llvm.dbg.value(metadata i64 %or.i.i10772788, metadata !84646, metadata !DIExpression()), !dbg !84647
... ...
exit:
%or.i.i1077 = or i64 %shr.i.i1076, 128, !dbg !84650
... ...
%or.i.i1077
is sunk into exit block but its llvm.dbg.value
is left out. When building coro frame, materializable instructions are reconstructed. %or.i.i1077
is reconstructed at the beginning of the block containing its user llvm.dbg.value
: llvm-project/CoroFrame.cpp at main · llvm/llvm-project · GitHub. This triggers an assert
Instruction does not dominate all uses!
%shr.i.i1076 = lshr i64 %272, 24, !dbg !88803
%or.i.i10772788 = or i64 %shr.i.i1076, 128, !dbg !88824
Even though I think the spilling code can be improved in this case, IndVarSimplify
is where things go wrong.