David Bolvansky | ca22d42 | 2018-05-16 11:39:52 +0000 | [diff] [blame] | 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 |
| 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 Bolvansky | cd3eb99 | 2018-05-23 03:01:45 +0000 | [diff] [blame] | 10 | @stdout = external global %struct._IO_FILE*, align 8 |
David Bolvansky | ca22d42 | 2018-05-16 11:39:52 +0000 | [diff] [blame] | 11 | @global_file = common global %struct._IO_FILE* null, align 8 |
| 12 | |
| 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 |
| 17 | ; |
| 18 | %call = call i32 @fgetc(%struct._IO_FILE* %f) |
| 19 | ret void |
| 20 | } |
| 21 | |
| 22 | declare i32 @fgetc(%struct._IO_FILE* nocapture) #0 |
| 23 | |
| 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 |
| 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 | |
| 35 | declare %struct._IO_FILE* @fopen(i8*, i8*) |
| 36 | declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #0 |
| 37 | |
| 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 |
| 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 | |
| 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 |
| 53 | ; |
| 54 | call void @fgetc_test() |
| 55 | ret void |
| 56 | } |
| 57 | |
| 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 |
| 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 | |
| 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 |
| 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 | |
| 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 |
| 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 | |
| 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 |
Benjamin Kramer | 8ac15bf | 2018-05-16 21:45:39 +0000 | [diff] [blame] | 104 | ; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]]) |
David Bolvansky | ca22d42 | 2018-05-16 11:39:52 +0000 | [diff] [blame] | 105 | ; 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 | |
| 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 |
| 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 | |
| 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 |
| 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 | |
| 144 | declare i32 @fclose(%struct._IO_FILE* nocapture) |
| 145 | |
| 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 |
| 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 | |
| 159 | declare void @modify_file(%struct._IO_FILE*) |
| 160 | |
| 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 |
| 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 | |
| 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 |
| 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 Bolvansky | cd3eb99 | 2018-05-23 03:01:45 +0000 | [diff] [blame] | 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 |
| 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 Bolvansky | ca22d42 | 2018-05-16 11:39:52 +0000 | [diff] [blame] | 207 | |
David Bolvansky | cd3eb99 | 2018-05-23 03:01:45 +0000 | [diff] [blame] | 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 |
| 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 Bolvansky | ca22d42 | 2018-05-16 11:39:52 +0000 | [diff] [blame] | 220 | |
David Bolvansky | cd3eb99 | 2018-05-23 03:01:45 +0000 | [diff] [blame] | 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) |