From 983cfca15dab3fb1731fb3c970f9d058173d8ef3 Mon Sep 17 00:00:00 2001 From: James Molloy Date: Wed, 2 Sep 2015 17:25:25 +0000 Subject: [PATCH] [ValueTracking] Look through casts when both operands are casts. We only looked through casts when one operand was a constant. We can also look through casts when both operands are non-constant, but both are in fact the same cast type. For example: %1 = icmp ult i8 %a, %b %2 = zext i8 %a to i32 %3 = zext i8 %b to i32 %4 = select i1 %1, i32 %2, i32 %3 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246678 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ValueTracking.cpp | 22 ++++++++++--- unittests/Analysis/ValueTrackingTest.cpp | 42 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 352b0fbd4dc..7de719579ad 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3750,14 +3750,26 @@ static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, return {SPF_UNKNOWN, SPNB_NA, false}; } -static Constant *lookThroughCast(CmpInst *CmpI, Value *V1, Value *V2, - Instruction::CastOps *CastOp) { +static Value *lookThroughCast(CmpInst *CmpI, Value *V1, Value *V2, + Instruction::CastOps *CastOp) { CastInst *CI = dyn_cast(V1); Constant *C = dyn_cast(V2); - if (!CI || !C) + CastInst *CI2 = dyn_cast(V2); + if (!CI) return nullptr; *CastOp = CI->getOpcode(); + if (CI2) { + // If V1 and V2 are both the same cast from the same type, we can look + // through V1. + if (CI2->getOpcode() == CI->getOpcode() && + CI2->getSrcTy() == CI->getSrcTy()) + return CI2->getOperand(0); + return nullptr; + } else if (!C) { + return nullptr; + } + if (isa(CI) && CmpI->isSigned()) { Constant *T = ConstantExpr::getTrunc(C, CI->getSrcTy()); // This is only valid if the truncated value can be sign-extended @@ -3817,11 +3829,11 @@ SelectPatternResult llvm::matchSelectPattern(Value *V, // Deal with type mismatches. if (CastOp && CmpLHS->getType() != TrueVal->getType()) { - if (Constant *C = lookThroughCast(CmpI, TrueVal, FalseVal, CastOp)) + if (Value *C = lookThroughCast(CmpI, TrueVal, FalseVal, CastOp)) return ::matchSelectPattern(Pred, FMF, CmpLHS, CmpRHS, cast(TrueVal)->getOperand(0), C, LHS, RHS); - if (Constant *C = lookThroughCast(CmpI, FalseVal, TrueVal, CastOp)) + if (Value *C = lookThroughCast(CmpI, FalseVal, TrueVal, CastOp)) return ::matchSelectPattern(Pred, FMF, CmpLHS, CmpRHS, C, cast(FalseVal)->getOperand(0), LHS, RHS); diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp index b5ad01968b9..1512ad0fd86 100644 --- a/unittests/Analysis/ValueTrackingTest.cpp +++ b/unittests/Analysis/ValueTrackingTest.cpp @@ -146,3 +146,45 @@ TEST_F(MatchSelectPatternTest, FMinConstantZeroNsz) { // But this should be, because we've ignored signed zeroes. expectPattern({SPF_FMINNUM, SPNB_RETURNS_OTHER, true}); } + +TEST_F(MatchSelectPatternTest, DoubleCastU) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp ult i8 %a, %b\n" + " %2 = zext i8 %a to i32\n" + " %3 = zext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // We should be able to look through the situation where we cast both operands + // to the select. + expectPattern({SPF_UMIN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, DoubleCastS) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp slt i8 %a, %b\n" + " %2 = sext i8 %a to i32\n" + " %3 = sext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // We should be able to look through the situation where we cast both operands + // to the select. + expectPattern({SPF_SMIN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, DoubleCastBad) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp ult i8 %a, %b\n" + " %2 = zext i8 %a to i32\n" + " %3 = sext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // We should be able to look through the situation where we cast both operands + // to the select. + expectPattern({SPF_UNKNOWN, SPNB_NA, false}); +} -- 2.34.1