blob: f10772bc8029b32bf126103ab552235c0ff4bf08 [file] [log] [blame]
David Bolvanskyca22d422018-05-16 11:39:52 +00001; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
3
4%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
5%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
6
7@.str = private unnamed_addr constant [5 x i8] c"file\00", align 1
8@.str.1 = private unnamed_addr constant [2 x i8] c"w\00", align 1
9@.str.2 = private unnamed_addr constant [4 x i8] c"str\00", align 1
David Bolvanskycd3eb992018-05-23 03:01:45 +000010@stdout = external global %struct._IO_FILE*, align 8
David Bolvanskyca22d422018-05-16 11:39:52 +000011@global_file = common global %struct._IO_FILE* null, align 8
12
13define void @external_fgetc_test(%struct._IO_FILE* %f) {
14; CHECK-LABEL: @external_fgetc_test(
15; CHECK-NEXT: [[CALL:%.*]] = call i32 @fgetc(%struct._IO_FILE* [[F:%.*]])
16; CHECK-NEXT: ret void
17;
18 %call = call i32 @fgetc(%struct._IO_FILE* %f)
19 ret void
20}
21
22declare i32 @fgetc(%struct._IO_FILE* nocapture) #0
23
24define void @external_fgetc_test2() {
25; CHECK-LABEL: @external_fgetc_test2(
26; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
27; CHECK-NEXT: [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]])
28; CHECK-NEXT: ret void
29;
30 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
31 %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call)
32 ret void
33}
34
35declare %struct._IO_FILE* @fopen(i8*, i8*)
36declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #0
37
38define internal void @fgetc_test() {
39; CHECK-LABEL: @fgetc_test(
40; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
41; CHECK-NEXT: [[FGETC_UNLOCKED:%.*]] = call i32 @fgetc_unlocked(%struct._IO_FILE* [[CALL]])
42; CHECK-NEXT: ret void
43;
44 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
45 %call1 = call i32 @fgetc(%struct._IO_FILE* %call)
46 ret void
47}
48
49define void @external_fgetc_internal_test() {
50; CHECK-LABEL: @external_fgetc_internal_test(
51; CHECK-NEXT: call void @fgetc_test()
52; CHECK-NEXT: ret void
53;
54 call void @fgetc_test()
55 ret void
56}
57
58define internal void @fwrite_test() {
59; CHECK-LABEL: @fwrite_test(
60; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1
61; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
62; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0
63; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]])
64; CHECK-NEXT: ret void
65;
66 %s = alloca [10 x i8], align 1
67 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
68 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0
69 %call1 = call i64 @fwrite(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call)
70 ret void
71}
72
73define internal void @fread_test() {
74; CHECK-LABEL: @fread_test(
75; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1
76; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
77; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0
78; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fread_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]])
79; CHECK-NEXT: ret void
80;
81 %s = alloca [10 x i8], align 1
82 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
83 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0
84 %call1 = call i64 @fread(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call)
85 ret void
86}
87
88define internal void @fputs_test() {
89; CHECK-LABEL: @fputs_test(
90; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
91; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
92; CHECK-NEXT: ret void
93;
94 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
95 %call1 = call i32 @fputs(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), %struct._IO_FILE* %call)
96 ret void
97}
98
99define internal void @fgets_test() {
100; CHECK-LABEL: @fgets_test(
101; CHECK-NEXT: [[BUF:%.*]] = alloca [10 x i8], align 1
102; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
103; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[BUF]], i64 0, i64 0
Benjamin Kramer8ac15bf2018-05-16 21:45:39 +0000104; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]])
David Bolvanskyca22d422018-05-16 11:39:52 +0000105; CHECK-NEXT: ret void
106;
107 %buf = alloca [10 x i8], align 1
108 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
109 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0
110 %call1 = call i8* @fgets(i8* nonnull %arraydecay, i32 10, %struct._IO_FILE* %call)
111 ret void
112}
113
114define internal void @fputc_test() {
115; CHECK-LABEL: @fputc_test(
116; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
117; CHECK-NEXT: [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]])
118; CHECK-NEXT: ret void
119;
120 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
121 %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call)
122 ret void
123}
124
125define i32 @main() {
126; CHECK-LABEL: @main(
127; CHECK-NEXT: call void @fwrite_test()
128; CHECK-NEXT: call void @fread_test()
129; CHECK-NEXT: call void @fputs_test()
130; CHECK-NEXT: call void @fgets_test()
131; CHECK-NEXT: call void @fputc_test()
132; CHECK-NEXT: call void @fgetc_test()
133; CHECK-NEXT: ret i32 0
134;
135 call void @fwrite_test()
136 call void @fread_test()
137 call void @fputs_test()
138 call void @fgets_test()
139 call void @fputc_test()
140 call void @fgetc_test()
141 ret i32 0
142}
143
144declare i32 @fclose(%struct._IO_FILE* nocapture)
145
146define void @test_with_fclose() {
147; CHECK-LABEL: @test_with_fclose(
148; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
149; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
150; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
151; CHECK-NEXT: ret void
152;
153 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
154 %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
155 %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
156 ret void
157}
158
159declare void @modify_file(%struct._IO_FILE*)
160
161define void @test_captured_by_function(){
162; CHECK-LABEL: @test_captured_by_function(
163; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
164; CHECK-NEXT: call void @modify_file(%struct._IO_FILE* [[CALL]])
165; CHECK-NEXT: [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
166; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
167; CHECK-NEXT: ret void
168;
169 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
170 call void @modify_file(%struct._IO_FILE* %call) #2
171 %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
172 %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
173 ret void
174}
175
176define void @test_captured_by_global_value() {
177; CHECK-LABEL: @test_captured_by_global_value(
178; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
179; CHECK-NEXT: [[DOTCAST:%.*]] = ptrtoint %struct._IO_FILE* [[CALL]] to i64
180; CHECK-NEXT: store i64 [[DOTCAST]], i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8
181; CHECK-NEXT: [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]])
182; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]])
183; CHECK-NEXT: ret void
184;
185 %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2
186 %.cast = ptrtoint %struct._IO_FILE* %call to i64
187 store i64 %.cast, i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8
188 %call1 = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* %call)
189 %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2
190 ret void
191}
192
David Bolvanskycd3eb992018-05-23 03:01:45 +0000193define void @test_captured_by_standard_stream(i8* nocapture readonly %s) {
194; CHECK-LABEL: @test_captured_by_standard_stream(
195; CHECK-NEXT: [[CALL:%.*]] = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
196; CHECK-NEXT: [[TMP:%.*]] = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
197; CHECK-NEXT: [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[TMP]])
198; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[TMP]])
199; CHECK-NEXT: ret void
200;
201 %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
202 %tmp = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
203 %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %tmp)
204 %call2 = tail call i32 @fclose(%struct._IO_FILE* %tmp)
205 ret void
206}
David Bolvanskyca22d422018-05-16 11:39:52 +0000207
David Bolvanskycd3eb992018-05-23 03:01:45 +0000208define void @test_captured_by_arg(i8* nocapture readonly %s, %struct._IO_FILE* nocapture %file) {
209; CHECK-LABEL: @test_captured_by_arg(
210; CHECK-NEXT: [[CALL:%.*]] = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
211; CHECK-NEXT: [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[FILE:%.*]])
212; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[FILE]])
213; CHECK-NEXT: ret void
214;
215 %call = tail call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0))
216 %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %file)
217 %call2 = tail call i32 @fclose(%struct._IO_FILE* %file)
218 ret void
219}
David Bolvanskyca22d422018-05-16 11:39:52 +0000220
David Bolvanskycd3eb992018-05-23 03:01:45 +0000221declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
222declare i64 @fread(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
223declare i32 @fputs(i8* nocapture readonly, %struct._IO_FILE* nocapture)
224declare i8* @fgets(i8*, i32, %struct._IO_FILE* nocapture)