1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Test that the strchr library call simplifier works correctly. 3; RUN: opt < %s -passes=instcombine -S | FileCheck %s 4 5target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" 6 7@hello = constant [14 x i8] c"hello world\5Cn\00" 8@null = constant [1 x i8] zeroinitializer 9@newlines = constant [3 x i8] c"\0D\0A\00" 10@chp = global ptr zeroinitializer 11 12declare ptr @strchr(ptr, i32) 13 14define void @test_simplify1() { 15; CHECK-LABEL: @test_simplify1( 16; CHECK-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 6), ptr @chp, align 4 17; CHECK-NEXT: ret void 18; 19 20 %dst = call ptr @strchr(ptr @hello, i32 119) 21 store ptr %dst, ptr @chp 22 ret void 23} 24 25define void @test_simplify2() { 26; CHECK-LABEL: @test_simplify2( 27; CHECK-NEXT: store ptr null, ptr @chp, align 4 28; CHECK-NEXT: ret void 29; 30 31 %dst = call ptr @strchr(ptr @null, i32 119) 32 store ptr %dst, ptr @chp 33 ret void 34} 35 36define void @test_simplify3() { 37; CHECK-LABEL: @test_simplify3( 38; CHECK-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 13), ptr @chp, align 4 39; CHECK-NEXT: ret void 40; 41 42 %dst = call ptr @strchr(ptr @hello, i32 0) 43 store ptr %dst, ptr @chp 44 ret void 45} 46 47define void @test_simplify4(i32 %chr) { 48; CHECK-LABEL: @test_simplify4( 49; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr noundef nonnull dereferenceable(1) @hello, i32 [[CHR:%.*]], i32 14) 50; CHECK-NEXT: store ptr [[MEMCHR]], ptr @chp, align 4 51; CHECK-NEXT: ret void 52; 53 54 %dst = call ptr @strchr(ptr @hello, i32 %chr) 55 store ptr %dst, ptr @chp 56 ret void 57} 58 59define void @test_simplify5() { 60; CHECK-LABEL: @test_simplify5( 61; CHECK-NEXT: store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 13), ptr @chp, align 4 62; CHECK-NEXT: ret void 63; 64 65 %dst = call ptr @strchr(ptr @hello, i32 65280) 66 store ptr %dst, ptr @chp 67 ret void 68} 69 70; Check transformation strchr(p, 0) -> p + strlen(p) 71define void @test_simplify6(ptr %str) { 72; CHECK-LABEL: @test_simplify6( 73; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]]) 74; CHECK-NEXT: [[STRCHR:%.*]] = getelementptr inbounds i8, ptr [[STR]], i32 [[STRLEN]] 75; CHECK-NEXT: store ptr [[STRCHR]], ptr @chp, align 4 76; CHECK-NEXT: ret void 77; 78 79 %dst = call ptr @strchr(ptr %str, i32 0) 80 store ptr %dst, ptr @chp 81 ret void 82} 83 84; Check transformation strchr("\r\n", C) != nullptr -> (C & 9217) != 0 85define i1 @test_simplify7(i32 %C) { 86; CHECK-LABEL: @test_simplify7( 87; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i16 88; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], 255 89; CHECK-NEXT: [[MEMCHR_BOUNDS:%.*]] = icmp samesign ult i16 [[TMP2]], 16 90; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i16 1, [[TMP2]] 91; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP3]], 9217 92; CHECK-NEXT: [[MEMCHR_BITS:%.*]] = icmp ne i16 [[TMP4]], 0 93; CHECK-NEXT: [[MEMCHR1:%.*]] = select i1 [[MEMCHR_BOUNDS]], i1 [[MEMCHR_BITS]], i1 false 94; CHECK-NEXT: ret i1 [[MEMCHR1]] 95; 96 97 %dst = call ptr @strchr(ptr @newlines, i32 %C) 98 %cmp = icmp ne ptr %dst, null 99 ret i1 %cmp 100} 101 102define ptr @test1(ptr %str, i32 %c) { 103; CHECK-LABEL: @test1( 104; CHECK-NEXT: [[RET:%.*]] = call ptr @strchr(ptr noundef nonnull dereferenceable(1) [[STR:%.*]], i32 [[C:%.*]]) 105; CHECK-NEXT: ret ptr [[RET]] 106; 107 108 %ret = call ptr @strchr(ptr %str, i32 %c) 109 ret ptr %ret 110} 111 112define ptr @test2(ptr %str, i32 %c) null_pointer_is_valid { 113; CHECK-LABEL: @test2( 114; CHECK-NEXT: [[RET:%.*]] = call ptr @strchr(ptr noundef [[STR:%.*]], i32 [[C:%.*]]) 115; CHECK-NEXT: ret ptr [[RET]] 116; 117 118 %ret = call ptr @strchr(ptr %str, i32 %c) 119 ret ptr %ret 120} 121