1; RUN: opt < %s -instcombine -S | FileCheck %s 2; 3; Test that instcombine folds allocsize function calls properly. 4; Dummy arguments are inserted to verify that allocsize is picking the right 5; args, and to prove that arbitrary unfoldable values don't interfere with 6; allocsize if they're not used by allocsize. 7 8declare i8* @my_malloc(i8*, i32) allocsize(1) 9declare i8* @my_calloc(i8*, i8*, i32, i32) allocsize(2, 3) 10 11; CHECK-LABEL: define void @test_malloc 12define void @test_malloc(i8** %p, i64* %r) { 13 %1 = call i8* @my_malloc(i8* null, i32 100) 14 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed 15 16 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 17 ; CHECK: store i64 100 18 store i64 %2, i64* %r, align 8 19 ret void 20} 21 22; CHECK-LABEL: define void @test_calloc 23define void @test_calloc(i8** %p, i64* %r) { 24 %1 = call i8* @my_calloc(i8* null, i8* null, i32 100, i32 5) 25 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed 26 27 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 28 ; CHECK: store i64 500 29 store i64 %2, i64* %r, align 8 30 ret void 31} 32 33; Failure cases with non-constant values... 34; CHECK-LABEL: define void @test_malloc_fails 35define void @test_malloc_fails(i8** %p, i64* %r, i32 %n) { 36 %1 = call i8* @my_malloc(i8* null, i32 %n) 37 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed 38 39 ; CHECK: @llvm.objectsize.i64.p0i8 40 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 41 store i64 %2, i64* %r, align 8 42 ret void 43} 44 45; CHECK-LABEL: define void @test_calloc_fails 46define void @test_calloc_fails(i8** %p, i64* %r, i32 %n) { 47 %1 = call i8* @my_calloc(i8* null, i8* null, i32 %n, i32 5) 48 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed 49 50 ; CHECK: @llvm.objectsize.i64.p0i8 51 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 52 store i64 %2, i64* %r, align 8 53 54 55 %3 = call i8* @my_calloc(i8* null, i8* null, i32 100, i32 %n) 56 store i8* %3, i8** %p, align 8 ; To ensure objectsize isn't killed 57 58 ; CHECK: @llvm.objectsize.i64.p0i8 59 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %3, i1 false) 60 store i64 %4, i64* %r, align 8 61 ret void 62} 63 64declare i8* @my_malloc_outofline(i8*, i32) #0 65declare i8* @my_calloc_outofline(i8*, i8*, i32, i32) #1 66 67; Verifying that out of line allocsize is parsed correctly 68; CHECK-LABEL: define void @test_outofline 69define void @test_outofline(i8** %p, i64* %r) { 70 %1 = call i8* @my_malloc_outofline(i8* null, i32 100) 71 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed 72 73 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 74 ; CHECK: store i64 100 75 store i64 %2, i64* %r, align 8 76 77 78 %3 = call i8* @my_calloc_outofline(i8* null, i8* null, i32 100, i32 5) 79 store i8* %3, i8** %p, align 8 ; To ensure objectsize isn't killed 80 81 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %3, i1 false) 82 ; CHECK: store i64 500 83 store i64 %4, i64* %r, align 8 84 ret void 85} 86 87declare i8* @my_malloc_i64(i8*, i64) #0 88declare i8* @my_tiny_calloc(i8*, i8*, i8, i8) #1 89declare i8* @my_varied_calloc(i8*, i8*, i32, i8) #1 90 91; CHECK-LABEL: define void @test_overflow 92define void @test_overflow(i8** %p, i32* %r) { 93 %r64 = bitcast i32* %r to i64* 94 95 ; (2**31 + 1) * 2 > 2**31. So overflow. Yay. 96 %big_malloc = call i8* @my_calloc(i8* null, i8* null, i32 2147483649, i32 2) 97 store i8* %big_malloc, i8** %p, align 8 98 99 ; CHECK: @llvm.objectsize 100 %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_malloc, i1 false) 101 store i32 %1, i32* %r, align 4 102 103 104 %big_little_malloc = call i8* @my_tiny_calloc(i8* null, i8* null, i8 127, i8 4) 105 store i8* %big_little_malloc, i8** %p, align 8 106 107 ; CHECK: store i32 508 108 %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_little_malloc, i1 false) 109 store i32 %2, i32* %r, align 4 110 111 112 ; malloc(2**33) 113 %big_malloc_i64 = call i8* @my_malloc_i64(i8* null, i64 8589934592) 114 store i8* %big_malloc_i64, i8** %p, align 8 115 116 ; CHECK: @llvm.objectsize 117 %3 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_malloc_i64, i1 false) 118 store i32 %3, i32* %r, align 4 119 120 121 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %big_malloc_i64, i1 false) 122 ; CHECK: store i64 8589934592 123 store i64 %4, i64* %r64, align 8 124 125 126 ; Just intended to ensure that we properly handle args of different types... 127 %varied_calloc = call i8* @my_varied_calloc(i8* null, i8* null, i32 1000, i8 5) 128 store i8* %varied_calloc, i8** %p, align 8 129 130 ; CHECK: store i32 5000 131 %5 = call i32 @llvm.objectsize.i32.p0i8(i8* %varied_calloc, i1 false) 132 store i32 %5, i32* %r, align 4 133 134 ret void 135} 136 137; CHECK-LABEL: define void @test_nobuiltin 138; We had a bug where `nobuiltin` would cause `allocsize` to be ignored in 139; @llvm.objectsize calculations. 140define void @test_nobuiltin(i8** %p, i64* %r) { 141 %1 = call i8* @my_malloc(i8* null, i32 100) nobuiltin 142 store i8* %1, i8** %p, align 8 143 144 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false) 145 ; CHECK: store i64 100 146 store i64 %2, i64* %r, align 8 147 ret void 148} 149 150attributes #0 = { allocsize(1) } 151attributes #1 = { allocsize(2, 3) } 152 153declare i32 @llvm.objectsize.i32.p0i8(i8*, i1) 154declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) 155