Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -16,6 +16,7 @@ #define LLVM_ANALYSIS_VALUETRACKING_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/Instruction.h" #include "llvm/Support/DataTypes.h" namespace llvm { @@ -275,7 +276,21 @@ }; /// Pattern match integer [SU]MIN, [SU]MAX and ABS idioms, returning the kind /// and providing the out parameter results if we successfully match. - SelectPatternFlavor matchSelectPattern(Value *V, Value *&LHS, Value *&RHS); + /// + /// If CastOp is not nullptr, also match MIN/MAX idioms where the type does + /// not match that of the original select. If this is the case, the cast + /// operation (one of Trunc,SExt,Zext) that must be done to transform the + /// type of LHS and RHS into the type of V is returned in CastOp. + /// + /// For example: + /// %1 = icmp slt i32 %a, i32 4 + /// %2 = sext i32 %a to i64 + /// %3 = select i1 %1, i64 %2, i64 4 + /// + /// -> LHS = %a, RHS = i32 4, *CastOp = Instruction::SExt + /// + SelectPatternFlavor matchSelectPattern(Value *V, Value *&LHS, Value *&RHS, + Instruction::CastOps *CastOp = nullptr); } // end namespace llvm Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3205,20 +3205,10 @@ return OverflowResult::MayOverflow; } -SelectPatternFlavor llvm::matchSelectPattern(Value *V, - Value *&LHS, Value *&RHS) { - SelectInst *SI = dyn_cast(V); - if (!SI) return SPF_UNKNOWN; - - ICmpInst *ICI = dyn_cast(SI->getCondition()); - if (!ICI) return SPF_UNKNOWN; - - ICmpInst::Predicate Pred = ICI->getPredicate(); - Value *CmpLHS = ICI->getOperand(0); - Value *CmpRHS = ICI->getOperand(1); - Value *TrueVal = SI->getTrueValue(); - Value *FalseVal = SI->getFalseValue(); - +static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, + Value *CmpLHS, Value *CmpRHS, + Value *TrueVal, Value *FalseVal, + Value *&LHS, Value *&RHS) { LHS = CmpLHS; RHS = CmpRHS; @@ -3285,3 +3275,55 @@ return SPF_UNKNOWN; } + +static Constant *lookThroughCast(ICmpInst *CmpI, Value *V1, Value *V2, + Instruction::CastOps *CastOp) { + CastInst *CI = dyn_cast(V1); + Constant *C = dyn_cast(V2); + if (!CI || !C) + return nullptr; + *CastOp = CI->getOpcode(); + + if ((isa(CI) && CmpI->isSigned()) || + (isa(CI) && CmpI->isUnsigned())) + return ConstantExpr::getTrunc(C, CI->getSrcTy()); + + if (isa(CI)) + return ConstantExpr::getIntegerCast(C, CI->getSrcTy(), CmpI->isSigned()); + + return nullptr; +} + +SelectPatternFlavor llvm::matchSelectPattern(Value *V, + Value *&LHS, Value *&RHS, + Instruction::CastOps *CastOp) { + SelectInst *SI = dyn_cast(V); + if (!SI) return SPF_UNKNOWN; + + ICmpInst *CmpI = dyn_cast(SI->getCondition()); + if (!CmpI) return SPF_UNKNOWN; + + ICmpInst::Predicate Pred = CmpI->getPredicate(); + Value *CmpLHS = CmpI->getOperand(0); + Value *CmpRHS = CmpI->getOperand(1); + Value *TrueVal = SI->getTrueValue(); + Value *FalseVal = SI->getFalseValue(); + + // Bail out early. + if (CmpI->isEquality()) + return SPF_UNKNOWN; + + // Deal with type mismatches. + if (CastOp && CmpLHS->getType() != TrueVal->getType()) { + if (Constant *C = lookThroughCast(CmpI, TrueVal, FalseVal, CastOp)) + return ::matchSelectPattern(Pred, CmpLHS, CmpRHS, + cast(TrueVal)->getOperand(0), C, + LHS, RHS); + if (Constant *C = lookThroughCast(CmpI, FalseVal, TrueVal, CastOp)) + return ::matchSelectPattern(Pred, CmpLHS, CmpRHS, + C, cast(FalseVal)->getOperand(0), + LHS, RHS); + } + return ::matchSelectPattern(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, + LHS, RHS); +}