[InstCombine] Signed saturation patterns
[llvm-core.git] / test / Transforms / InstCombine / unlocked-stdio.ll
blobf10772bc8029b32bf126103ab552235c0ff4bf08
1 ; 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
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 }
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
10 @stdout = external global %struct._IO_FILE*, align 8
11 @global_file = common global %struct._IO_FILE* null, align 8
13 define 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
18   %call = call i32 @fgetc(%struct._IO_FILE* %f)
19   ret void
22 declare i32 @fgetc(%struct._IO_FILE* nocapture) #0
24 define 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
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
35 declare %struct._IO_FILE* @fopen(i8*, i8*)
36 declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #0
38 define 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
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
49 define void @external_fgetc_internal_test() {
50 ; CHECK-LABEL: @external_fgetc_internal_test(
51 ; CHECK-NEXT:    call void @fgetc_test()
52 ; CHECK-NEXT:    ret void
54   call void @fgetc_test()
55   ret void
58 define 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
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
73 define 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
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
88 define 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
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
99 define 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
104 ; CHECK-NEXT:    [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]])
105 ; CHECK-NEXT:    ret void
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
114 define 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
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
125 define 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
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
144 declare i32 @fclose(%struct._IO_FILE* nocapture)
146 define 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
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
159 declare void @modify_file(%struct._IO_FILE*)
161 define 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
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
176 define 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
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
193 define 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
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
208 define 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
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
221 declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
222 declare i64 @fread(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture)
223 declare i32 @fputs(i8* nocapture readonly, %struct._IO_FILE* nocapture)
224 declare i8* @fgets(i8*, i32, %struct._IO_FILE* nocapture)