Index: llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp =================================================================== --- llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp +++ llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp @@ -906,7 +906,7 @@ return false; } -/// Try to expand strcmp(P, "x") calls. +/// Try to expand strcmp(P, "x"), strcmp(P, "xy") calls. static bool expandStrcmp(CallInst *CI, DominatorTree &DT, bool &MadeCFGChange) { Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); @@ -921,10 +921,10 @@ Value *NonConstantP = nullptr; StringRef ConstantStr; - if (!HasStr1 && HasStr2 && Str2.size() == 1) { + if (!HasStr1 && HasStr2 && (Str2.size() == 1 || Str2.size() == 2)) { NonConstantP = Str1P; ConstantStr = Str2; - } else if (!HasStr2 && HasStr1 && Str1.size() == 1) { + } else if (!HasStr2 && HasStr1 && (Str1.size() == 1 || Str1.size() == 2)) { NonConstantP = Str2P; ConstantStr = Str1; } else { @@ -946,6 +946,19 @@ // v1 = P[1] // dst = phi(v0, v1) // + // For strcmp(P, "xy") do the following transformation: + // + // (before) + // dst = strcmp(P, "x") + // + // (after) + // v0 = P[0] - 'x' + // [if v0 == 0] + // v1 = P[1] - 'y' + // [if v1 == 0] + // v2 = P[2] + // dst = phi(v0, v1, v2) + // IRBuilder<> B(CI->getParent()); DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); @@ -966,6 +979,8 @@ IsFirstCharacterSubZero, CI, /*Unreachable*/ false, /*BranchWeights*/ nullptr, &DTU); + BasicBlock *StrcmpExpandSubJoinBB = CI->getParent(); + B.SetInsertPoint(IsFirstCharacterSubZeroBBTerminator); B.GetInsertBlock()->setName("strcmp_expand_sub_is_zero"); BasicBlock *IsFirstCharacterSubZeroBB = B.GetInsertBlock(); @@ -973,13 +988,48 @@ B.CreateLoad(B.getInt8Ty(), B.CreateConstInBoundsGEP1_64( B.getInt8Ty(), NonConstantP, 1)), RetType); + Value *IsFirstCharacterSubZeroResult = Str1SecondCharacterValue; + + bool TwoCharacterConstantStr = ConstantStr.size() == 2; + BasicBlock *IsSecondCharacterSubZeroBB = nullptr; + Value *Str1ThirdCharacterValue = nullptr; + + if (TwoCharacterConstantStr) { + Value *Str2SecondCharacterValue = + ConstantInt::get(RetType, static_cast(ConstantStr[1])); + Value *SecondCharacterSub = + B.CreateNSWSub(Str1SecondCharacterValue, Str2SecondCharacterValue); + IsFirstCharacterSubZeroResult = SecondCharacterSub; + Value *IsSecondCharacterSubZero = + B.CreateICmpEQ(SecondCharacterSub, ConstantInt::get(RetType, 0)); + IsSecondCharacterSubZeroBB = + BasicBlock::Create(B.getContext(), "strcmp_expand_sub_is_zero", + InitialBB->getParent(), StrcmpExpandSubJoinBB); + + B.CreateCondBr(IsSecondCharacterSubZero, IsSecondCharacterSubZeroBB, + StrcmpExpandSubJoinBB); + IsFirstCharacterSubZeroBBTerminator->eraseFromParent(); + + B.SetInsertPoint(IsSecondCharacterSubZeroBB); + Str1ThirdCharacterValue = B.CreateZExt( + B.CreateLoad(B.getInt8Ty(), B.CreateConstInBoundsGEP1_64( + B.getInt8Ty(), NonConstantP, 2)), + RetType); + B.CreateBr(StrcmpExpandSubJoinBB); + + DTU.applyUpdates({{DominatorTree::Insert, IsSecondCharacterSubZeroBB, + StrcmpExpandSubJoinBB}}); + } B.SetInsertPoint(CI); - B.GetInsertBlock()->setName("strcmp_expand_sub_join"); + StrcmpExpandSubJoinBB->setName("strcmp_expand_sub_join"); - PHINode *Result = B.CreatePHI(RetType, 2); + PHINode *Result = B.CreatePHI(RetType, 2 + TwoCharacterConstantStr); Result->addIncoming(FirstCharacterSub, InitialBB); - Result->addIncoming(Str1SecondCharacterValue, IsFirstCharacterSubZeroBB); + Result->addIncoming(IsFirstCharacterSubZeroResult, IsFirstCharacterSubZeroBB); + + if (TwoCharacterConstantStr) + Result->addIncoming(Str1ThirdCharacterValue, IsSecondCharacterSubZeroBB); CI->replaceAllUsesWith(Result); CI->eraseFromParent(); Index: llvm/test/Transforms/AggressiveInstCombine/strcmp.ll =================================================================== --- llvm/test/Transforms/AggressiveInstCombine/strcmp.ll +++ llvm/test/Transforms/AggressiveInstCombine/strcmp.ll @@ -209,8 +209,26 @@ define i1 @expand_strcmp_eq_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_eq_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -220,8 +238,26 @@ define i1 @expand_strcmp_ne_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_ne_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -231,8 +267,26 @@ define i1 @expand_strcmp_sgt_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sgt_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -242,8 +296,26 @@ define i1 @expand_strcmp_sge_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sge_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -253,8 +325,26 @@ define i1 @expand_strcmp_slt_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_slt_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -264,8 +354,26 @@ define i1 @expand_strcmp_sle_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sle_s2( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) -; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[CALL]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] +; CHECK: strcmp_expand_sub_is_zero: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 +; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_is_zero1: +; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 +; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] +; CHECK: strcmp_expand_sub_join: +; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[TMP13]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2)