brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · 896717f Raw
320 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 52; Test for autorelease pool optimizations3; RUN: opt -passes=objc-arc < %s -S | FileCheck %s4 5declare ptr @llvm.objc.autoreleasePoolPush()6declare void @llvm.objc.autoreleasePoolPop(ptr)7declare ptr @llvm.objc.autorelease(ptr)8declare ptr @llvm.objc.retain(ptr)9declare ptr @create_object()10declare void @use_object(ptr)11declare ptr @object_with_thing()12declare void @opaque_callee()13 14; Empty autorelease pool should be eliminated15define void @test_empty_pool() {16; CHECK-LABEL: define void @test_empty_pool() {17; CHECK-NEXT:    ret void18;19  %pool = call ptr @llvm.objc.autoreleasePoolPush()20  call void @llvm.objc.autoreleasePoolPop(ptr %pool)21  ret void22}23 24; Pool with only release should be removed25define void @test_autorelease_to_release() {26; CHECK-LABEL: define void @test_autorelease_to_release() {27; CHECK-NEXT:    [[OBJ:%.*]] = call ptr @create_object()28; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ]]) #[[ATTR0:[0-9]+]], !clang.imprecise_release [[META0:![0-9]+]]29; CHECK-NEXT:    ret void30;31  %obj = call ptr @create_object()32  %pool = call ptr @llvm.objc.autoreleasePoolPush()33  call ptr @llvm.objc.autorelease(ptr %obj)34  call void @llvm.objc.autoreleasePoolPop(ptr %pool)35  ret void36}37 38; Pool with autoreleases should not be optimized39define void @test_multiple_autoreleases() {40; CHECK-LABEL: define void @test_multiple_autoreleases() {41; CHECK-NEXT:    [[OBJ1:%.*]] = call ptr @create_object()42; CHECK-NEXT:    [[OBJ2:%.*]] = call ptr @create_object()43; CHECK-NEXT:    [[POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]44; CHECK-NEXT:    call void @use_object(ptr [[OBJ1]])45; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ1]]) #[[ATTR0]]46; CHECK-NEXT:    call void @use_object(ptr [[OBJ2]])47; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ2]]) #[[ATTR0]]48; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[POOL]]) #[[ATTR0]]49; CHECK-NEXT:    ret void50;51  %obj1 = call ptr @create_object()52  %obj2 = call ptr @create_object()53  %pool = call ptr @llvm.objc.autoreleasePoolPush()54  call void @use_object(ptr %obj1)55  call ptr @llvm.objc.autorelease(ptr %obj1)56  call void @use_object(ptr %obj2)57  call ptr @llvm.objc.autorelease(ptr %obj2)58  call void @llvm.objc.autoreleasePoolPop(ptr %pool)59  ret void60}61 62; Pool with calls should not be optimized63define void @test_calls() {64; CHECK-LABEL: define void @test_calls() {65; CHECK-NEXT:    [[POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]66; CHECK-NEXT:    [[OBJ1:%.*]] = call ptr @object_with_thing()67; CHECK-NEXT:    call void @use_object(ptr [[OBJ1]])68; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[POOL]]) #[[ATTR0]]69; CHECK-NEXT:    ret void70;71  %pool = call ptr @llvm.objc.autoreleasePoolPush()72  %obj1 = call ptr @object_with_thing()73  call void @use_object(ptr %obj1)74  call void @llvm.objc.autoreleasePoolPop(ptr %pool)75  ret void76}77 78; Pool with opaque call should not be optimized79define void @test_opaque_call() {80; CHECK-LABEL: define void @test_opaque_call() {81; CHECK-NEXT:    [[POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]82; CHECK-NEXT:    call void @opaque_callee()83; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[POOL]]) #[[ATTR0]]84; CHECK-NEXT:    ret void85;86  %pool = call ptr @llvm.objc.autoreleasePoolPush()87  call void @opaque_callee()88  call void @llvm.objc.autoreleasePoolPop(ptr %pool)89  ret void90}91 92; Nested empty pools should be eliminated93define void @test_nested_empty_pools() {94; CHECK-LABEL: define void @test_nested_empty_pools() {95; CHECK-NEXT:    ret void96;97  %pool1 = call ptr @llvm.objc.autoreleasePoolPush()98  %pool2 = call ptr @llvm.objc.autoreleasePoolPush()99  call void @llvm.objc.autoreleasePoolPop(ptr %pool2)100  call void @llvm.objc.autoreleasePoolPop(ptr %pool1)101  ret void102}103 104; Empty pool with cast should be eliminated105define void @test_empty_pool_with_cast() {106; CHECK-LABEL: define void @test_empty_pool_with_cast() {107; CHECK-NEXT:    [[CAST:%.*]] = bitcast ptr poison to ptr108; CHECK-NEXT:    ret void109;110  %pool = call ptr @llvm.objc.autoreleasePoolPush()111  %cast = bitcast ptr %pool to ptr112  call void @llvm.objc.autoreleasePoolPop(ptr %cast)113  ret void114}115 116; Autorelease shadowing - autorelease in inner pool doesn't prevent outer optimization117define void @test_autorelease_shadowing_basic() {118; CHECK-LABEL: define void @test_autorelease_shadowing_basic() {119; CHECK-NEXT:    [[OBJ:%.*]] = call ptr @create_object()120; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ]]) #[[ATTR0]], !clang.imprecise_release [[META0]]121; CHECK-NEXT:    ret void122;123  %obj = call ptr @create_object()124  %outer_pool = call ptr @llvm.objc.autoreleasePoolPush()125 126  ; Inner pool with autorelease - this should be shadowed127  %inner_pool = call ptr @llvm.objc.autoreleasePoolPush()128  call ptr @llvm.objc.autorelease(ptr %obj)129  call void @llvm.objc.autoreleasePoolPop(ptr %inner_pool)130 131  call void @llvm.objc.autoreleasePoolPop(ptr %outer_pool)132  ret void133}134 135; Multiple nested levels with shadowing136define void @test_multiple_nested_shadowing() {137; CHECK-LABEL: define void @test_multiple_nested_shadowing() {138; CHECK-NEXT:    [[OBJ1:%.*]] = call ptr @create_object()139; CHECK-NEXT:    [[OBJ2:%.*]] = call ptr @create_object()140; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]141; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]142; CHECK-NEXT:    ret void143;144  %obj1 = call ptr @create_object()145  %obj2 = call ptr @create_object()146  %outer_pool = call ptr @llvm.objc.autoreleasePoolPush()147 148  ; First inner pool149  %inner1_pool = call ptr @llvm.objc.autoreleasePoolPush()150  call ptr @llvm.objc.autorelease(ptr %obj1)151  call void @llvm.objc.autoreleasePoolPop(ptr %inner1_pool)152 153  ; Second inner pool with nested level154  %inner2_pool = call ptr @llvm.objc.autoreleasePoolPush()155  %inner3_pool = call ptr @llvm.objc.autoreleasePoolPush()156  call ptr @llvm.objc.autorelease(ptr %obj2)157  call void @llvm.objc.autoreleasePoolPop(ptr %inner3_pool)158  call void @llvm.objc.autoreleasePoolPop(ptr %inner2_pool)159 160  call void @llvm.objc.autoreleasePoolPop(ptr %outer_pool)161  ret void162}163 164; Autorelease outside inner pool prevents optimization165define void @test_autorelease_outside_inner_pool() {166; CHECK-LABEL: define void @test_autorelease_outside_inner_pool() {167; CHECK-NEXT:    [[OBJ1:%.*]] = call ptr @create_object()168; CHECK-NEXT:    [[OBJ2:%.*]] = call ptr @create_object()169; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]170; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]171; CHECK-NEXT:    ret void172;173  %obj1 = call ptr @create_object()174  %obj2 = call ptr @create_object()175  %outer_pool = call ptr @llvm.objc.autoreleasePoolPush()176 177  ; This autorelease is NOT in an inner pool, so outer pool can't be optimized178  call ptr @llvm.objc.autorelease(ptr %obj1)179 180  ; Inner pool with autorelease (shadowed)181  %inner_pool = call ptr @llvm.objc.autoreleasePoolPush()182  call ptr @llvm.objc.autorelease(ptr %obj2)183  call void @llvm.objc.autoreleasePoolPop(ptr %inner_pool)184 185  call void @llvm.objc.autoreleasePoolPop(ptr %outer_pool)186  ret void187}188 189; Known ObjC functions don't prevent optimization190define void @test_known_objc_functions() {191; CHECK-LABEL: define void @test_known_objc_functions() {192; CHECK-NEXT:    [[OBJ:%.*]] = call ptr @create_object()193; CHECK-NEXT:    ret void194;195  %obj = call ptr @create_object()196  %pool = call ptr @llvm.objc.autoreleasePoolPush()197 198  ; These are all known ObjC runtime functions that don't produce autoreleases199  %retained = call ptr @llvm.objc.retain(ptr %obj)200  call void @llvm.objc.release(ptr %obj)201 202  call void @llvm.objc.autoreleasePoolPop(ptr %pool)203  ret void204}205 206; Complex shadowing with mixed autoreleases207define void @test_complex_shadowing() {208; CHECK-LABEL: define void @test_complex_shadowing() {209; CHECK-NEXT:    [[OBJ1:%.*]] = call ptr @create_object()210; CHECK-NEXT:    [[OBJ2:%.*]] = call ptr @create_object()211; CHECK-NEXT:    [[OBJ3:%.*]] = call ptr @create_object()212; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]213; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]214; CHECK-NEXT:    [[INNER2_POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]215; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ3]]) #[[ATTR0]]216; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[INNER2_POOL]]) #[[ATTR0]]217; CHECK-NEXT:    ret void218;219  %obj1 = call ptr @create_object()220  %obj2 = call ptr @create_object()221  %obj3 = call ptr @create_object()222  %outer_pool = call ptr @llvm.objc.autoreleasePoolPush()223 224  ; This autorelease is outside inner pools - prevents optimization225  call ptr @llvm.objc.autorelease(ptr %obj1)226 227  ; Inner pool 1 with shadowed autorelease228  %inner1_pool = call ptr @llvm.objc.autoreleasePoolPush()229  call ptr @llvm.objc.autorelease(ptr %obj2)230  call void @llvm.objc.autoreleasePoolPop(ptr %inner1_pool)231 232  ; Some safe ObjC operations233  %retained = call ptr @llvm.objc.retain(ptr %obj3)234  call void @llvm.objc.release(ptr %retained)235 236  ; Inner pool 2 with shadowed autorelease237  %inner2_pool = call ptr @llvm.objc.autoreleasePoolPush()238  call ptr @llvm.objc.autorelease(ptr %obj3)239  call void @llvm.objc.autoreleasePoolPop(ptr %inner2_pool)240 241  call void @llvm.objc.autoreleasePoolPop(ptr %outer_pool)242  ret void243}244 245; Non-ObjC function that may autorelease prevents optimization246define void @test_non_objc_may_autorelease() {247; CHECK-LABEL: define void @test_non_objc_may_autorelease() {248; CHECK-NEXT:    [[POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]249; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @function_that_might_autorelease()250; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[POOL]]) #[[ATTR0]]251; CHECK-NEXT:    ret void252;253  %pool = call ptr @llvm.objc.autoreleasePoolPush()254  call ptr @function_that_might_autorelease()255  call void @llvm.objc.autoreleasePoolPop(ptr %pool)256  ret void257}258 259; Non-ObjC function that doesn't autorelease allows optimization260define void @test_non_objc_no_autorelease() {261; CHECK-LABEL: define void @test_non_objc_no_autorelease() {262; CHECK-NEXT:    call void @safe_function()263; CHECK-NEXT:    ret void264;265  %pool = call ptr @llvm.objc.autoreleasePoolPush()266  call void @safe_function()267  call void @llvm.objc.autoreleasePoolPop(ptr %pool)268  ret void269}270 271; Incomplete push/pop pairs across blocks - only inner pairs count272define void @test_incomplete_pairs_inner_shadowing() {273; CHECK-LABEL: define void @test_incomplete_pairs_inner_shadowing() {274; CHECK-NEXT:    [[OBJ:%.*]] = call ptr @create_object()275; CHECK-NEXT:    [[OUTER_POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]276; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ]]) #[[ATTR0]], !clang.imprecise_release [[META0]]277; CHECK-NEXT:    ret void278;279  %obj = call ptr @create_object()280  %outer_pool = call ptr @llvm.objc.autoreleasePoolPush()281 282  ; Inner complete pair - autorelease should be shadowed by this283  %inner_pool = call ptr @llvm.objc.autoreleasePoolPush()284  call ptr @llvm.objc.autorelease(ptr %obj)      ; This SHOULD be shadowed by inner pair285  call void @llvm.objc.autoreleasePoolPop(ptr %inner_pool)  ; Completes the inner pair286 287  ; Note: %outer_pool pop is in a different block (common pattern)288  ; But the autorelease was shadowed by the complete inner pair289  ret void290}291 292; Helper functions for testing interprocedural analysis293 294; Safe function that doesn't call autorelease295define void @safe_function() {296  ; Just some computation, no autoreleases297; CHECK-LABEL: define void @safe_function() {298; CHECK-NEXT:    [[X:%.*]] = add i32 1, 2299; CHECK-NEXT:    ret void300;301  %x = add i32 1, 2302  ret void303}304 305; Function that may produce autoreleases (simulated by calling autorelease)306define ptr @function_that_might_autorelease() {307; CHECK-LABEL: define ptr @function_that_might_autorelease() {308; CHECK-NEXT:    [[OBJ:%.*]] = call ptr @create_object()309; CHECK-NEXT:    [[AUTORELEASED:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ]]) #[[ATTR0]]310; CHECK-NEXT:    ret ptr [[AUTORELEASED]]311;312  %obj = call ptr @create_object()313  %autoreleased = call ptr @llvm.objc.autorelease(ptr %obj)314  ret ptr %autoreleased315}316 317;.318; CHECK: [[META0]] = !{}319;.320