1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
;
; Test that strncpy(D, S, N) calls with the empty string S as a source
; are simplified for all values of N.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare ptr @strncpy(ptr, ptr, i64)
; A string of length 4 but size 9 to also verify that characters after
; the nul don't affect the transformation.
@s4 = constant [9 x i8] c"1234\00567\00"
declare void @sink(ptr, ptr)
; Verify that exactly overlapping strncpy(D, D, N) calls are simplified
; only when N < 2.
define void @fold_strncpy_overlap(ptr %dst, i64 %n) {
; CHECK-LABEL: @fold_strncpy_overlap(
; CHECK-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[DST]])
; CHECK-NEXT: ret void
;
; Fold strncpy(D, D, 0) to D.
%ed_0 = call ptr @strncpy(ptr %dst, ptr %dst, i64 0)
call void @sink(ptr %dst, ptr %ed_0)
; Fold strncpy(D, D, 1) to D.
%ed_1 = call ptr @strncpy(ptr %dst, ptr %dst, i64 1)
call void @sink(ptr %dst, ptr %ed_1)
ret void
}
; Verify that exactly overlapping strncpy(D, D, N) calls are left alone
; when N >= 2.
; Such calls are undefined and although they're benign and could be
; simplified to
; memset(D + strnlen(D, N), D, N - strnlen(D, N))
; there is little to gain from it.
define void @call_strncpy_overlap(ptr %dst, i64 %n) {
; CHECK-LABEL: @call_strncpy_overlap(
; CHECK-NEXT: [[ED_2:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 2)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_2]])
; CHECK-NEXT: [[ED_3:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 3)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_3]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr [[DST]], ptr [[DST]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_N]])
; CHECK-NEXT: ret void
;
; Do not transform strncpy(D, D, 2).
%ed_2 = call ptr @strncpy(ptr %dst, ptr %dst, i64 2)
call void @sink(ptr %dst, ptr %ed_2)
; Do not transform strncpy(D, D, 3).
%ed_3 = call ptr @strncpy(ptr %dst, ptr %dst, i64 3)
call void @sink(ptr %dst, ptr %ed_3)
; Do not transform strncpy(D, D, N).
%ed_n = call ptr @strncpy(ptr %dst, ptr %dst, i64 %n)
call void @sink(ptr %dst, ptr %ed_n)
ret void
}
; Verify that strncpy(D, "", N) calls are transformed to memset(D, 0, N).
define void @fold_strncpy_s0(ptr %dst, i64 %n) {
; CHECK-LABEL: @fold_strncpy_s0(
; CHECK-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])
; CHECK-NEXT: store i8 0, ptr [[DST]], align 1
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
; CHECK-NEXT: store i16 0, ptr [[DST]], align 1
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], i8 0, i64 9, i1 false)
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 1 [[DST]], i8 0, i64 [[N:%.*]], i1 false)
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
; CHECK-NEXT: ret void
;
%ps0 = getelementptr [9 x i8], ptr @s4, i32 0, i32 4
; Fold strncpy(D, "", 0) to just D.
%es0_0 = call ptr @strncpy(ptr %dst, ptr %ps0, i64 0)
call void @sink(ptr %dst, ptr %es0_0)
; Transform strncpy(D, "", 1) to *D = '\0, D.
%es0_1 = call ptr @strncpy(ptr %dst, ptr %ps0, i64 1)
call void @sink(ptr %dst, ptr %es0_1)
; Transform strncpy(D, "", 2) to memset(D, 0, 2), D.
%es0_2 = call ptr @strncpy(ptr %dst, ptr %ps0, i64 2)
call void @sink(ptr %dst, ptr %es0_2)
; Transform strncpy(D, "", 9) to memset(D, 0, 9), D.
%es0_9 = call ptr @strncpy(ptr %dst, ptr %ps0, i64 9)
call void @sink(ptr %dst, ptr %es0_9)
; Transform strncpy(D, "", n) to memset(D, 0, n), D.
%es0_n = call ptr @strncpy(ptr %dst, ptr %ps0, i64 %n)
call void @sink(ptr %dst, ptr %es0_n)
ret void
}
; Verify that strncpy(D, S, N) calls with nonconstant source S and constant
; size are simplified when N < 2.
define void @fold_strncpy_s(ptr %dst, ptr %src, i64 %n) {
; CHECK-LABEL: @fold_strncpy_s(
; CHECK-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])
; CHECK-NEXT: [[STXNCPY_CHAR0:%.*]] = load i8, ptr [[SRC:%.*]], align 1
; CHECK-NEXT: store i8 [[STXNCPY_CHAR0]], ptr [[DST]], align 1
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
; CHECK-NEXT: ret void
;
; Fold strncpy(D, S, 0) to just D.
%ed_0 = call ptr @strncpy(ptr %dst, ptr %src, i64 0)
call void @sink(ptr %dst, ptr %ed_0)
; Transform strncpy(D, S, 1) to *D = '\0, D.
%ed_1 = call ptr @strncpy(ptr %dst, ptr %src, i64 1)
call void @sink(ptr %dst, ptr %ed_1)
ret void
}
; Verify that strncpy(D, S, N) calls with nonconstant source S and constant
; size are not transformed when N is either unknown or greater than one.
; Also verify that the arguments of the call are annotated with the right
; attributes.
define void @call_strncpy_s(ptr %dst, ptr %src, i64 %n) {
; CHECK-LABEL: @call_strncpy_s(
; CHECK-NEXT: [[ED_2:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[SRC:%.*]], i64 2)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_2]])
; CHECK-NEXT: [[ED_9:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[SRC]], i64 9)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_9]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr [[DST]], ptr [[SRC]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_N]])
; CHECK-NEXT: ret void
;
; Do not transform strncpy(D, S, 2) when S is unknown. Both *D and *S must
; be derefernceable but neither D[1] nor S[1] need be.
%ed_2 = call ptr @strncpy(ptr %dst, ptr %src, i64 2)
call void @sink(ptr %dst, ptr %ed_2)
; Do not transform strncpy(D, S, 9) when S is unknown..
%ed_9 = call ptr @strncpy(ptr %dst, ptr %src, i64 9)
call void @sink(ptr %dst, ptr %ed_9)
; Do not transform strncpy(D, S, N) when all arguments are unknown. Both
; D and S must be nonnull but neither *D nor *S need be dereferenceable.
; TODO: Both D and S should be annotated nonnull and noundef regardless
; of the value of N. See https://reviews.llvm.org/D124633.
%ed_n = call ptr @strncpy(ptr %dst, ptr %src, i64 %n)
call void @sink(ptr %dst, ptr %ed_n)
ret void
}
|