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 a "%c" format string are transformed into a store of the character. 5; Also verify that a size in excess of INT_MAX prevents the transformation. 6; 7; RUN: opt < %s -passes=instcombine -S | FileCheck %s 8 9@pcnt_c = constant [3 x i8] c"%c\00" 10 11@adst = external global [0 x ptr] 12@asiz = external global [0 x i32] 13 14declare i32 @snprintf(ptr, i64, ptr, ...) 15 16 17; Verify that all snprintf calls with a bound between INT_MAX and down 18; to 0 are transformed to memcpy. 19 20define void @fold_snprintf_pcnt_c(i32 %c) { 21; CHECK-LABEL: @fold_snprintf_pcnt_c( 22; CHECK-NEXT: [[PDIMAX:%.*]] = load ptr, ptr @adst, align 8 23; CHECK-NEXT: store i8 1, ptr [[PDIMAX]], align 1 24; CHECK-NEXT: [[NUL:%.*]] = getelementptr inbounds nuw i8, ptr [[PDIMAX]], i64 1 25; CHECK-NEXT: store i8 0, ptr [[NUL]], align 1 26; CHECK-NEXT: store i32 1, ptr @asiz, align 4 27; CHECK-NEXT: [[PD2:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 8), align 8 28; CHECK-NEXT: store i8 2, ptr [[PD2]], align 1 29; CHECK-NEXT: [[NUL1:%.*]] = getelementptr inbounds nuw i8, ptr [[PD2]], i64 1 30; CHECK-NEXT: store i8 0, ptr [[NUL1]], align 1 31; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 4), align 4 32; CHECK-NEXT: [[PD2_0:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 16), align 8 33; CHECK-NEXT: store i8 0, ptr [[PD2_0]], align 1 34; CHECK-NEXT: [[NUL2:%.*]] = getelementptr inbounds nuw i8, ptr [[PD2_0]], i64 1 35; CHECK-NEXT: store i8 0, ptr [[NUL2]], align 1 36; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 8), align 4 37; CHECK-NEXT: [[PD1:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 24), align 8 38; CHECK-NEXT: store i8 0, ptr [[PD1]], align 1 39; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 12), align 4 40; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 16), align 4 41; CHECK-NEXT: [[PD2_C:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 32), align 8 42; CHECK-NEXT: [[CHAR:%.*]] = trunc i32 [[C:%.*]] to i8 43; CHECK-NEXT: store i8 [[CHAR]], ptr [[PD2_C]], align 1 44; CHECK-NEXT: [[NUL3:%.*]] = getelementptr inbounds nuw i8, ptr [[PD2_C]], i64 1 45; CHECK-NEXT: store i8 0, ptr [[NUL3]], align 1 46; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 16), align 4 47; CHECK-NEXT: [[PD1_C:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 40), align 8 48; CHECK-NEXT: store i8 0, ptr [[PD1_C]], align 1 49; CHECK-NEXT: store i32 1, ptr getelementptr (i8, ptr @asiz, i64 20), align 4 50; CHECK-NEXT: ret void 51; 52 53 ; Transform snprintf(dst, INT_MAX, "%c", 1) to memcpy(dst, "1", 2), 1. 54 %pdimax = load ptr, ptr @adst 55 %nimax = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdimax, i64 2147483647, ptr @pcnt_c, i32 1) 56 store i32 %nimax, ptr @asiz 57 58 ; Transform snprintf(dst, 2, "%c", '\2') to memcpy(dst, "2", 2), 1. 59 %pd2 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 1) 60 %n2 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd2, i64 2, ptr @pcnt_c, i8 2) 61 store i32 %n2, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 1) 62 63 ; Transform snprintf(dst, 2, "%c", '\0') to memcpy(dst, "\0", 2), 1. 64 %pd2_0 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 2) 65 %n2_0 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd2_0, i64 2, ptr @pcnt_c, i8 0) 66 store i32 %n2_0, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 2) 67 68 ; Transform snprintf(dst, 1, "%c", (short)3) to memcpy(dst, "\3", 2), 1. 69 %pd1 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 3) 70 %n1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd1, i64 1, ptr @pcnt_c, i16 3) 71 store i32 %n1, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 3) 72 73 ; Fold snprintf(dst, 0, "%c", 4) to 1. 74 %pd0 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 4) 75 %n0 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd0, i64 0, ptr @pcnt_c, i32 4) 76 store i32 %n0, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 4) 77 78 79 ; Transform snprintf(dst, 2, "%c", c) with a nonconstant c to 80 ; dst[0] = c, dst[1] = '\0', 1. 81 %pd2_c = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 4) 82 %n2_c = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd2_c, i64 2, ptr @pcnt_c, i32 %c) 83 store i32 %n2_c, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 4) 84 85 ; Transform snprintf(dst, 1, "%c", c) with a nonconstant c to *dst = '\0', 0. 86 %pd1_c = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 5) 87 %n1_c = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pd1_c, i64 1, ptr @pcnt_c, i32 %c) 88 store i32 %n1_c, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 5) 89 90 ret void 91} 92 93 94; Verify that snprintf calls with a bound greater than INT_MAX are not 95; transformed. POSIX requires implementations to set errno to EOVERFLOW 96; so such calls could be folded to just that followed by returning -1. 97 98define void @call_snprintf_pcnt_c_ximax(i32 %c) { 99; CHECK-LABEL: @call_snprintf_pcnt_c_ximax( 100; CHECK-NEXT: [[PDM1:%.*]] = load ptr, ptr @adst, align 8 101; CHECK-NEXT: [[NM1:%.*]] = call i32 (ptr, i64, ptr, ...) @snprintf(ptr noundef nonnull dereferenceable(1) [[PDM1]], i64 -1, ptr nonnull @pcnt_c, i8 0) 102; CHECK-NEXT: store i32 [[NM1]], ptr @asiz, align 4 103; CHECK-NEXT: [[PDIMAXP1:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 8), align 8 104; CHECK-NEXT: [[NIMAXP1:%.*]] = call i32 (ptr, i64, ptr, ...) @snprintf(ptr noundef nonnull dereferenceable(1) [[PDIMAXP1]], i64 2147483648, ptr nonnull @pcnt_c, i8 1) 105; CHECK-NEXT: store i32 [[NIMAXP1]], ptr getelementptr (i8, ptr @asiz, i64 4), align 4 106; CHECK-NEXT: [[PDM1SL32:%.*]] = load ptr, ptr getelementptr (i8, ptr @adst, i64 16), align 8 107; CHECK-NEXT: [[NM1SL32:%.*]] = call i32 (ptr, i64, ptr, ...) @snprintf(ptr noundef nonnull dereferenceable(1) [[PDM1SL32]], i64 -4294967296, ptr nonnull @pcnt_c, i8 1) 108; CHECK-NEXT: store i32 [[NM1SL32]], ptr getelementptr (i8, ptr @asiz, i64 8), align 4 109; CHECK-NEXT: ret void 110; 111 112 %pdm1 = load ptr, ptr @adst 113 %nm1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdm1, i64 -1, ptr @pcnt_c, i8 0) 114 store i32 %nm1, ptr @asiz 115 116 117 %pdimaxp1 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 1) 118 %nimaxp1 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdimaxp1, i64 2147483648, ptr @pcnt_c, i8 1) 119 store i32 %nimaxp1, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 1) 120 121 ; Exercise snprintf(dst, -1LU << 32, "%c", c). 122 %pdm1sl32 = load ptr, ptr getelementptr ([0 x ptr], ptr @adst, i32 0, i32 2) 123 %nm1sl32 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %pdm1sl32, i64 18446744069414584320, ptr @pcnt_c, i8 1) 124 store i32 %nm1sl32, ptr getelementptr ([0 x i32], ptr @asiz, i32 0, i32 2) 125 126 ret void 127} 128