xref: /llvm-project/llvm/test/Transforms/InstCombine/snprintf-2.ll (revision 462cb3cd6cecd0511ecaf0e3ebcaba455ece587d)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2;
3; Verify that snprintf calls with a constant size not exceeding INT_MAX
4; and constant format string with no formatting directives are transformed
5; into memcpy.  Also verify that a size in excess of INT_MAX prevents
6; the transformation.
7;
8; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s -check-prefixes=ANY,BE
9; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s -check-prefixes=ANY,LE
10
11@s = constant [4 x i8] c"123\00"
12
13@adst = external global [0 x ptr]
14@asiz = external global [0 x i32]
15
16declare i32 @snprintf(ptr, i64, ptr, ...)
17
18
19; Verify that all snprintf calls with a bound between INT_MAX and down
20; to 0 are transformed to memcpy.
21
22define void @fold_snprintf_fmt() {
23; BE-LABEL: @fold_snprintf_fmt(
24; BE-NEXT:    [[PDIMAX:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 17179869176), align 8
25; BE-NEXT:    store i32 825373440, ptr [[PDIMAX]], align 1
26; BE-NEXT:    store i32 3, ptr @asiz, align 4
27; BE-NEXT:    [[PD5:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 40), align 8
28; BE-NEXT:    store i32 825373440, ptr [[PD5]], align 1
29; BE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 20), align 4
30; BE-NEXT:    [[PD4:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 32), align 8
31; BE-NEXT:    store i32 825373440, ptr [[PD4]], align 1
32; BE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 16), align 4
33; BE-NEXT:    [[PD3:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 24), align 8
34; BE-NEXT:    store i16 12594, ptr [[PD3]], align 1
35; BE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[PD3]], i64 2
36; BE-NEXT:    store i8 0, ptr [[ENDPTR]], align 1
37; BE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 12), align 4
38; BE-NEXT:    [[PD2:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 16), align 8
39; BE-NEXT:    store i8 49, ptr [[PD2]], align 1
40; BE-NEXT:    [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[PD2]], i64 1
41; BE-NEXT:    store i8 0, ptr [[ENDPTR1]], align 1
42; BE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 8), align 4
43; BE-NEXT:    [[PD1:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 8), align 8
44; BE-NEXT:    store i8 0, ptr [[PD1]], align 1
45; BE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 4), align 4
46; BE-NEXT:    store i32 3, ptr @asiz, align 4
47; BE-NEXT:    ret void
48;
49; LE-LABEL: @fold_snprintf_fmt(
50; LE-NEXT:    [[PDIMAX:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 17179869176), align 8
51; LE-NEXT:    store i32 3355185, ptr [[PDIMAX]], align 1
52; LE-NEXT:    store i32 3, ptr @asiz, align 4
53; LE-NEXT:    [[PD5:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 40), align 8
54; LE-NEXT:    store i32 3355185, ptr [[PD5]], align 1
55; LE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 20), align 4
56; LE-NEXT:    [[PD4:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 32), align 8
57; LE-NEXT:    store i32 3355185, ptr [[PD4]], align 1
58; LE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 16), align 4
59; LE-NEXT:    [[PD3:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 24), align 8
60; LE-NEXT:    store i16 12849, ptr [[PD3]], align 1
61; LE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[PD3]], i64 2
62; LE-NEXT:    store i8 0, ptr [[ENDPTR]], align 1
63; LE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 12), align 4
64; LE-NEXT:    [[PD2:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 16), align 8
65; LE-NEXT:    store i8 49, ptr [[PD2]], align 1
66; LE-NEXT:    [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[PD2]], i64 1
67; LE-NEXT:    store i8 0, ptr [[ENDPTR1]], align 1
68; LE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 8), align 4
69; LE-NEXT:    [[PD1:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 8), align 8
70; LE-NEXT:    store i8 0, ptr [[PD1]], align 1
71; LE-NEXT:    store i32 3, ptr getelementptr (i8, ptr @asiz, i64 4), align 4
72; LE-NEXT:    store i32 3, ptr @asiz, align 4
73; LE-NEXT:    ret void
74;
75
76  %pdimax = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 2147483647)
77  %nimax = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdimax, i64 2147483647, ptr @s)
78  store i32 %nimax, ptr @asiz
79
80  %pd5 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 5)
81  %n5 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd5, i64 5, ptr @s)
82  store i32 %n5, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 5)
83
84  %pd4 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 4)
85  %n4 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd4, i64 4, ptr @s)
86  store i32 %n4, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 4)
87
88  %pd3 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 3)
89  %n3 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd3, i64 3, ptr @s)
90  store i32 %n3, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 3)
91
92  %pd2 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 2)
93  %n2 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd2, i64 2, ptr @s)
94  store i32 %n2, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 2)
95
96  %pd1 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 1)
97  %n1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd1, i64 1, ptr @s)
98  store i32 %n1, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 1)
99
100  %pd0 = load ptr, ptr @adst
101  %n0 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd0, i64 0, ptr @s)
102  store i32 %n0, ptr @asiz
103
104  ret void
105}
106
107
108; Verify that snprintf calls with a bound greater than INT_MAX are not
109; transformed.  POSIX requires implementations to set errno to EOVERFLOW
110; so such calls could be folded to just that followed by returning -1.
111
112define void @call_snprintf_fmt_ximax() {
113; ANY-LABEL: @call_snprintf_fmt_ximax(
114; ANY-NEXT:    [[PDM1:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 8), align 8
115; ANY-NEXT:    [[NM1:%.*]] = call i32 (ptr, i64, ptr, ...) @snprintf(ptr noundef nonnull dereferenceable(1) [[PDM1]], i64 -1, ptr nonnull @s)
116; ANY-NEXT:    store i32 [[NM1]], ptr getelementptr (i8, ptr @asiz, i64 4), align 4
117; ANY-NEXT:    [[PDIMAXP1:%.*]] = load ptr, ptr @adst, align 8
118; ANY-NEXT:    [[NIMAXP1:%.*]] = call i32 (ptr, i64, ptr, ...) @snprintf(ptr noundef nonnull dereferenceable(1) [[PDIMAXP1]], i64 2147483648, ptr nonnull @s)
119; ANY-NEXT:    store i32 [[NIMAXP1]], ptr @asiz, align 4
120; ANY-NEXT:    ret void
121;
122
123  %pdm1 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 1)
124  %nm1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdm1, i64 -1, ptr @s)
125  store i32 %nm1, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 1)
126
127  %pdimaxp1 = load ptr, ptr @adst
128  %nimaxp1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdimaxp1, i64 2147483648, ptr @s)
129  store i32 %nimaxp1, ptr @asiz
130
131  ret void
132}
133