1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Verify that calls to atoi and related conversion functions with members 3; of constant structs as arguments are folded to constants as expected. 4; RUN: opt < %s -passes=instcombine -S | FileCheck %s 5 6declare i32 @atoi(ptr) 7declare i64 @atol(ptr) 8declare i64 @atoll(ptr) 9 10declare i64 @strtol(ptr, ptr, i32) 11declare i64 @strtoll(ptr, ptr, i32) 12 13%struct.A = type { [4 x i8], [5 x i8], [7 x i8] } 14 15@a = constant [2 x %struct.A] [%struct.A { [4 x i8] c"1\00\00\00", [5 x i8] c"12\00\00\00", [7 x i8] c"56789\00\00" }, %struct.A { [4 x i8] c"123\00", [5 x i8] c"1234\00", [7 x i8] c"67890\00\00" }] 16 17 18; Fold atoi(a[I].M) for constant I in [0, 1] and member M in [a, b] 19; to a constant. 20 21define void @fold_atoi_member(ptr %pi) { 22; CHECK-LABEL: @fold_atoi_member( 23; CHECK-NEXT: store i32 1, ptr [[PI:%.*]], align 4 24; CHECK-NEXT: [[PIA0B:%.*]] = getelementptr i8, ptr [[PI]], i64 4 25; CHECK-NEXT: store i32 12, ptr [[PIA0B]], align 4 26; CHECK-NEXT: [[PIA1A:%.*]] = getelementptr i8, ptr [[PI]], i64 8 27; CHECK-NEXT: store i32 123, ptr [[PIA1A]], align 4 28; CHECK-NEXT: [[PIA1B:%.*]] = getelementptr i8, ptr [[PI]], i64 12 29; CHECK-NEXT: store i32 1234, ptr [[PIA1B]], align 4 30; CHECK-NEXT: ret void 31; 32; Fold atoi(a[0].a) to 1. 33 %ia0a = call i32 @atoi(ptr @a) 34 store i32 %ia0a, ptr %pi 35 36; Fold atoi(a[0].b) to 12. 37 %pa0b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 0 38 %ia0b = call i32 @atoi(ptr %pa0b) 39 %pia0b = getelementptr i32, ptr %pi, i32 1 40 store i32 %ia0b, ptr %pia0b 41 42; Fold atoi(a[1].a) to 123. 43 %pa1a = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 0 44 %ia1a = call i32 @atoi(ptr %pa1a) 45 %pia1a = getelementptr i32, ptr %pi, i32 2 46 store i32 %ia1a, ptr %pia1a 47 48; Fold atoi(a[1].b) to 1234. 49 %pa1b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 0 50 %ia1b = call i32 @atoi(ptr %pa1b) 51 %pia1b = getelementptr i32, ptr %pi, i32 3 52 store i32 %ia1b, ptr %pia1b 53 54 ret void 55} 56 57 58; TODO: Fold atoi with an excessive offset. It's undefined so folding it 59; to zero is valid and might prevent crashes or returning a bogus value, 60; even though it prevents detecting the bug by sanitizers. 61; This is not fully implemented because the out-of-bounds offset results 62; in the empty string which atoi (via strtol) is required to interpret as 63; a zero but for which it may set errno to EINVAL. To fold only 64; the undefined calls the folder would have to differentiate between 65; the empty string an out-of-bounds pointer. 66 67define void @fold_atoi_offset_out_of_bounds(ptr %pi) { 68; CHECK-LABEL: @fold_atoi_offset_out_of_bounds( 69; CHECK-NEXT: [[IA_0_0_32:%.*]] = call i32 @atoi(ptr nonnull getelementptr inbounds nuw (i8, ptr @a, i64 32)) 70; CHECK-NEXT: store i32 [[IA_0_0_32]], ptr [[PI:%.*]], align 4 71; CHECK-NEXT: [[IA_0_0_33:%.*]] = call i32 @atoi(ptr getelementptr (i8, ptr @a, i64 33)) 72; CHECK-NEXT: store i32 [[IA_0_0_33]], ptr [[PI]], align 4 73; CHECK-NEXT: ret void 74; 75; TODO: Check folding. 76; Fold atoi((const char*)a + sizeof a) to zero. 77 %ia_0_0_32 = call i32 @atoi(ptr getelementptr inbounds ([2 x %struct.A], ptr @a, i64 1, i64 0, i32 0, i64 0)) 78 store i32 %ia_0_0_32, ptr %pi 79 80; Likewise, fold atoi((const char*)a + sizeof a + 1) to zero. 81 %pa_0_0_33 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 0, i64 33 82 %ia_0_0_33 = call i32 @atoi(ptr %pa_0_0_33) 83 store i32 %ia_0_0_33, ptr %pi 84 85 ret void 86} 87 88 89; Fold atol(a[I].M) for constant I in [0, 1] and member M in [a, b, c] 90; to a constant. 91 92define void @fold_atol_member(ptr %pi) { 93; CHECK-LABEL: @fold_atol_member( 94; CHECK-NEXT: store i64 1, ptr [[PI:%.*]], align 4 95; CHECK-NEXT: [[PIA0B:%.*]] = getelementptr i8, ptr [[PI]], i64 8 96; CHECK-NEXT: store i64 12, ptr [[PIA0B]], align 4 97; CHECK-NEXT: [[PIA0C:%.*]] = getelementptr i8, ptr [[PI]], i64 16 98; CHECK-NEXT: store i64 56789, ptr [[PIA0C]], align 4 99; CHECK-NEXT: [[PIA1A:%.*]] = getelementptr i8, ptr [[PI]], i64 24 100; CHECK-NEXT: store i64 123, ptr [[PIA1A]], align 4 101; CHECK-NEXT: [[PIA1B:%.*]] = getelementptr i8, ptr [[PI]], i64 32 102; CHECK-NEXT: store i64 1234, ptr [[PIA1B]], align 4 103; CHECK-NEXT: [[PIA1C:%.*]] = getelementptr i8, ptr [[PI]], i64 40 104; CHECK-NEXT: store i64 67890, ptr [[PIA1C]], align 4 105; CHECK-NEXT: ret void 106; 107; Fold atol(a[0].a) to 1. 108 %ia0a = call i64 @atol(ptr @a) 109 store i64 %ia0a, ptr %pi 110 111; Fold atol(a[0].b) to 12. 112 %pa0b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 0 113 %ia0b = call i64 @atol(ptr %pa0b) 114 %pia0b = getelementptr i64, ptr %pi, i32 1 115 store i64 %ia0b, ptr %pia0b 116 117; Fold atol(a[0].c) to 56789. 118 %pa0c = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 0 119 %ia0c = call i64 @atol(ptr %pa0c) 120 %pia0c = getelementptr i64, ptr %pi, i32 2 121 store i64 %ia0c, ptr %pia0c 122 123; Fold atol(a[1].a) to 123. 124 %pa1a = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 0 125 %ia1a = call i64 @atol(ptr %pa1a) 126 %pia1a = getelementptr i64, ptr %pi, i32 3 127 store i64 %ia1a, ptr %pia1a 128 129; Fold atol(a[1].b) to 1234. 130 %pa1b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 0 131 %ia1b = call i64 @atol(ptr %pa1b) 132 %pia1b = getelementptr i64, ptr %pi, i32 4 133 store i64 %ia1b, ptr %pia1b 134 135; Fold atol(a[1].c) to 67890. 136 %pa1c = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 0 137 %ia1c = call i64 @atol(ptr %pa1c) 138 %pia1c = getelementptr i64, ptr %pi, i32 5 139 store i64 %ia1c, ptr %pia1c 140 141 ret void 142} 143 144 145; Fold atoll(a[I].M + C) for constant I in [0, 1], member M in [a, b, c], 146; and C in a valid range to a constant. 147 148define void @fold_atoll_member_pC(ptr %pi) { 149; CHECK-LABEL: @fold_atoll_member_pC( 150; CHECK-NEXT: store i64 1, ptr [[PI:%.*]], align 4 151; CHECK-NEXT: [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8 152; CHECK-NEXT: store i64 2, ptr [[PIA0BP1]], align 4 153; CHECK-NEXT: [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16 154; CHECK-NEXT: store i64 89, ptr [[PIA0CP3]], align 4 155; CHECK-NEXT: [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24 156; CHECK-NEXT: store i64 3, ptr [[PIA1AP2]], align 4 157; CHECK-NEXT: [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32 158; CHECK-NEXT: store i64 4, ptr [[PIA1BP3]], align 4 159; CHECK-NEXT: [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40 160; CHECK-NEXT: store i64 0, ptr [[PIA1CP4]], align 4 161; CHECK-NEXT: ret void 162; 163; Fold atoll(a[0].a) to 1. 164 %ia0a = call i64 @atol(ptr @a) 165 store i64 %ia0a, ptr %pi 166 167; Fold atoll(a[0].b + 1) to 2. 168 %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1 169 %ia0bp1 = call i64 @atol(ptr %pa0bp1) 170 %pia0bp1 = getelementptr i64, ptr %pi, i32 1 171 store i64 %ia0bp1, ptr %pia0bp1 172 173; Fold atoll(a[0].c + 3) to 89. 174 %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3 175 %ia0cp3 = call i64 @atol(ptr %pa0cp3) 176 %pia0cp3 = getelementptr i64, ptr %pi, i32 2 177 store i64 %ia0cp3, ptr %pia0cp3 178 179; Fold atoll(a[1].a + 2) to 3. 180 %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2 181 %ia1ap2 = call i64 @atol(ptr %pa1ap2) 182 %pia1ap2 = getelementptr i64, ptr %pi, i32 3 183 store i64 %ia1ap2, ptr %pia1ap2 184 185; Fold atoll(a[1].b + 3) to 4. 186 %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3 187 %ia1bp3 = call i64 @atol(ptr %pa1bp3) 188 %pia1bp3 = getelementptr i64, ptr %pi, i32 4 189 store i64 %ia1bp3, ptr %pia1bp3 190 191; Fold atoll(a[1].c + 4) to 0. 192 %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4 193 %ia1cp4 = call i64 @atol(ptr %pa1cp4) 194 %pia1cp4 = getelementptr i64, ptr %pi, i32 5 195 store i64 %ia1cp4, ptr %pia1cp4 196 197 ret void 198} 199 200 201; Fold strtol(a[I].M + C, 0, 0) for constant I in [0, 1], member M in [a, b, c], 202; and C in a valid range to a constant. 203 204define void @fold_strtol_member_pC(ptr %pi) { 205; CHECK-LABEL: @fold_strtol_member_pC( 206; CHECK-NEXT: store i64 1, ptr [[PI:%.*]], align 4 207; CHECK-NEXT: [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8 208; CHECK-NEXT: store i64 2, ptr [[PIA0BP1]], align 4 209; CHECK-NEXT: [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16 210; CHECK-NEXT: store i64 89, ptr [[PIA0CP3]], align 4 211; CHECK-NEXT: [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24 212; CHECK-NEXT: store i64 3, ptr [[PIA1AP2]], align 4 213; CHECK-NEXT: [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32 214; CHECK-NEXT: store i64 4, ptr [[PIA1BP3]], align 4 215; CHECK-NEXT: [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40 216; CHECK-NEXT: store i64 0, ptr [[PIA1CP4]], align 4 217; CHECK-NEXT: ret void 218; 219; Fold strtol(a[0].a, 0, 0) to 1. 220 %ia0a = call i64 @strtol(ptr @a, ptr null, i32 0) 221 store i64 %ia0a, ptr %pi 222 223; Fold strtol(a[0].b + 1, 0, 0, ptr null, i32 0) to 2. 224 %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1 225 %ia0bp1 = call i64 @strtol(ptr %pa0bp1, ptr null, i32 0) 226 %pia0bp1 = getelementptr i64, ptr %pi, i32 1 227 store i64 %ia0bp1, ptr %pia0bp1 228 229; Fold strtol(a[0].c + 3, 0, 0, ptr null, i32 0) to 89. 230 %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3 231 %ia0cp3 = call i64 @strtol(ptr %pa0cp3, ptr null, i32 0) 232 %pia0cp3 = getelementptr i64, ptr %pi, i32 2 233 store i64 %ia0cp3, ptr %pia0cp3 234 235; Fold strtol(a[1].a + 2, 0, 0, ptr null, i32 0) to 3. 236 %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2 237 %ia1ap2 = call i64 @strtol(ptr %pa1ap2, ptr null, i32 0) 238 %pia1ap2 = getelementptr i64, ptr %pi, i32 3 239 store i64 %ia1ap2, ptr %pia1ap2 240 241; Fold strtol(a[1].b + 3, 0, 0, ptr null, i32 0) to 4. 242 %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3 243 %ia1bp3 = call i64 @strtol(ptr %pa1bp3, ptr null, i32 0) 244 %pia1bp3 = getelementptr i64, ptr %pi, i32 4 245 store i64 %ia1bp3, ptr %pia1bp3 246 247; Fold strtol(a[1].c + 4, 0, 0, ptr null, i32 0) to 0. 248 %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4 249 %ia1cp4 = call i64 @strtol(ptr %pa1cp4, ptr null, i32 0) 250 %pia1cp4 = getelementptr i64, ptr %pi, i32 5 251 store i64 %ia1cp4, ptr %pia1cp4 252 253 ret void 254} 255 256 257; Fold strtoll(a[I].M + C, 0, 0) for constant I in [0, 1], member M 258; in [a, b, c], and C in a valid range to a constant. 259 260define void @fold_strtoll_member_pC(ptr %pi) { 261; CHECK-LABEL: @fold_strtoll_member_pC( 262; CHECK-NEXT: store i64 1, ptr [[PI:%.*]], align 4 263; CHECK-NEXT: [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8 264; CHECK-NEXT: store i64 2, ptr [[PIA0BP1]], align 4 265; CHECK-NEXT: [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16 266; CHECK-NEXT: store i64 89, ptr [[PIA0CP3]], align 4 267; CHECK-NEXT: [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24 268; CHECK-NEXT: store i64 3, ptr [[PIA1AP2]], align 4 269; CHECK-NEXT: [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32 270; CHECK-NEXT: store i64 4, ptr [[PIA1BP3]], align 4 271; CHECK-NEXT: [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40 272; CHECK-NEXT: store i64 0, ptr [[PIA1CP4]], align 4 273; CHECK-NEXT: ret void 274; 275; Fold strtoll(a[0].a, 0, 0) to 1. 276 %ia0a = call i64 @strtoll(ptr @a, ptr null, i32 0) 277 store i64 %ia0a, ptr %pi 278 279; Fold strtoll(a[0].b + 1, 0, 0, ptr null, i32 0) to 2. 280 %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1 281 %ia0bp1 = call i64 @strtoll(ptr %pa0bp1, ptr null, i32 0) 282 %pia0bp1 = getelementptr i64, ptr %pi, i32 1 283 store i64 %ia0bp1, ptr %pia0bp1 284 285; Fold strtoll(a[0].c + 3, 0, 0, ptr null, i32 0) to 89. 286 %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3 287 %ia0cp3 = call i64 @strtoll(ptr %pa0cp3, ptr null, i32 0) 288 %pia0cp3 = getelementptr i64, ptr %pi, i32 2 289 store i64 %ia0cp3, ptr %pia0cp3 290 291; Fold strtoll(a[1].a + 2, 0, 0, ptr null, i32 0) to 3. 292 %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2 293 %ia1ap2 = call i64 @strtoll(ptr %pa1ap2, ptr null, i32 0) 294 %pia1ap2 = getelementptr i64, ptr %pi, i32 3 295 store i64 %ia1ap2, ptr %pia1ap2 296 297; Fold strtoll(a[1].b + 3, 0, 0, ptr null, i32 0) to 4. 298 %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3 299 %ia1bp3 = call i64 @strtoll(ptr %pa1bp3, ptr null, i32 0) 300 %pia1bp3 = getelementptr i64, ptr %pi, i32 4 301 store i64 %ia1bp3, ptr %pia1bp3 302 303; Fold strtoll(a[1].c + 4, 0, 0, ptr null, i32 0) to 0. 304 %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4 305 %ia1cp4 = call i64 @strtoll(ptr %pa1cp4, ptr null, i32 0) 306 %pia1cp4 = getelementptr i64, ptr %pi, i32 5 307 store i64 %ia1cp4, ptr %pia1cp4 308 309 ret void 310} 311