| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -instcombine -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s |
| |
| %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] } |
| %struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 } |
| |
| @.str = private unnamed_addr constant [5 x i8] c"file\00", align 1 |
| @.str.1 = private unnamed_addr constant [2 x i8] c"w\00", align 1 |
| @.str.2 = private unnamed_addr constant [4 x i8] c"str\00", align 1 |
| @stdout = external global %struct._IO_FILE*, align 8 |
| @global_file = common global %struct._IO_FILE* null, align 8 |
| |
| define void @external_fgetc_test(%struct._IO_FILE* %f) { |
| ; CHECK-LABEL: @external_fgetc_test( |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @fgetc(%struct._IO_FILE* [[F:%.*]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %call = call i32 @fgetc(%struct._IO_FILE* %f) |
| ret void |
| } |
| |
| declare i32 @fgetc(%struct._IO_FILE* nocapture) #0 |
| |
| define void @external_fgetc_test2() { |
| ; CHECK-LABEL: @external_fgetc_test2( |
| ; 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)) |
| ; CHECK-NEXT: [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| declare %struct._IO_FILE* @fopen(i8*, i8*) |
| declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #0 |
| |
| define internal void @fgetc_test() { |
| ; CHECK-LABEL: @fgetc_test( |
| ; 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)) |
| ; CHECK-NEXT: [[FGETC_UNLOCKED:%.*]] = call i32 @fgetc_unlocked(%struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %call1 = call i32 @fgetc(%struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define void @external_fgetc_internal_test() { |
| ; CHECK-LABEL: @external_fgetc_internal_test( |
| ; CHECK-NEXT: call void @fgetc_test() |
| ; CHECK-NEXT: ret void |
| ; |
| call void @fgetc_test() |
| ret void |
| } |
| |
| define internal void @fwrite_test() { |
| ; CHECK-LABEL: @fwrite_test( |
| ; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1 |
| ; 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)) |
| ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %s = alloca [10 x i8], align 1 |
| %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)) |
| %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0 |
| %call1 = call i64 @fwrite(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define internal void @fread_test() { |
| ; CHECK-LABEL: @fread_test( |
| ; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1 |
| ; 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)) |
| ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fread_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %s = alloca [10 x i8], align 1 |
| %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)) |
| %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %s, i64 0, i64 0 |
| %call1 = call i64 @fread(i8* nonnull %arraydecay, i64 10, i64 10, %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define internal void @fputs_test() { |
| ; CHECK-LABEL: @fputs_test( |
| ; 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)) |
| ; 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]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %call1 = call i32 @fputs(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define internal void @fgets_test() { |
| ; CHECK-LABEL: @fgets_test( |
| ; CHECK-NEXT: [[BUF:%.*]] = alloca [10 x i8], align 1 |
| ; 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)) |
| ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[BUF]], i64 0, i64 0 |
| ; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %buf = alloca [10 x i8], align 1 |
| %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)) |
| %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0 |
| %call1 = call i8* @fgets(i8* nonnull %arraydecay, i32 10, %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define internal void @fputc_test() { |
| ; CHECK-LABEL: @fputc_test( |
| ; 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)) |
| ; CHECK-NEXT: [[FPUTC_UNLOCKED:%.*]] = call i32 @fputc_unlocked(i32 99, %struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %call1 = call i32 @fputc(i32 99, %struct._IO_FILE* %call) |
| ret void |
| } |
| |
| define i32 @main() { |
| ; CHECK-LABEL: @main( |
| ; CHECK-NEXT: call void @fwrite_test() |
| ; CHECK-NEXT: call void @fread_test() |
| ; CHECK-NEXT: call void @fputs_test() |
| ; CHECK-NEXT: call void @fgets_test() |
| ; CHECK-NEXT: call void @fputc_test() |
| ; CHECK-NEXT: call void @fgetc_test() |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| call void @fwrite_test() |
| call void @fread_test() |
| call void @fputs_test() |
| call void @fgets_test() |
| call void @fputc_test() |
| call void @fgetc_test() |
| ret i32 0 |
| } |
| |
| declare i32 @fclose(%struct._IO_FILE* nocapture) |
| |
| define void @test_with_fclose() { |
| ; CHECK-LABEL: @test_with_fclose( |
| ; 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)) |
| ; 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]]) |
| ; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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 |
| %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) |
| %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2 |
| ret void |
| } |
| |
| declare void @modify_file(%struct._IO_FILE*) |
| |
| define void @test_captured_by_function(){ |
| ; CHECK-LABEL: @test_captured_by_function( |
| ; 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)) |
| ; CHECK-NEXT: call void @modify_file(%struct._IO_FILE* [[CALL]]) |
| ; 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]]) |
| ; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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 |
| call void @modify_file(%struct._IO_FILE* %call) #2 |
| %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) |
| %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2 |
| ret void |
| } |
| |
| define void @test_captured_by_global_value() { |
| ; CHECK-LABEL: @test_captured_by_global_value( |
| ; 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)) |
| ; CHECK-NEXT: [[DOTCAST:%.*]] = ptrtoint %struct._IO_FILE* [[CALL]] to i64 |
| ; CHECK-NEXT: store i64 [[DOTCAST]], i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8 |
| ; 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]]) |
| ; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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 |
| %.cast = ptrtoint %struct._IO_FILE* %call to i64 |
| store i64 %.cast, i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8 |
| %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) |
| %call2 = call i32 @fclose(%struct._IO_FILE* %call) #2 |
| ret void |
| } |
| |
| define void @test_captured_by_standard_stream(i8* nocapture readonly %s) { |
| ; CHECK-LABEL: @test_captured_by_standard_stream( |
| ; 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)) |
| ; CHECK-NEXT: [[TMP:%.*]] = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8 |
| ; CHECK-NEXT: [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[TMP]]) |
| ; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[TMP]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %tmp = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8 |
| %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %tmp) |
| %call2 = tail call i32 @fclose(%struct._IO_FILE* %tmp) |
| ret void |
| } |
| |
| define void @test_captured_by_arg(i8* nocapture readonly %s, %struct._IO_FILE* nocapture %file) { |
| ; CHECK-LABEL: @test_captured_by_arg( |
| ; 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)) |
| ; CHECK-NEXT: [[CALL1:%.*]] = tail call i32 @fputs(i8* [[S:%.*]], %struct._IO_FILE* [[FILE:%.*]]) |
| ; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @fclose(%struct._IO_FILE* [[FILE]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %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)) |
| %call1 = tail call i32 @fputs(i8* %s, %struct._IO_FILE* %file) |
| %call2 = tail call i32 @fclose(%struct._IO_FILE* %file) |
| ret void |
| } |
| |
| declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture) |
| declare i64 @fread(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture) |
| declare i32 @fputs(i8* nocapture readonly, %struct._IO_FILE* nocapture) |
| declare i8* @fgets(i8*, i32, %struct._IO_FILE* nocapture) |