1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4@.str = private unnamed_addr constant [4 x i8] c"str\00", align 1
5@.str.1 = private unnamed_addr constant [3 x i8] c"%%\00", align 1
6@.str.2 = private unnamed_addr constant [3 x i8] c"%c\00", align 1
7@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
8@.str.4 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
9
10
11declare i32 @snprintf(i8*, i64, i8*, ...) #1
12
13define void @test_not_const_fmt(i8* %buf, i8* %fmt) #0 {
14; CHECK-LABEL: @test_not_const_fmt(
15; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* noundef nonnull dereferenceable(1) [[BUF:%.*]], i64 32, i8* [[FMT:%.*]])
16; CHECK-NEXT:    ret void
17;
18  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* %fmt) #2
19  ret void
20}
21
22; size is '0', do not add nonnull attribute
23define void @test_not_const_fmt_zero_size_return_value(i8* %buf, i8* %fmt) #0 {
24; CHECK-LABEL: @test_not_const_fmt_zero_size_return_value(
25; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 0, i8* [[FMT:%.*]])
26; CHECK-NEXT:    ret void
27;
28  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* %fmt) #2
29  ret void
30}
31
32define void @test_not_const_size(i8* %buf, i64 %size) #0 {
33; CHECK-LABEL: @test_not_const_size(
34; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 [[SIZE:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))
35; CHECK-NEXT:    ret void
36;
37  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 %size, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
38  ret void
39}
40
41
42define i32 @test_return_value(i8* %buf) #0 {
43; CHECK-LABEL: @test_return_value(
44; CHECK-NEXT:    ret i32 3
45;
46  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
47  ret i32 %call
48}
49
50define void @test_percentage(i8* %buf) #0 {
51; CHECK-LABEL: @test_percentage(
52; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* noundef nonnull dereferenceable(1) [[BUF:%.*]], i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0))
53; CHECK-NEXT:    ret void
54;
55  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0)) #2
56  ret void
57}
58
59define i32 @test_null_buf_return_value() #0 {
60; CHECK-LABEL: @test_null_buf_return_value(
61; CHECK-NEXT:    ret i32 3
62;
63  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
64  ret i32 %call
65}
66
67define i32 @test_percentage_return_value() #0 {
68; CHECK-LABEL: @test_percentage_return_value(
69; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0))
70; CHECK-NEXT:    ret i32 [[CALL]]
71;
72  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0)) #3
73  ret i32 %call
74}
75
76
77define void @test_correct_copy(i8* %buf) #0 {
78; CHECK-LABEL: @test_correct_copy(
79; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[BUF:%.*]] to i32*
80; CHECK-NEXT:    store i32 7500915, i32* [[TMP1]], align 1
81; CHECK-NEXT:    ret void
82;
83  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
84  ret void
85}
86
87define i32 @test_char_zero_size(i8* %buf) #0 {
88; CHECK-LABEL: @test_char_zero_size(
89; CHECK-NEXT:    ret i32 1
90;
91  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
92  ret i32 %call
93}
94
95define i32 @test_char_wrong_size(i8* %buf) #0 {
96; CHECK-LABEL: @test_char_wrong_size(
97; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* noundef nonnull dereferenceable(1) [[BUF:%.*]], i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65)
98; CHECK-NEXT:    ret i32 [[CALL]]
99;
100  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
101  ret i32 %call
102}
103
104define i32 @test_char_ok_size(i8* %buf) #0 {
105; CHECK-LABEL: @test_char_ok_size(
106; CHECK-NEXT:    store i8 65, i8* [[BUF:%.*]], align 1
107; CHECK-NEXT:    [[NUL:%.*]] = getelementptr inbounds i8, i8* [[BUF]], i64 1
108; CHECK-NEXT:    store i8 0, i8* [[NUL]], align 1
109; CHECK-NEXT:    ret i32 1
110;
111  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0), i32 65) #2
112  ret i32 %call
113}
114
115define i32 @test_str_zero_size(i8* %buf) #0 {
116; CHECK-LABEL: @test_str_zero_size(
117; CHECK-NEXT:    ret i32 3
118;
119  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
120  ret i32 %call
121}
122
123define i32 @test_str_wrong_size(i8* %buf) #0 {
124; CHECK-LABEL: @test_str_wrong_size(
125; CHECK-NEXT:    [[CALL:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* noundef nonnull dereferenceable(1) [[BUF:%.*]], i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))
126; CHECK-NEXT:    ret i32 [[CALL]]
127;
128  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
129  ret i32 %call
130}
131
132define i32 @test_str_ok_size(i8* %buf) #0 {
133; CHECK-LABEL: @test_str_ok_size(
134; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[BUF:%.*]] to i32*
135; CHECK-NEXT:    store i32 7500915, i32* [[TMP1]], align 1
136; CHECK-NEXT:    ret i32 3
137;
138  %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2
139  ret i32 %call
140}
141
142; snprintf(buf, 32, "") -> memcpy -> store
143define i32 @test_str_ok_size_tail(i8* %buf) {
144; CHECK-LABEL: @test_str_ok_size_tail(
145; CHECK-NEXT:    store i8 0, i8* [[BUF:%.*]], align 1
146; CHECK-NEXT:    ret i32 0
147;
148  %1 = tail call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 8, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i64 0, i64 0))
149  ret i32 %1
150}
151
152define i32 @test_str_ok_size_musttail(i8* %buf, i64 %x, i8* %y, ...) {
153; CHECK-LABEL: @test_str_ok_size_musttail(
154; CHECK-NEXT:    [[TMP1:%.*]] = musttail call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 8, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i64 0, i64 0), ...)
155; CHECK-NEXT:    ret i32 [[TMP1]]
156;
157  %1 = musttail call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 8, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i64 0, i64 0), ...)
158  ret i32 %1
159}
160
161; snprintf(buf, 32, "%s", "str") -> memcpy -> store
162define i32 @test_str_ok_size_tail2(i8* %buf) {
163; CHECK-LABEL: @test_str_ok_size_tail2(
164; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[BUF:%.*]] to i32*
165; CHECK-NEXT:    store i32 7500915, i32* [[TMP1]], align 1
166; CHECK-NEXT:    ret i32 3
167;
168  %1 = tail call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0))
169  ret i32 %1
170}
171
172define i32 @test_str_ok_size_musttail2(i8* %buf, i64 %x, i8* %y, ...) {
173; CHECK-LABEL: @test_str_ok_size_musttail2(
174; CHECK-NEXT:    [[TMP1:%.*]] = musttail call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[BUF:%.*]], i64 8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), ...)
175; CHECK-NEXT:    ret i32 [[TMP1]]
176;
177  %1 = musttail call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), ...)
178  ret i32 %1
179}
180