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 10@stdout = external global %struct._IO_FILE*, align 8 11@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 104; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]]) 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 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 193define 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} 207 208define 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} 220 221declare 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) 225