1
+ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
1
2
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
2
3
;
3
4
; Test that instcombine folds allocsize function calls properly.
8
9
declare ptr @my_malloc (ptr , i32 ) allocsize(1 )
9
10
declare ptr @my_calloc (ptr , ptr , i32 , i32 ) allocsize(2 , 3 )
10
11
11
- ; CHECK-LABEL: define void @test_malloc
12
12
define void @test_malloc (ptr %p , ptr %r ) {
13
+ ; CHECK-LABEL: define void @test_malloc(
14
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]]) {
15
+ ; CHECK-NEXT: [[TMP1:%.*]] = call dereferenceable_or_null(100) ptr @my_malloc(ptr null, i32 100)
16
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
17
+ ; CHECK-NEXT: store i64 100, ptr [[R]], align 8
18
+ ; CHECK-NEXT: ret void
19
+ ;
13
20
%1 = call ptr @my_malloc (ptr null , i32 100 )
14
21
store ptr %1 , ptr %p , align 8 ; To ensure objectsize isn't killed
15
22
16
23
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
17
- ; CHECK: store i64 100
18
24
store i64 %2 , ptr %r , align 8
19
25
ret void
20
26
}
21
27
22
- ; CHECK-LABEL: define void @test_calloc
23
28
define void @test_calloc (ptr %p , ptr %r ) {
29
+ ; CHECK-LABEL: define void @test_calloc(
30
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]]) {
31
+ ; CHECK-NEXT: [[TMP1:%.*]] = call dereferenceable_or_null(500) ptr @my_calloc(ptr null, ptr null, i32 100, i32 5)
32
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
33
+ ; CHECK-NEXT: store i64 500, ptr [[R]], align 8
34
+ ; CHECK-NEXT: ret void
35
+ ;
24
36
%1 = call ptr @my_calloc (ptr null , ptr null , i32 100 , i32 5 )
25
37
store ptr %1 , ptr %p , align 8 ; To ensure objectsize isn't killed
26
38
27
39
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
28
- ; CHECK: store i64 500
29
40
store i64 %2 , ptr %r , align 8
30
41
ret void
31
42
}
32
43
33
44
; Failure cases with non-constant values...
34
- ; CHECK-LABEL: define void @test_malloc_fails
35
45
define void @test_malloc_fails (ptr %p , ptr %r , i32 %n ) {
46
+ ; CHECK-LABEL: define void @test_malloc_fails(
47
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {
48
+ ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @my_malloc(ptr null, i32 [[N]])
49
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
50
+ ; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[TMP1]], i1 false, i1 false, i1 false)
51
+ ; CHECK-NEXT: store i64 [[TMP2]], ptr [[R]], align 8
52
+ ; CHECK-NEXT: ret void
53
+ ;
36
54
%1 = call ptr @my_malloc (ptr null , i32 %n )
37
55
store ptr %1 , ptr %p , align 8 ; To ensure objectsize isn't killed
38
56
39
- ; CHECK: @llvm.objectsize.i64.p0
40
57
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
41
58
store i64 %2 , ptr %r , align 8
42
59
ret void
43
60
}
44
61
45
- ; CHECK-LABEL: define void @test_calloc_fails
46
62
define void @test_calloc_fails (ptr %p , ptr %r , i32 %n ) {
63
+ ; CHECK-LABEL: define void @test_calloc_fails(
64
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {
65
+ ; CHECK-NEXT: [[TMP1:%.*]] = call ptr @my_calloc(ptr null, ptr null, i32 [[N]], i32 5)
66
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
67
+ ; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[TMP1]], i1 false, i1 false, i1 false)
68
+ ; CHECK-NEXT: store i64 [[TMP2]], ptr [[R]], align 8
69
+ ; CHECK-NEXT: [[TMP3:%.*]] = call ptr @my_calloc(ptr null, ptr null, i32 100, i32 [[N]])
70
+ ; CHECK-NEXT: store ptr [[TMP3]], ptr [[P]], align 8
71
+ ; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[TMP3]], i1 false, i1 false, i1 false)
72
+ ; CHECK-NEXT: store i64 [[TMP4]], ptr [[R]], align 8
73
+ ; CHECK-NEXT: ret void
74
+ ;
47
75
%1 = call ptr @my_calloc (ptr null , ptr null , i32 %n , i32 5 )
48
76
store ptr %1 , ptr %p , align 8 ; To ensure objectsize isn't killed
49
77
50
- ; CHECK: @llvm.objectsize.i64.p0
51
78
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
52
79
store i64 %2 , ptr %r , align 8
53
80
54
81
55
82
%3 = call ptr @my_calloc (ptr null , ptr null , i32 100 , i32 %n )
56
83
store ptr %3 , ptr %p , align 8 ; To ensure objectsize isn't killed
57
84
58
- ; CHECK: @llvm.objectsize.i64.p0
59
85
%4 = call i64 @llvm.objectsize.i64.p0 (ptr %3 , i1 false )
60
86
store i64 %4 , ptr %r , align 8
61
87
ret void
@@ -65,21 +91,28 @@ declare ptr @my_malloc_outofline(ptr, i32) #0
65
91
declare ptr @my_calloc_outofline (ptr , ptr , i32 , i32 ) #1
66
92
67
93
; Verifying that out of line allocsize is parsed correctly
68
- ; CHECK-LABEL: define void @test_outofline
69
94
define void @test_outofline (ptr %p , ptr %r ) {
95
+ ; CHECK-LABEL: define void @test_outofline(
96
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]]) {
97
+ ; CHECK-NEXT: [[TMP1:%.*]] = call dereferenceable_or_null(100) ptr @my_malloc_outofline(ptr null, i32 100)
98
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
99
+ ; CHECK-NEXT: store i64 100, ptr [[R]], align 8
100
+ ; CHECK-NEXT: [[TMP2:%.*]] = call dereferenceable_or_null(500) ptr @my_calloc_outofline(ptr null, ptr null, i32 100, i32 5)
101
+ ; CHECK-NEXT: store ptr [[TMP2]], ptr [[P]], align 8
102
+ ; CHECK-NEXT: store i64 500, ptr [[R]], align 8
103
+ ; CHECK-NEXT: ret void
104
+ ;
70
105
%1 = call ptr @my_malloc_outofline (ptr null , i32 100 )
71
106
store ptr %1 , ptr %p , align 8 ; To ensure objectsize isn't killed
72
107
73
108
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
74
- ; CHECK: store i64 100
75
109
store i64 %2 , ptr %r , align 8
76
110
77
111
78
112
%3 = call ptr @my_calloc_outofline (ptr null , ptr null , i32 100 , i32 5 )
79
113
store ptr %3 , ptr %p , align 8 ; To ensure objectsize isn't killed
80
114
81
115
%4 = call i64 @llvm.objectsize.i64.p0 (ptr %3 , i1 false )
82
- ; CHECK: store i64 500
83
116
store i64 %4 , ptr %r , align 8
84
117
ret void
85
118
}
@@ -88,22 +121,37 @@ declare ptr @my_malloc_i64(ptr, i64) #0
88
121
declare ptr @my_tiny_calloc (ptr , ptr , i8 , i8 ) #1
89
122
declare ptr @my_varied_calloc (ptr , ptr , i32 , i8 ) #1
90
123
91
- ; CHECK-LABEL: define void @test_overflow
92
124
define void @test_overflow (ptr %p , ptr %r ) {
93
-
94
125
; (2**31 + 1) * 2 > 2**31. So overflow. Yay.
126
+ ; CHECK-LABEL: define void @test_overflow(
127
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]]) {
128
+ ; CHECK-NEXT: [[BIG_MALLOC:%.*]] = call dereferenceable_or_null(4294967298) ptr @my_calloc(ptr null, ptr null, i32 -2147483647, i32 2)
129
+ ; CHECK-NEXT: store ptr [[BIG_MALLOC]], ptr [[P]], align 8
130
+ ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.objectsize.i32.p0(ptr [[BIG_MALLOC]], i1 false, i1 false, i1 false)
131
+ ; CHECK-NEXT: store i32 [[TMP1]], ptr [[R]], align 4
132
+ ; CHECK-NEXT: [[BIG_LITTLE_MALLOC:%.*]] = call dereferenceable_or_null(508) ptr @my_tiny_calloc(ptr null, ptr null, i8 127, i8 4)
133
+ ; CHECK-NEXT: store ptr [[BIG_LITTLE_MALLOC]], ptr [[P]], align 8
134
+ ; CHECK-NEXT: store i32 508, ptr [[R]], align 4
135
+ ; CHECK-NEXT: [[BIG_MALLOC_I64:%.*]] = call dereferenceable_or_null(8589934592) ptr @my_malloc_i64(ptr null, i64 8589934592)
136
+ ; CHECK-NEXT: store ptr [[BIG_MALLOC_I64]], ptr [[P]], align 8
137
+ ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.objectsize.i32.p0(ptr [[BIG_MALLOC_I64]], i1 false, i1 false, i1 false)
138
+ ; CHECK-NEXT: store i32 [[TMP2]], ptr [[R]], align 4
139
+ ; CHECK-NEXT: store i64 8589934592, ptr [[R]], align 8
140
+ ; CHECK-NEXT: [[VARIED_CALLOC:%.*]] = call dereferenceable_or_null(5000) ptr @my_varied_calloc(ptr null, ptr null, i32 1000, i8 5)
141
+ ; CHECK-NEXT: store ptr [[VARIED_CALLOC]], ptr [[P]], align 8
142
+ ; CHECK-NEXT: store i32 5000, ptr [[R]], align 4
143
+ ; CHECK-NEXT: ret void
144
+ ;
95
145
%big_malloc = call ptr @my_calloc (ptr null , ptr null , i32 2147483649 , i32 2 )
96
146
store ptr %big_malloc , ptr %p , align 8
97
147
98
- ; CHECK: @llvm.objectsize
99
148
%1 = call i32 @llvm.objectsize.i32.p0 (ptr %big_malloc , i1 false )
100
149
store i32 %1 , ptr %r , align 4
101
150
102
151
103
152
%big_little_malloc = call ptr @my_tiny_calloc (ptr null , ptr null , i8 127 , i8 4 )
104
153
store ptr %big_little_malloc , ptr %p , align 8
105
154
106
- ; CHECK: store i32 508
107
155
%2 = call i32 @llvm.objectsize.i32.p0 (ptr %big_little_malloc , i1 false )
108
156
store i32 %2 , ptr %r , align 4
109
157
@@ -112,36 +160,38 @@ define void @test_overflow(ptr %p, ptr %r) {
112
160
%big_malloc_i64 = call ptr @my_malloc_i64 (ptr null , i64 8589934592 )
113
161
store ptr %big_malloc_i64 , ptr %p , align 8
114
162
115
- ; CHECK: @llvm.objectsize
116
163
%3 = call i32 @llvm.objectsize.i32.p0 (ptr %big_malloc_i64 , i1 false )
117
164
store i32 %3 , ptr %r , align 4
118
165
119
166
120
167
%4 = call i64 @llvm.objectsize.i64.p0 (ptr %big_malloc_i64 , i1 false )
121
- ; CHECK: store i64 8589934592
122
168
store i64 %4 , ptr %r , align 8
123
169
124
170
125
171
; Just intended to ensure that we properly handle args of different types...
126
172
%varied_calloc = call ptr @my_varied_calloc (ptr null , ptr null , i32 1000 , i8 5 )
127
173
store ptr %varied_calloc , ptr %p , align 8
128
174
129
- ; CHECK: store i32 5000
130
175
%5 = call i32 @llvm.objectsize.i32.p0 (ptr %varied_calloc , i1 false )
131
176
store i32 %5 , ptr %r , align 4
132
177
133
178
ret void
134
179
}
135
180
136
- ; CHECK-LABEL: define void @test_nobuiltin
137
181
; We had a bug where `nobuiltin` would cause `allocsize` to be ignored in
138
182
; @llvm.objectsize calculations.
139
183
define void @test_nobuiltin (ptr %p , ptr %r ) {
184
+ ; CHECK-LABEL: define void @test_nobuiltin(
185
+ ; CHECK-SAME: ptr [[P:%.*]], ptr [[R:%.*]]) {
186
+ ; CHECK-NEXT: [[TMP1:%.*]] = call dereferenceable_or_null(100) ptr @my_malloc(ptr null, i32 100) #[[ATTR3:[0-9]+]]
187
+ ; CHECK-NEXT: store ptr [[TMP1]], ptr [[P]], align 8
188
+ ; CHECK-NEXT: store i64 100, ptr [[R]], align 8
189
+ ; CHECK-NEXT: ret void
190
+ ;
140
191
%1 = call ptr @my_malloc (ptr null , i32 100 ) nobuiltin
141
192
store ptr %1 , ptr %p , align 8
142
193
143
194
%2 = call i64 @llvm.objectsize.i64.p0 (ptr %1 , i1 false )
144
- ; CHECK: store i64 100
145
195
store i64 %2 , ptr %r , align 8
146
196
ret void
147
197
}
0 commit comments