[ValueTracking] Look through casts when both operands are casts.
authorJames Molloy <james.molloy@arm.com>
Wed, 2 Sep 2015 17:25:25 +0000 (17:25 +0000)
committerJames Molloy <james.molloy@arm.com>
Wed, 2 Sep 2015 17:25:25 +0000 (17:25 +0000)
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
unittests/Analysis/ValueTrackingTest.cpp

index 352b0fbd4dcb25a815fd7b6f06a7562d50f2cd89..7de719579ad19bd43d82b340142b555f319293e1 100644 (file)
@@ -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<CastInst>(V1);
   Constant *C = dyn_cast<Constant>(V2);
-  if (!CI || !C)
+  CastInst *CI2 = dyn_cast<CastInst>(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<SExtInst>(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<CastInst>(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<CastInst>(FalseVal)->getOperand(0),
                                   LHS, RHS);
index b5ad01968b96911ac47188b594c74feebe7c7a2c..1512ad0fd868ec7758831fb49559f2cb7dfc1379 100644 (file)
@@ -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});
+}