207 lines · plain
1; RUN: opt -passes=objc-arc -S < %s 2>&1 | FileCheck %s '--implicit-check-not=ignoring invalid debug'2 3declare void @alterRefCount()4declare void @use(ptr)5declare void @readOnlyFunc(ptr, ptr)6 7@g0 = global ptr null, align 88 9; Check that ARC optimizer doesn't reverse the order of the retain call and the10; release call when there are debug instructions.11 12; CHECK: call ptr @llvm.objc.retain(ptr %x)13; CHECK: call void @llvm.objc.release(ptr %x)14 15define i32 @test(ptr %x, ptr %y, i8 %z, i32 %i) {16 %i.addr = alloca i32, align 417 store i32 %i, ptr %i.addr, align 418 %v1 = tail call ptr @llvm.objc.retain(ptr %x)19 store i8 %z, ptr %x20 call void @llvm.dbg.declare(metadata ptr %i.addr, metadata !11, metadata !DIExpression()), !dbg !1021 call void @alterRefCount()22 tail call void @llvm.objc.release(ptr %x)23 ret i32 %i24}25 26; ARC optimizer shouldn't move the release call, which is a precise release call27; past the call to @alterRefCount.28 29; CHECK-LABEL: define void @test2(30; CHECK: call void @alterRefCount(31; CHECK: call void @llvm.objc.release(32 33define void @test2() {34 %v0 = load ptr, ptr @g0, align 835 %v1 = tail call ptr @llvm.objc.retain(ptr %v0)36 tail call void @use(ptr %v0)37 tail call void @alterRefCount()38 tail call void @llvm.objc.release(ptr %v0)39 ret void40}41 42; Check that code motion is disabled in @test3 and @test4.43; Previously, ARC optimizer would move the release past the retain.44 45; if.then:46; call void @readOnlyFunc(ptr %obj, ptr null)47; call void @llvm.objc.release(ptr %obj) #1, !clang.imprecise_release !248; %1 = add i32 1, 249; %2 = tail call ptr @llvm.objc.retain(ptr %obj)50;51; Ideally, the retain/release pairs in BB if.then should be removed.52 53define void @test3(ptr %obj, i1 %cond) {54; CHECK-LABEL: @test3(55; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])56; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]57; CHECK: if.then:58; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)59; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 260; CHECK-NEXT: call void @alterRefCount()61; CHECK-NEXT: br label [[JOIN:%.*]]62; CHECK: if.else:63; CHECK-NEXT: call void @alterRefCount()64; CHECK-NEXT: call void @use(ptr [[OBJ]])65; CHECK-NEXT: br label [[JOIN]]66; CHECK: join:67; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA:[0-9]+]]68; CHECK-NEXT: ret void69;70 %v0 = call ptr @llvm.objc.retain(ptr %obj)71 br i1 %cond, label %if.then, label %if.else72 73if.then:74 call void @readOnlyFunc(ptr %obj, ptr null) #075 add i32 1, 276 call void @alterRefCount()77 br label %join78 79if.else:80 call void @alterRefCount()81 call void @use(ptr %obj)82 br label %join83 84join:85 call void @llvm.objc.release(ptr %obj), !clang.imprecise_release !986 ret void87}88 89define void @test4(ptr %obj0, ptr %obj1, i1 %cond) {90; CHECK-LABEL: @test4(91; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ0:%.*]])92; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ1:%.*]])93; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]94; CHECK: if.then:95; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ0]], ptr [[OBJ1]])96; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 297; CHECK-NEXT: call void @alterRefCount()98; CHECK-NEXT: br label [[JOIN:%.*]]99; CHECK: if.else:100; CHECK-NEXT: call void @alterRefCount()101; CHECK-NEXT: call void @use(ptr [[OBJ0]])102; CHECK-NEXT: call void @use(ptr [[OBJ1]])103; CHECK-NEXT: br label [[JOIN]]104; CHECK: join:105; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ0]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA]]106; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ1]]) {{.*}}, !clang.imprecise_release ![[EMPTYMETA]]107; CHECK-NEXT: ret void108;109 %v0 = call ptr @llvm.objc.retain(ptr %obj0)110 %v1 = call ptr @llvm.objc.retain(ptr %obj1)111 br i1 %cond, label %if.then, label %if.else112 113if.then:114 call void @readOnlyFunc(ptr %obj0, ptr %obj1) #0115 add i32 1, 2116 call void @alterRefCount()117 br label %join118 119if.else:120 call void @alterRefCount()121 call void @use(ptr %obj0)122 call void @use(ptr %obj1)123 br label %join124 125join:126 call void @llvm.objc.release(ptr %obj0), !clang.imprecise_release !9127 call void @llvm.objc.release(ptr %obj1), !clang.imprecise_release !9128 ret void129}130 131; In this test, insertion points for the retain and release calls that could be132; eliminated are in different blocks (bb1 and if.then).133 134define void @test5(ptr %obj, i1 %cond0, i1 %cond1) {135; CHECK-LABEL: @test5(136; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])137; CHECK-NEXT: br i1 [[COND0:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]138; CHECK: if.then:139; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)140; CHECK-NEXT: br i1 [[COND1:%.*]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]141; CHECK: if.then2:142; CHECK-NEXT: br label [[BB1:%.*]]143; CHECK: if.else2:144; CHECK-NEXT: br label [[BB1]]145; CHECK: bb1:146; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2147; CHECK-NEXT: call void @alterRefCount()148; CHECK-NEXT: br label [[JOIN:%.*]]149; CHECK: if.else:150; CHECK-NEXT: call void @alterRefCount()151; CHECK-NEXT: call void @use(ptr [[OBJ]])152; CHECK-NEXT: br label [[JOIN]]153; CHECK: join:154; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]])155; CHECK-NEXT: ret void156;157 %v0 = call ptr @llvm.objc.retain(ptr %obj)158 br i1 %cond0, label %if.then, label %if.else159 160if.then:161 call void @readOnlyFunc(ptr %obj, ptr null) #0162 br i1 %cond1, label %if.then2, label %if.else2163 164if.then2:165 br label %bb1166 167if.else2:168 br label %bb1169 170bb1:171 add i32 1, 2172 call void @alterRefCount()173 br label %join174 175if.else:176 call void @alterRefCount()177 call void @use(ptr %obj)178 br label %join179 180join:181 call void @llvm.objc.release(ptr %obj), !clang.imprecise_release !9182 ret void183}184 185declare void @llvm.dbg.declare(metadata, metadata, metadata)186declare ptr @llvm.objc.retain(ptr) local_unnamed_addr187declare void @llvm.objc.release(ptr) local_unnamed_addr188 189attributes #0 = { readonly }190 191!llvm.module.flags = !{!0, !1}192 193; CHECK: ![[EMPTYMETA]] = !{}194 195!0 = !{i32 2, !"Dwarf Version", i32 4}196!1 = !{i32 2, !"Debug Info Version", i32 3}197!2 = !DILocalVariable(name: "i", arg: 1, scope: !3, file: !4, line: 1, type: !7)198!3 = distinct !DISubprogram(name: "test", scope: !4, file: !4, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !9)199!4 = !DIFile(filename: "test.m", directory: "dir")200!5 = !DISubroutineType(types: !6)201!6 = !{!7, !7}202!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)203!8 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !4, isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !9, nameTableKind: None)204!9 = !{}205!10 = !DILocation(line: 1, column: 14, scope: !3)206!11 = !DILocalVariable(name: "foo", scope: !3, type: !7)207