1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4@.str = private unnamed_addr constant [27 x i8] c"abcdefghijklmnopqrstuvwxyz\00", align 1 5@.str.1 = private unnamed_addr constant [2 x i8] c"\0D\0A", align 1 6@.str.2 = private unnamed_addr constant [10 x i8] c"abcdefmno\00", align 1 7@.str.3 = private unnamed_addr constant [10 x i8] c"abcijkmno\00", align 1 8@.str.4 = private unnamed_addr constant [7 x i8] c"mnabcc\00", align 1 9 10declare ptr @strchr(ptr, i32) 11declare ptr @memchr(ptr, i32, i64) 12 13define zeroext i1 @strchr_to_memchr_n_equals_len(i32 %c) { 14; CHECK-LABEL: @strchr_to_memchr_n_equals_len( 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]] 21; 22 %call = tail call ptr @strchr(ptr nonnull dereferenceable(27) @.str, i32 %c) 23 %cmp = icmp ne ptr %call, null 24 ret i1 %cmp 25} 26 27define zeroext i1 @memchr_n_equals_len(i32 %c) { 28; CHECK-LABEL: @memchr_n_equals_len( 29; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8 30; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 10 31; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], 13 32; CHECK-NEXT: [[CMP:%.*]] = and i1 [[TMP3]], [[TMP2]] 33; CHECK-NEXT: ret i1 [[CMP]] 34; 35 %call = tail call ptr @memchr(ptr nonnull dereferenceable(3) @.str.1, i32 %c, i64 2) 36 %cmp = icmp eq ptr %call, null 37 ret i1 %cmp 38} 39 40define zeroext i1 @memchr_n_less_than_len(i32 %c) { 41; CHECK-LABEL: @memchr_n_less_than_len( 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]] 46; 47 %call = tail call ptr @memchr(ptr @.str, i32 %c, i64 15) 48 %cmp = icmp ne ptr %call, null 49 ret i1 %cmp 50} 51 52 53define zeroext i1 @memchr_n_more_than_len(i32 %c) { 54; CHECK-LABEL: @memchr_n_more_than_len( 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]] 61; 62 %call = tail call ptr @memchr(ptr @.str, i32 %c, i64 30) 63 %cmp = icmp ne ptr %call, null 64 ret i1 %cmp 65} 66 67; Negative test - no comparison with zero 68 69define ptr @memchr_no_zero_cmp(i32 %c) { 70; CHECK-LABEL: @memchr_no_zero_cmp( 71; CHECK-NEXT: [[MEMCHR:%.*]] = tail call ptr @memchr(ptr noundef nonnull dereferenceable(1) @.str, i32 [[C:%.*]], i64 27) 72; CHECK-NEXT: ret ptr [[MEMCHR]] 73; 74 %call = tail call ptr @strchr(ptr nonnull dereferenceable(27) @.str, i32 %c) 75 ret ptr %call 76} 77 78define ptr @memchr_no_zero_cmp2(i32 %c) { 79; CHECK-LABEL: @memchr_no_zero_cmp2( 80; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8 81; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 10 82; CHECK-NEXT: [[MEMCHR_SEL1:%.*]] = select i1 [[TMP2]], ptr getelementptr inbounds nuw (i8, ptr @.str.1, i64 1), ptr null 83; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP1]], 13 84; CHECK-NEXT: [[MEMCHR_SEL2:%.*]] = select i1 [[TMP3]], ptr @.str.1, ptr [[MEMCHR_SEL1]] 85; CHECK-NEXT: ret ptr [[MEMCHR_SEL2]] 86; 87 %call = tail call ptr @strchr(ptr nonnull dereferenceable(3) @.str.1, i32 %c) 88 ret ptr %call 89} 90 91; Negative test - opt for size 92 93define zeroext i1 @memchr_n_equals_len_minsize(i32 %c) minsize { 94; CHECK-LABEL: @memchr_n_equals_len_minsize( 95; CHECK-NEXT: [[MEMCHR:%.*]] = tail call ptr @memchr(ptr noundef nonnull dereferenceable(1) @.str, i32 [[C:%.*]], i64 27) 96; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[MEMCHR]], null 97; CHECK-NEXT: ret i1 [[CMP]] 98; 99 %call = tail call ptr @strchr(ptr nonnull dereferenceable(27) @.str, i32 %c) 100 %cmp = icmp ne ptr %call, null 101 ret i1 %cmp 102} 103 104define zeroext i1 @memchr_n_equals_len2_minsize(i32 %c) minsize { 105; CHECK-LABEL: @memchr_n_equals_len2_minsize( 106; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8 107; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 10 108; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], 13 109; CHECK-NEXT: [[CMP:%.*]] = and i1 [[TMP3]], [[TMP2]] 110; CHECK-NEXT: ret i1 [[CMP]] 111; 112 %call = tail call ptr @memchr(ptr nonnull dereferenceable(3) @.str.1, i32 %c, i64 2) 113 %cmp = icmp eq ptr %call, null 114 ret i1 %cmp 115} 116 117; Positive test - 2 non-contiguous ranges 118define zeroext i1 @strchr_to_memchr_2_non_cont_ranges(i32 %c) { 119; CHECK-LABEL: @strchr_to_memchr_2_non_cont_ranges( 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]] 127; 128 %call = tail call ptr @memchr(ptr @.str.2, i32 %c, i64 9) 129 %cmp = icmp ne ptr %call, null 130 ret i1 %cmp 131} 132 133; Positive test - 2 non-contiguous ranges with char duplication 134define zeroext i1 @strchr_to_memchr_2_non_cont_ranges_char_dup(i32 %c) { 135; CHECK-LABEL: @strchr_to_memchr_2_non_cont_ranges_char_dup( 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]] 143; 144 %call = tail call ptr @memchr(ptr @.str.4, i32 %c, i64 6) 145 %cmp = icmp ne ptr %call, null 146 ret i1 %cmp 147} 148 149; Negative test - more than 2 non-contiguous ranges 150define zeroext i1 @strchr_to_memchr_3_non_cont_ranges(i32 %c) { 151; CHECK-LABEL: @strchr_to_memchr_3_non_cont_ranges( 152; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @memchr(ptr noundef nonnull dereferenceable(1) @.str.3, i32 [[C:%.*]], i64 9) 153; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[CALL]], null 154; CHECK-NEXT: ret i1 [[CMP]] 155; 156 %call = tail call ptr @memchr(ptr @.str.3, i32 %c, i64 9) 157 %cmp = icmp ne ptr %call, null 158 ret i1 %cmp 159} 160