Skip to content

Commit 7134d2e

Browse files
authored
[SimplifyLibCalls] Fix memchr misoptimization (#106121)
The `ch` argument of memcmp should be truncated to `unsigned char` before using it in comparisons. This didn't happen on all code paths. The following program miscompiled at -O1 and higher: ```C++ #include <cstring> #include <iostream> char ch = '\x81'; int main() { bool found = std::strchr("\x80\x81\x82", ch) != nullptr; std::cout << std::boolalpha << found << '\n'; } ```
1 parent 824cffe commit 7134d2e

File tree

2 files changed

+34
-27
lines changed

2 files changed

+34
-27
lines changed

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,10 +1454,12 @@ Value *LibCallSimplifier::optimizeMemChr(CallInst *CI, IRBuilderBase &B) {
14541454
if (NonContRanges > 2)
14551455
return nullptr;
14561456

1457+
// Slice off the character's high end bits.
1458+
CharVal = B.CreateTrunc(CharVal, B.getInt8Ty());
1459+
14571460
SmallVector<Value *> CharCompares;
14581461
for (unsigned char C : SortedStr)
1459-
CharCompares.push_back(
1460-
B.CreateICmpEQ(CharVal, ConstantInt::get(CharVal->getType(), C)));
1462+
CharCompares.push_back(B.CreateICmpEQ(CharVal, B.getInt8(C)));
14611463

14621464
return B.CreateIntToPtr(B.CreateOr(CharCompares), CI->getType());
14631465
}

llvm/test/Transforms/InstCombine/memchr-7.ll

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ declare ptr @memchr(ptr, i32, i64)
1212

1313
define zeroext i1 @strchr_to_memchr_n_equals_len(i32 %c) {
1414
; CHECK-LABEL: @strchr_to_memchr_n_equals_len(
15-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[C:%.*]], 0
16-
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[C]], -97
17-
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 26
18-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[TMP1]], [[TMP3]]
19-
; CHECK-NEXT: ret i1 [[TMP4]]
15+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
16+
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
17+
; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[TMP1]], -97
18+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 26
19+
; CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
20+
; CHECK-NEXT: ret i1 [[TMP5]]
2021
;
2122
%call = tail call ptr @strchr(ptr nonnull dereferenceable(27) @.str, i32 %c)
2223
%cmp = icmp ne ptr %call, null
@@ -38,9 +39,10 @@ define zeroext i1 @memchr_n_equals_len(i32 %c) {
3839

3940
define zeroext i1 @memchr_n_less_than_len(i32 %c) {
4041
; CHECK-LABEL: @memchr_n_less_than_len(
41-
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[C:%.*]], -97
42-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 15
43-
; CHECK-NEXT: ret i1 [[TMP2]]
42+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
43+
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], -97
44+
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i8 [[TMP2]], 15
45+
; CHECK-NEXT: ret i1 [[TMP3]]
4446
;
4547
%call = tail call ptr @memchr(ptr @.str, i32 %c, i64 15)
4648
%cmp = icmp ne ptr %call, null
@@ -50,11 +52,12 @@ define zeroext i1 @memchr_n_less_than_len(i32 %c) {
5052

5153
define zeroext i1 @memchr_n_more_than_len(i32 %c) {
5254
; CHECK-LABEL: @memchr_n_more_than_len(
53-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[C:%.*]], 0
54-
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[C]], -97
55-
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 26
56-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[TMP1]], [[TMP3]]
57-
; CHECK-NEXT: ret i1 [[TMP4]]
55+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
56+
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
57+
; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[TMP1]], -97
58+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 26
59+
; CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
60+
; CHECK-NEXT: ret i1 [[TMP5]]
5861
;
5962
%call = tail call ptr @memchr(ptr @.str, i32 %c, i64 30)
6063
%cmp = icmp ne ptr %call, null
@@ -114,12 +117,13 @@ define zeroext i1 @memchr_n_equals_len2_minsize(i32 %c) minsize {
114117
; Positive test - 2 non-contiguous ranges
115118
define zeroext i1 @strchr_to_memchr_2_non_cont_ranges(i32 %c) {
116119
; CHECK-LABEL: @strchr_to_memchr_2_non_cont_ranges(
117-
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[C:%.*]], -97
118-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 6
119-
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[C]], -109
120-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], 3
121-
; CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
122-
; CHECK-NEXT: ret i1 [[TMP5]]
120+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
121+
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], -97
122+
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i8 [[TMP2]], 6
123+
; CHECK-NEXT: [[TMP4:%.*]] = add i8 [[TMP1]], -109
124+
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i8 [[TMP4]], 3
125+
; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]]
126+
; CHECK-NEXT: ret i1 [[TMP6]]
123127
;
124128
%call = tail call ptr @memchr(ptr @.str.2, i32 %c, i64 9)
125129
%cmp = icmp ne ptr %call, null
@@ -129,12 +133,13 @@ define zeroext i1 @strchr_to_memchr_2_non_cont_ranges(i32 %c) {
129133
; Positive test - 2 non-contiguous ranges with char duplication
130134
define zeroext i1 @strchr_to_memchr_2_non_cont_ranges_char_dup(i32 %c) {
131135
; CHECK-LABEL: @strchr_to_memchr_2_non_cont_ranges_char_dup(
132-
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[C:%.*]], -97
133-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 3
134-
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[C]], -109
135-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], 2
136-
; CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]]
137-
; CHECK-NEXT: ret i1 [[TMP5]]
136+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
137+
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], -97
138+
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i8 [[TMP2]], 3
139+
; CHECK-NEXT: [[TMP4:%.*]] = add i8 [[TMP1]], -109
140+
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i8 [[TMP4]], 2
141+
; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]]
142+
; CHECK-NEXT: ret i1 [[TMP6]]
138143
;
139144
%call = tail call ptr @memchr(ptr @.str.4, i32 %c, i64 6)
140145
%cmp = icmp ne ptr %call, null

0 commit comments

Comments
 (0)