Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -563,6 +563,52 @@ return B.CreateZExt(B.CreateLoad(B.getInt8Ty(), Str1P, "strcmpload"), CI->getType()); + // Fold strcmp(P, "x"), strcmp(P, "xx") + if (HasStr2 && (Str2.size() == 1 || Str2.size() == 2)) { + if (Str2.size() == 2) { + return nullptr; + } + + BasicBlock *InsertBB = B.GetInsertBlock(); + + /// Split basic block before and after strcmp call + BasicBlock *JoinBB = InsertBB->splitBasicBlock(CI, "strcmp_fold_sub_join"); + + // Erase br instruction + InsertBB->erase(--InsertBB->end(), InsertBB->end()); + + B.SetInsertPoint(InsertBB); + Value *Str1FirstCharacterValue = B.CreateIntCast( + B.CreateLoad(B.getInt8Ty(), Str1P), B.getInt32Ty(), true); + Value *Str2FirstCharacterValue = ConstantInt::get( + B.getInt32Ty(), static_cast(Str2[0]), true); + Value *FirstCharacterSub = + B.CreateNSWSub(Str1FirstCharacterValue, Str2FirstCharacterValue); + + BasicBlock *SubIsZeroBB = + BasicBlock::Create(B.getContext(), "strcmp_fold_sub_is_zero", + InsertBB->getParent(), JoinBB); + B.CreateCondBr(B.CreateICmpEQ(FirstCharacterSub, + ConstantInt::get(B.getInt32Ty(), 0, true)), + SubIsZeroBB, JoinBB); + + B.SetInsertPoint(SubIsZeroBB); + Value *Str1SecondCharacterValue = B.CreateIntCast( + B.CreateLoad(B.getInt8Ty(), + B.CreateConstInBoundsGEP1_32(B.getInt8Ty(), Str1P, 1)), + B.getInt32Ty(), true); + B.CreateBr(JoinBB); + + B.SetInsertPoint(JoinBB); + + /// Insert PHI in join block before strcmp call + PHINode *Result = PHINode::Create(B.getInt32Ty(), 2, "", CI); + Result->addIncoming(FirstCharacterSub, InsertBB); + Result->addIncoming(Str1SecondCharacterValue, SubIsZeroBB); + + return Result; + } + // strcmp(P, "x") -> memcmp(P, "x", 2) uint64_t Len1 = GetStringLength(Str1P); if (Len1) Index: llvm/test/Transforms/InstCombine/strcmp-5.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/strcmp-5.ll @@ -0,0 +1,52 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; TODO: Test that ... +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +declare i32 @strcmp(ptr, ptr) + +@s1 = constant [2 x i8] c"0\00" +@s2 = constant [3 x i8] c"05\00" + +; Fold strcmp(C, "x"), strcmp(C, "xx"). + +define i1 @fold_strcmp_s1_1(ptr %C) { +; CHECK-LABEL: @fold_strcmp_s1_1( +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr %C, align 1 +; CHECK-NEXT: [[SEXT1:%.*]] = sext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SEXT1]], -48 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[ADD]], 0 +; CHECK-NEXT: br i1 [[CMP1]], label %strcmp_fold_sub_is_zero, label %strcmp_fold_sub_join +; CHECK-LABEL: strcmp_fold_sub_is_zero: +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr %C, i64 1 +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 +; CHECK-NEXT: [[SEXT2:%.*]] = sext i8 [[TMP3]] to i32 +; CHECK-NEXT: br label %strcmp_fold_sub_join +; CHECK-LABEL: strcmp_fold_sub_join: +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[ADD]], %0 ], [ [[SEXT2]], %strcmp_fold_sub_is_zero ] +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[PHI]], 0 +; CHECK-NEXT: ret i1 [[CMP2]] +; + %call = call i32 @strcmp(ptr %C, ptr noundef @s1) + %cmp = icmp eq i32 %call, 0 + ret i1 %cmp +} + +define i32 @fold_strcmp_s1_2(ptr %C) { +; CHECK-LABEL: @fold_strcmp_s1_2( +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr %C, align 1 +; CHECK-NEXT: [[SEXT1:%.*]] = sext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SEXT1]], -48 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[ADD]], 0 +; CHECK-NEXT: br i1 [[CMP1]], label %strcmp_fold_sub_is_zero, label %strcmp_fold_sub_join +; CHECK-LABEL: strcmp_fold_sub_is_zero: +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr %C, i64 1 +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 +; CHECK-NEXT: [[SEXT2:%.*]] = sext i8 [[TMP3]] to i32 +; CHECK-NEXT: br label %strcmp_fold_sub_join +; CHECK-LABEL: strcmp_fold_sub_join: +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[ADD]], %0 ], [ [[SEXT2]], %strcmp_fold_sub_is_zero ] +; CHECK-NEXT: ret i32 [[PHI]] +; + %call = call i32 @strcmp(ptr %C, ptr noundef @s1) + ret i32 %call +}