Jeremy Morse 3d7aa961ac
[DebugInfo][RemoveDIs] Use autoupgrader to convert old debug-info (#143452)
By chance, two things have prevented the autoupgrade path being
exercised much so far:
 * LLParser setting the debug-info mode to "old" on seeing intrinsics,
* The test in AutoUpgrade.cpp wanting to upgrade into a "new" debug-info
block.

In practice, this appears to mean this code path hasn't seen the various
invalid inputs that can come its way. This commit does a number of
things:
* Tolerates the various illegal inputs that can be written with
debug-intrinsics, and that must be tolerated until the Verifier runs,
 * Printing illegal/null DbgRecord fields must succeed,
* Verifier errors need to localise the function/block where the error
is,
 * Tests that now see debug records will print debug-record errors,

Plus a few new tests for other intrinsic-to-debug-record failures modes
I found. There are also two edge cases:
* Some of the unit tests switch back and forth between intrinsic and
record modes at will; I've deleted coverage and some assertions to
tolerate this as intrinsic support is now Gone (TM),
* In sroa-extract-bits.ll, the order of debug records flips. This is
because the autoupgrader upgrades in the opposite order to the basic
block conversion routines... which doesn't change the record order, but
_does_ change the use list order in Metadata! This should (TM) have no
consequence to the correctness of LLVM, but will change the order of
various records and the order of DWARF record output too.

I tried to reduce this patch to a smaller collection of changes, but
they're all intertwined, sorry.
2025-06-11 13:56:30 +01:00

207 lines
6.8 KiB
LLVM

; RUN: opt -passes=objc-arc -S < %s 2>&1 | FileCheck %s '--implicit-check-not=ignoring invalid debug'
declare void @alterRefCount()
declare void @use(ptr)
declare void @readOnlyFunc(ptr, ptr)
@g0 = global ptr null, align 8
; Check that ARC optimizer doesn't reverse the order of the retain call and the
; release call when there are debug instructions.
; CHECK: call ptr @llvm.objc.retain(ptr %x)
; CHECK: call void @llvm.objc.release(ptr %x)
define i32 @test(ptr %x, ptr %y, i8 %z, i32 %i) {
%i.addr = alloca i32, align 4
store i32 %i, ptr %i.addr, align 4
%v1 = tail call ptr @llvm.objc.retain(ptr %x)
store i8 %z, ptr %x
call void @llvm.dbg.declare(metadata ptr %i.addr, metadata !11, metadata !DIExpression()), !dbg !10
call void @alterRefCount()
tail call void @llvm.objc.release(ptr %x)
ret i32 %i
}
; ARC optimizer shouldn't move the release call, which is a precise release call
; past the call to @alterRefCount.
; CHECK-LABEL: define void @test2(
; CHECK: call void @alterRefCount(
; CHECK: call void @llvm.objc.release(
define void @test2() {
%v0 = load ptr, ptr @g0, align 8
%v1 = tail call ptr @llvm.objc.retain(ptr %v0)
tail call void @use(ptr %v0)
tail call void @alterRefCount()
tail call void @llvm.objc.release(ptr %v0)
ret void
}
; Check that code motion is disabled in @test3 and @test4.
; Previously, ARC optimizer would move the release past the retain.
; if.then:
; call void @readOnlyFunc(ptr %obj, ptr null)
; call void @llvm.objc.release(ptr %obj) #1, !clang.imprecise_release !2
; %1 = add i32 1, 2
; %2 = tail call ptr @llvm.objc.retain(ptr %obj)
;
; Ideally, the retain/release pairs in BB if.then should be removed.
define void @test3(ptr %obj, i1 %cond) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: if.else:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ]])
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA:[0-9]+]]
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj)
br i1 %cond, label %if.then, label %if.else
if.then:
call void @readOnlyFunc(ptr %obj, ptr null) #0
add i32 1, 2
call void @alterRefCount()
br label %join
if.else:
call void @alterRefCount()
call void @use(ptr %obj)
br label %join
join:
call void @llvm.objc.release(ptr %obj), !clang.imprecise_release !9
ret void
}
define void @test4(ptr %obj0, ptr %obj1, i1 %cond) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ1:%.*]])
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ0]], ptr [[OBJ1]])
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: if.else:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ0]])
; CHECK-NEXT: call void @use(ptr [[OBJ1]])
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ0]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA]]
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ1]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA]]
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj0)
%v1 = call ptr @llvm.objc.retain(ptr %obj1)
br i1 %cond, label %if.then, label %if.else
if.then:
call void @readOnlyFunc(ptr %obj0, ptr %obj1) #0
add i32 1, 2
call void @alterRefCount()
br label %join
if.else:
call void @alterRefCount()
call void @use(ptr %obj0)
call void @use(ptr %obj1)
br label %join
join:
call void @llvm.objc.release(ptr %obj0), !clang.imprecise_release !9
call void @llvm.objc.release(ptr %obj1), !clang.imprecise_release !9
ret void
}
; In this test, insertion points for the retain and release calls that could be
; eliminated are in different blocks (bb1 and if.then).
define void @test5(ptr %obj, i1 %cond0, i1 %cond1) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])
; CHECK-NEXT: br i1 [[COND0:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]
; CHECK: if.then2:
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: if.else2:
; CHECK-NEXT: br label [[BB1]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: br label [[JOIN:%.*]]
; CHECK: if.else:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ]])
; CHECK-NEXT: br label [[JOIN]]
; CHECK: join:
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]])
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj)
br i1 %cond0, label %if.then, label %if.else
if.then:
call void @readOnlyFunc(ptr %obj, ptr null) #0
br i1 %cond1, label %if.then2, label %if.else2
if.then2:
br label %bb1
if.else2:
br label %bb1
bb1:
add i32 1, 2
call void @alterRefCount()
br label %join
if.else:
call void @alterRefCount()
call void @use(ptr %obj)
br label %join
join:
call void @llvm.objc.release(ptr %obj), !clang.imprecise_release !9
ret void
}
declare void @llvm.dbg.declare(metadata, metadata, metadata)
declare ptr @llvm.objc.retain(ptr) local_unnamed_addr
declare void @llvm.objc.release(ptr) local_unnamed_addr
attributes #0 = { readonly }
!llvm.module.flags = !{!0, !1}
; CHECK: ![[EMPTYMETA]] = !{}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !DILocalVariable(name: "i", arg: 1, scope: !3, file: !4, line: 1, type: !7)
!3 = distinct !DISubprogram(name: "test", scope: !4, file: !4, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !9)
!4 = !DIFile(filename: "test.m", directory: "dir")
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !7}
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!8 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !4, isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !9, nameTableKind: None)
!9 = !{}
!10 = !DILocation(line: 1, column: 14, scope: !3)
!11 = !DILocalVariable(name: "foo", scope: !3, type: !7)