brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.1 KiB · 5cff5d6 Raw
337 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3; PR12014 5target datalayout = "p:32:32:32"6 7define i32 @main(i32 %argc, ptr %argv) {8; CHECK-LABEL: @main(9; CHECK-NEXT:    ret i32 010;11  %c_19 = alloca ptr12  %mul = mul i32 ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i32), 1013  %malloc_206 = tail call ptr @malloc(i32 %mul)14  store ptr %malloc_206, ptr %c_1915  %tmp_207 = load ptr, ptr %c_1916  tail call void @free(ptr %tmp_207)17  ret i32 018}19 20define i32 @dead_aligned_alloc(i32 %size, i32 %alignment, i8 %value) {21; CHECK-LABEL: @dead_aligned_alloc(22; CHECK-NEXT:    ret i32 023;24  %aligned_allocation = tail call ptr @aligned_alloc(i32 %alignment, i32 %size)25  store i8 %value, ptr %aligned_allocation26  tail call void @free(ptr %aligned_allocation)27  ret i32 028}29 30define i1 @aligned_alloc_only_pointe(i32 %size, i32 %alignment, i8 %value) {31; CHECK-LABEL: @aligned_alloc_only_pointe(32; CHECK-NEXT:    [[ALIGNED_ALLOCATION:%.*]] = tail call ptr @aligned_alloc(i32 [[ALIGNMENT:%.*]], i32 [[SIZE:%.*]])33; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null34; CHECK-NEXT:    ret i1 [[CMP]]35;36  %aligned_allocation = tail call ptr @aligned_alloc(i32 %alignment, i32 %size)37  %cmp = icmp ne ptr %aligned_allocation, null38  ret i1 %cmp39}40 41define i1 @aligned_alloc_pointer_only_used_by_cmp_alignment_and_value_known_ok(i32 %size, i32 %alignment, i8 %value) {42; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_alignment_and_value_known_ok(43; CHECK-NEXT:    ret i1 true44;45  %aligned_allocation = tail call ptr @aligned_alloc(i32 8, i32 32)46  %cmp = icmp ne ptr %aligned_allocation, null47  ret i1 %cmp48}49 50define i1 @aligned_alloc_pointer_only_used_by_cmp_alignment_no_power_of_2(i32 %size, i32 %alignment, i8 %value) {51; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_alignment_no_power_of_2(52; CHECK-NEXT:    [[ALIGNED_ALLOCATION:%.*]] = tail call dereferenceable_or_null(32) ptr @aligned_alloc(i32 3, i32 32)53; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null54; CHECK-NEXT:    ret i1 [[CMP]]55;56  %aligned_allocation = tail call ptr @aligned_alloc(i32 3, i32 32)57  %cmp = icmp ne ptr %aligned_allocation, null58  ret i1 %cmp59}60 61define i1 @aligned_alloc_pointer_only_used_by_cmp_size_not_multiple_of_alignment(i32 %size, i32 %alignment, i8 %value) {62; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_size_not_multiple_of_alignment(63; CHECK-NEXT:    [[ALIGNED_ALLOCATION:%.*]] = tail call dereferenceable_or_null(31) ptr @aligned_alloc(i32 8, i32 31)64; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null65; CHECK-NEXT:    ret i1 [[CMP]]66;67  %aligned_allocation = tail call ptr @aligned_alloc(i32 8, i32 31)68  %cmp = icmp ne ptr %aligned_allocation, null69  ret i1 %cmp70}71 72; This test uses a aligned allocation function different to @aligned_alloc,73; and should be treated as having @aligned_alloc's constraints on alignment74; and size operands.75define i1 @other_aligned_allocation_function(i32 %size, i32 %alignment, i8 %value) {76; CHECK-LABEL: @other_aligned_allocation_function(77; CHECK-NEXT:    ret i1 true78;79  %aligned_allocation = tail call ptr @other_aligned_alloc(i32 %alignment, i32 %size)80  %cmp = icmp ne ptr %aligned_allocation, null81  ret i1 %cmp82}83 84declare noalias ptr @calloc(i32, i32) nounwind allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc"85declare noalias ptr @malloc(i32) allockind("alloc,uninitialized") allocsize(0) "alloc-family"="malloc"86declare noalias ptr @aligned_alloc(i32, i32) allockind("alloc,uninitialized,aligned") allocsize(1) "alloc-family"="malloc"87declare noalias ptr @other_aligned_alloc(i32, i32) allockind("alloc,uninitialized,aligned") allocsize(1) "alloc-family"="malloc"88declare void @free(ptr) allockind("free") "alloc-family"="malloc"89 90define i1 @foo() {91; CHECK-LABEL: @foo(92; CHECK-NEXT:    ret i1 false93;94  %m = call ptr @malloc(i32 1)95  %z = icmp eq ptr %m, null96  call void @free(ptr %m)97  ret i1 %z98}99 100declare void @llvm.lifetime.start.p0(ptr)101declare void @llvm.lifetime.end.p0(ptr)102declare i64 @llvm.objectsize.i64(ptr, i1)103declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind104declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind105declare void @llvm.memset.p0.i32(ptr, i8, i32, i1) nounwind106 107define void @test3(ptr %src) {108; CHECK-LABEL: @test3(109; CHECK-NEXT:    ret void110;111  %a = call noalias ptr @malloc(i32 10)112  %size = call i64 @llvm.objectsize.i64(ptr %a, i1 true)113  store i8 42, ptr %a114  call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %src, i32 32, i1 false)115  call void @llvm.memmove.p0.p0.i32(ptr %a, ptr %src, i32 32, i1 false)116  call void @llvm.memset.p0.i32(ptr %a, i8 5, i32 32, i1 false)117  %alloc2 = call noalias ptr @calloc(i32 5, i32 7) nounwind118  %z = icmp ne ptr %alloc2, null119  ret void120}121 122;; This used to crash.123define void @test4() {124; CHECK-LABEL: @test4(125; CHECK-NEXT:    ret void126;127  %A = call ptr @malloc(i32 16000)128  call void @free(ptr %A)129  ret void130}131 132define void @test5(ptr %ptr, ptr %esc) {133; CHECK-LABEL: @test5(134; CHECK-NEXT:    [[C:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700)135; CHECK-NEXT:    [[D:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700)136; CHECK-NEXT:    [[E:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700)137; CHECK-NEXT:    [[F:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700)138; CHECK-NEXT:    [[G:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700)139; CHECK-NEXT:    store ptr [[C]], ptr [[ESC:%.*]], align 4140; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[D]], ptr [[PTR:%.*]], i32 32, i1 true)141; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i32(ptr [[E]], ptr [[PTR]], i32 32, i1 true)142; CHECK-NEXT:    call void @llvm.memset.p0.i32(ptr [[F]], i8 5, i32 32, i1 true)143; CHECK-NEXT:    store volatile i8 4, ptr [[G]], align 1144; CHECK-NEXT:    ret void145;146  %a = call ptr @malloc(i32 700)147  %b = call ptr @malloc(i32 700)148  %c = call ptr @malloc(i32 700)149  %d = call ptr @malloc(i32 700)150  %e = call ptr @malloc(i32 700)151  %f = call ptr @malloc(i32 700)152  %g = call ptr @malloc(i32 700)153  call void @llvm.memcpy.p0.p0.i32(ptr %ptr, ptr %a, i32 32, i1 false)154  call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %b, i32 32, i1 false)155  store ptr %c, ptr %esc156  call void @llvm.memcpy.p0.p0.i32(ptr %d, ptr %ptr, i32 32, i1 true)157  call void @llvm.memmove.p0.p0.i32(ptr %e, ptr %ptr, i32 32, i1 true)158  call void @llvm.memset.p0.i32(ptr %f, i8 5, i32 32, i1 true)159  store volatile i8 4, ptr %g160  ret void161}162 163;; When a basic block contains only a call to free and this block is accessed164;; through a test of the argument of free against null, move the call in the165;; predecessor block.166;; Using simplifycfg will remove the empty basic block and the branch operation167;; Then, performing a dead elimination will remove the comparison.168;; This is what happens with -O1 and upper.169define void @test6(ptr %foo) minsize {170; CHECK-LABEL: @test6(171; CHECK-NEXT:  entry:172; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[FOO:%.*]], null173; CHECK-NEXT:    tail call void @free(ptr [[FOO]])174; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]175; CHECK:       if.then:176; CHECK-NEXT:    br label [[IF_END]]177; CHECK:       if.end:178; CHECK-NEXT:    ret void179;180;; Call to free moved181;; Block is now empty and may be simplified by simplifycfg182entry:183  %tobool = icmp eq ptr %foo, null184  br i1 %tobool, label %if.end, label %if.then185 186if.then:                                          ; preds = %entry187  tail call void @free(ptr %foo)188  br label %if.end189 190if.end:                                           ; preds = %entry, %if.then191  ret void192}193 194;; Check that the optimization that moves a call to free in its predecessor195;; block (see test6) also happens when noop casts are involved.196define void @test12(ptr %foo) minsize {197; CHECK-LABEL: @test12(198; CHECK-NEXT:  entry:199; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[FOO:%.*]], null200; CHECK-NEXT:    tail call void @free(ptr [[FOO]])201; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]202; CHECK:       if.then:203; CHECK-NEXT:    br label [[IF_END]]204; CHECK:       if.end:205; CHECK-NEXT:    ret void206;207;; Everything before the call to free should have been moved as well.208;; Call to free moved209;; Block is now empty and may be simplified by simplifycfg210entry:211  %tobool = icmp eq ptr %foo, null212  br i1 %tobool, label %if.end, label %if.then213 214if.then:                                          ; preds = %entry215  tail call void @free(ptr %foo)216  br label %if.end217 218if.end:                                           ; preds = %entry, %if.then219  ret void220}221 222;; Test that nonnull-implying attributes on the parameter are adjusted when the223;; call is moved, since they may no longer be valid and result in miscompiles if224;; kept unchanged.225define void @test_nonnull_free_move(ptr %foo) minsize {226; CHECK-LABEL: @test_nonnull_free_move(227; CHECK-NEXT:  entry:228; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[FOO:%.*]], null229; CHECK-NEXT:    tail call void @free(ptr [[FOO]])230; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]231; CHECK:       if.then:232; CHECK-NEXT:    br label [[IF_END]]233; CHECK:       if.end:234; CHECK-NEXT:    ret void235;236entry:237  %tobool = icmp eq ptr %foo, null238  br i1 %tobool, label %if.end, label %if.then239 240if.then:                                          ; preds = %entry241  tail call void @free(ptr nonnull %foo)242  br label %if.end243 244if.end:                                           ; preds = %entry, %if.then245  ret void246}247 248define void @test_dereferenceable_free_move(ptr %foo) minsize {249; CHECK-LABEL: @test_dereferenceable_free_move(250; CHECK-NEXT:  entry:251; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[FOO:%.*]], null252; CHECK-NEXT:    tail call void @free(ptr dereferenceable_or_null(4) [[FOO]])253; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]254; CHECK:       if.then:255; CHECK-NEXT:    br label [[IF_END]]256; CHECK:       if.end:257; CHECK-NEXT:    ret void258;259entry:260  %tobool = icmp eq ptr %foo, null261  br i1 %tobool, label %if.end, label %if.then262 263if.then:                                          ; preds = %entry264  tail call void @free(ptr dereferenceable(4) %foo)265  br label %if.end266 267if.end:                                           ; preds = %entry, %if.then268  ret void269}270 271define void @test_nonnull_dereferenceable_free_move(ptr %foo) minsize {272; CHECK-LABEL: @test_nonnull_dereferenceable_free_move(273; CHECK-NEXT:  entry:274; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[FOO:%.*]], null275; CHECK-NEXT:    tail call void @free(ptr dereferenceable_or_null(16) [[FOO]])276; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]277; CHECK:       if.then:278; CHECK-NEXT:    br label [[IF_END]]279; CHECK:       if.end:280; CHECK-NEXT:    ret void281;282entry:283  %tobool = icmp eq ptr %foo, null284  br i1 %tobool, label %if.end, label %if.then285 286if.then:                                          ; preds = %entry287  tail call void @free(ptr nonnull dereferenceable(16) %foo)288  br label %if.end289 290if.end:                                           ; preds = %entry, %if.then291  ret void292}293 294; The next four tests cover the semantics of the nofree attributes.  These295; are thought to be legal transforms, but an implementation thereof has296; been reverted once due to difficult to isolate fallout.297 298; TODO: Freeing a no-free pointer -> %foo must be null299define void @test13(ptr nofree %foo) {300; CHECK-LABEL: @test13(301; CHECK-NEXT:    call void @free(ptr [[FOO:%.*]])302; CHECK-NEXT:    ret void303;304  call void @free(ptr %foo)305  ret void306}307 308; TODO: Freeing a no-free pointer -> %foo must be null309define void @test14(ptr %foo) nofree {310; CHECK-LABEL: @test14(311; CHECK-NEXT:    call void @free(ptr [[FOO:%.*]])312; CHECK-NEXT:    ret void313;314  call void @free(ptr %foo)315  ret void316}317 318; TODO: free call marked no-free ->  %foo must be null319define void @test15(ptr %foo) {320; CHECK-LABEL: @test15(321; CHECK-NEXT:    call void @free(ptr [[FOO:%.*]]) #[[ATTR8:[0-9]+]]322; CHECK-NEXT:    ret void323;324  call void @free(ptr %foo) nofree325  ret void326}327 328; TODO: freeing a nonnull nofree pointer -> full UB329define void @test16(ptr nonnull nofree %foo) {330; CHECK-LABEL: @test16(331; CHECK-NEXT:    call void @free(ptr [[FOO:%.*]])332; CHECK-NEXT:    ret void333;334  call void @free(ptr %foo)335  ret void336}337