305 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; Test that the strlen library call simplifier works correctly.3;4; RUN: opt < %s -passes=instcombine -S | FileCheck %s5 6target 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"7 8@hello = constant [6 x i8] c"hello\00"9@longer = constant [7 x i8] c"longer\00"10@null = constant [1 x i8] zeroinitializer11@null_hello = constant [7 x i8] c"\00hello\00"12@nullstring = constant i8 013@a = common global [32 x i8] zeroinitializer, align 114@null_hello_mid = constant [13 x i8] c"hello wor\00ld\00"15 16declare i32 @strlen(ptr)17 18; Check strlen(string constant) -> integer constant.19 20define i32 @test_simplify1() {21; CHECK-LABEL: @test_simplify1(22; CHECK-NEXT: ret i32 523;24 %hello_l = call i32 @strlen(ptr @hello)25 ret i32 %hello_l26}27 28define i32 @test_simplify2() {29; CHECK-LABEL: @test_simplify2(30; CHECK-NEXT: ret i32 031;32 %null_l = call i32 @strlen(ptr @null)33 ret i32 %null_l34}35 36define i32 @test_simplify3() {37; CHECK-LABEL: @test_simplify3(38; CHECK-NEXT: ret i32 039;40 %null_hello_l = call i32 @strlen(ptr @null_hello)41 ret i32 %null_hello_l42}43 44define i32 @test_simplify4() {45; CHECK-LABEL: @test_simplify4(46; CHECK-NEXT: ret i32 047;48 %len = tail call i32 @strlen(ptr @nullstring) nounwind49 ret i32 %len50}51 52; Check strlen(x) == 0 --> *x == 0.53 54define i1 @test_simplify5() {55; CHECK-LABEL: @test_simplify5(56; CHECK-NEXT: ret i1 false57;58 %hello_l = call i32 @strlen(ptr @hello)59 %eq_hello = icmp eq i32 %hello_l, 060 ret i1 %eq_hello61}62 63define i1 @test_simplify6(ptr %str_p) {64; CHECK-LABEL: @test_simplify6(65; CHECK-NEXT: [[CHAR0:%.*]] = load i8, ptr [[STR_P:%.*]], align 166; CHECK-NEXT: [[EQ_NULL:%.*]] = icmp eq i8 [[CHAR0]], 067; CHECK-NEXT: ret i1 [[EQ_NULL]]68;69 %str_l = call i32 @strlen(ptr %str_p)70 %eq_null = icmp eq i32 %str_l, 071 ret i1 %eq_null72}73 74; Check strlen(x) != 0 --> *x != 0.75 76define i1 @test_simplify7() {77; CHECK-LABEL: @test_simplify7(78; CHECK-NEXT: ret i1 true79;80 %hello_l = call i32 @strlen(ptr @hello)81 %ne_hello = icmp ne i32 %hello_l, 082 ret i1 %ne_hello83}84 85define i1 @test_simplify8(ptr %str_p) {86; CHECK-LABEL: @test_simplify8(87; CHECK-NEXT: [[CHAR0:%.*]] = load i8, ptr [[STR_P:%.*]], align 188; CHECK-NEXT: [[NE_NULL:%.*]] = icmp ne i8 [[CHAR0]], 089; CHECK-NEXT: ret i1 [[NE_NULL]]90;91 %str_l = call i32 @strlen(ptr %str_p)92 %ne_null = icmp ne i32 %str_l, 093 ret i1 %ne_null94}95 96define i32 @test_simplify9(i1 %x) {97; CHECK-LABEL: @test_simplify9(98; CHECK-NEXT: [[L:%.*]] = select i1 [[X:%.*]], i32 5, i32 699; CHECK-NEXT: ret i32 [[L]]100;101 %s = select i1 %x, ptr @hello, ptr @longer102 %l = call i32 @strlen(ptr %s)103 ret i32 %l104}105 106; Check the case that should be simplified to a sub instruction.107; strlen(@hello + x) --> 5 - x108 109define i32 @test_simplify10_inbounds(i32 %x) {110; CHECK-LABEL: @test_simplify10_inbounds(111; CHECK-NEXT: [[HELLO_L:%.*]] = sub i32 5, [[X:%.*]]112; CHECK-NEXT: ret i32 [[HELLO_L]]113;114 %hello_p = getelementptr inbounds [6 x i8], ptr @hello, i32 0, i32 %x115 %hello_l = call i32 @strlen(ptr %hello_p)116 ret i32 %hello_l117}118 119define i32 @test_simplify10_inbounds_i8gep(i32 %x) {120; CHECK-LABEL: @test_simplify10_inbounds_i8gep(121; CHECK-NEXT: [[HELLO_L:%.*]] = sub i32 5, [[X:%.*]]122; CHECK-NEXT: ret i32 [[HELLO_L]]123;124 %hello_p = getelementptr inbounds i8, ptr @hello, i32 %x125 %hello_l = call i32 @strlen(ptr %hello_p)126 ret i32 %hello_l127}128 129define i32 @test_simplify10_inbounds_i8gep_const() {130; CHECK-LABEL: @test_simplify10_inbounds_i8gep_const(131; CHECK-NEXT: ret i32 3132;133 %hello_p = getelementptr inbounds i8, ptr @hello, i32 2134 %hello_l = call i32 @strlen(ptr %hello_p)135 ret i32 %hello_l136}137 138define i32 @test_simplify10_no_inbounds(i32 %x) {139; CHECK-LABEL: @test_simplify10_no_inbounds(140; CHECK-NEXT: [[HELLO_L:%.*]] = sub i32 5, [[X:%.*]]141; CHECK-NEXT: ret i32 [[HELLO_L]]142;143 %hello_p = getelementptr [6 x i8], ptr @hello, i32 0, i32 %x144 %hello_l = call i32 @strlen(ptr %hello_p)145 ret i32 %hello_l146}147 148define i32 @test_simplify10_no_inbounds_i8gep(i32 %x) {149; CHECK-LABEL: @test_simplify10_no_inbounds_i8gep(150; CHECK-NEXT: [[HELLO_L:%.*]] = sub i32 5, [[X:%.*]]151; CHECK-NEXT: ret i32 [[HELLO_L]]152;153 %hello_p = getelementptr i8, ptr @hello, i32 %x154 %hello_l = call i32 @strlen(ptr %hello_p)155 ret i32 %hello_l156}157 158; strlen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)159 160define i32 @test_simplify11(i32 %x) {161; CHECK-LABEL: @test_simplify11(162; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 7163; CHECK-NEXT: [[HELLO_L:%.*]] = sub nuw nsw i32 9, [[AND]]164; CHECK-NEXT: ret i32 [[HELLO_L]]165;166 %and = and i32 %x, 7167 %hello_p = getelementptr inbounds [13 x i8], ptr @null_hello_mid, i32 0, i32 %and168 %hello_l = call i32 @strlen(ptr %hello_p)169 ret i32 %hello_l170}171 172; Check cases that shouldn't be simplified.173 174define i32 @test_no_simplify1() {175; CHECK-LABEL: @test_no_simplify1(176; CHECK-NEXT: [[A_L:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) @a)177; CHECK-NEXT: ret i32 [[A_L]]178;179 %a_l = call i32 @strlen(ptr @a)180 ret i32 %a_l181}182 183; strlen(@null_hello + x) should not be simplified to a sub instruction.184 185define i32 @test_no_simplify2(i32 %x) {186; CHECK-LABEL: @test_no_simplify2(187; CHECK-NEXT: [[HELLO_P:%.*]] = getelementptr inbounds i8, ptr @null_hello, i32 [[X:%.*]]188; CHECK-NEXT: [[HELLO_L:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[HELLO_P]])189; CHECK-NEXT: ret i32 [[HELLO_L]]190;191 %hello_p = getelementptr inbounds [7 x i8], ptr @null_hello, i32 0, i32 %x192 %hello_l = call i32 @strlen(ptr %hello_p)193 ret i32 %hello_l194}195 196define i32 @test_no_simplify2_no_null_opt(i32 %x) #0 {197; CHECK-LABEL: @test_no_simplify2_no_null_opt(198; CHECK-NEXT: [[HELLO_P:%.*]] = getelementptr inbounds i8, ptr @null_hello, i32 [[X:%.*]]199; CHECK-NEXT: [[HELLO_L:%.*]] = call i32 @strlen(ptr noundef [[HELLO_P]])200; CHECK-NEXT: ret i32 [[HELLO_L]]201;202 %hello_p = getelementptr inbounds [7 x i8], ptr @null_hello, i32 0, i32 %x203 %hello_l = call i32 @strlen(ptr %hello_p)204 ret i32 %hello_l205}206 207; strlen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.208 209define i32 @test_no_simplify3(i32 %x) {210; CHECK-LABEL: @test_no_simplify3(211; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 15212; CHECK-NEXT: [[HELLO_P:%.*]] = getelementptr inbounds nuw i8, ptr @null_hello_mid, i32 [[AND]]213; CHECK-NEXT: [[HELLO_L:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[HELLO_P]])214; CHECK-NEXT: ret i32 [[HELLO_L]]215;216 %and = and i32 %x, 15217 %hello_p = getelementptr inbounds [13 x i8], ptr @null_hello_mid, i32 0, i32 %and218 %hello_l = call i32 @strlen(ptr %hello_p)219 ret i32 %hello_l220}221 222define i32 @test_no_simplify3_on_null_opt(i32 %x) #0 {223; CHECK-LABEL: @test_no_simplify3_on_null_opt(224; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 15225; CHECK-NEXT: [[HELLO_P:%.*]] = getelementptr inbounds nuw i8, ptr @null_hello_mid, i32 [[AND]]226; CHECK-NEXT: [[HELLO_L:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[HELLO_P]])227; CHECK-NEXT: ret i32 [[HELLO_L]]228;229 %and = and i32 %x, 15230 %hello_p = getelementptr inbounds [13 x i8], ptr @null_hello_mid, i32 0, i32 %and231 %hello_l = call i32 @strlen(ptr %hello_p)232 ret i32 %hello_l233}234 235define i32 @test1(ptr %str) {236; CHECK-LABEL: @test1(237; CHECK-NEXT: [[LEN:%.*]] = tail call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]]) #[[ATTR1:[0-9]+]]238; CHECK-NEXT: ret i32 [[LEN]]239;240 %len = tail call i32 @strlen(ptr %str) nounwind241 ret i32 %len242}243 244define i32 @test2(ptr %str) #0 {245; CHECK-LABEL: @test2(246; CHECK-NEXT: [[LEN:%.*]] = tail call i32 @strlen(ptr noundef [[STR:%.*]]) #[[ATTR1]]247; CHECK-NEXT: ret i32 [[LEN]]248;249 %len = tail call i32 @strlen(ptr %str) nounwind250 ret i32 %len251}252 253; Test cases for PR47149.254define i1 @strlen0_after_write_to_first_byte_global() {255; CHECK-LABEL: @strlen0_after_write_to_first_byte_global(256; CHECK-NEXT: store i8 49, ptr @a, align 16257; CHECK-NEXT: ret i1 false258;259 store i8 49, ptr @a, align 16260 %len = tail call i32 @strlen(ptr nonnull dereferenceable(1) @a)261 %cmp = icmp eq i32 %len, 0262 ret i1 %cmp263}264 265define i1 @strlen0_after_write_to_second_byte_global() {266; CHECK-LABEL: @strlen0_after_write_to_second_byte_global(267; CHECK-NEXT: store i8 49, ptr getelementptr inbounds nuw (i8, ptr @a, i32 1), align 16268; CHECK-NEXT: [[CHAR0:%.*]] = load i8, ptr @a, align 1269; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[CHAR0]], 0270; CHECK-NEXT: ret i1 [[CMP]]271;272 store i8 49, ptr getelementptr inbounds ([32 x i8], ptr @a, i64 0, i64 1), align 16273 %len = tail call i32 @strlen(ptr nonnull dereferenceable(1) @a)274 %cmp = icmp eq i32 %len, 0275 ret i1 %cmp276}277 278define i1 @strlen0_after_write_to_first_byte(ptr %ptr) {279; CHECK-LABEL: @strlen0_after_write_to_first_byte(280; CHECK-NEXT: store i8 49, ptr [[PTR:%.*]], align 1281; CHECK-NEXT: ret i1 false282;283 store i8 49, ptr %ptr284 %len = tail call i32 @strlen(ptr nonnull dereferenceable(1) %ptr)285 %cmp = icmp eq i32 %len, 0286 ret i1 %cmp287}288 289define i1 @strlen0_after_write_to_second_byte(ptr %ptr) {290; CHECK-LABEL: @strlen0_after_write_to_second_byte(291; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i32 1292; CHECK-NEXT: store i8 49, ptr [[GEP]], align 1293; CHECK-NEXT: [[CHAR0:%.*]] = load i8, ptr [[PTR]], align 1294; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[CHAR0]], 0295; CHECK-NEXT: ret i1 [[CMP]]296;297 %gep = getelementptr i8, ptr %ptr, i64 1298 store i8 49, ptr %gep299 %len = tail call i32 @strlen(ptr nonnull dereferenceable(1) %ptr)300 %cmp = icmp eq i32 %len, 0301 ret i1 %cmp302}303 304attributes #0 = { null_pointer_is_valid }305