summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/Scalar/EarlyCSE.cpp27
-rw-r--r--test/Transforms/EarlyCSE/commute.ll49
2 files changed, 54 insertions, 22 deletions
diff --git a/lib/Transforms/Scalar/EarlyCSE.cpp b/lib/Transforms/Scalar/EarlyCSE.cpp
index 1066dc33007..11bf8ee733c 100644
--- a/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -27,6 +27,7 @@
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -142,6 +143,19 @@ unsigned DenseMapInfo<SimpleValue>::getHashValue(SimpleValue Val) {
return hash_combine(Inst->getOpcode(), Pred, LHS, RHS);
}
+ // Hash min/max (cmp + select) to allow for commuted operands, non-canonical
+ // compare predicate (eg, the compare for smin may use 'sgt' rather than
+ // 'slt'), and non-canonical operands in the compare.
+ Value *A, *B;
+ SelectPatternFlavor SPF = matchSelectPattern(Inst, A, B).Flavor;
+ // TODO: We should also detect abs and FP min/max.
+ if (SPF == SPF_SMIN || SPF == SPF_SMAX ||
+ SPF == SPF_UMIN || SPF == SPF_UMAX) {
+ if (A > B)
+ std::swap(A, B);
+ return hash_combine(Inst->getOpcode(), SPF, A, B);
+ }
+
if (CastInst *CI = dyn_cast<CastInst>(Inst))
return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
@@ -200,6 +214,19 @@ bool DenseMapInfo<SimpleValue>::isEqual(SimpleValue LHS, SimpleValue RHS) {
LHSCmp->getSwappedPredicate() == RHSCmp->getPredicate();
}
+ // Min/max can occur with commuted operands, non-canonical predicates, and/or
+ // non-canonical operands.
+ Value *LHSA, *LHSB;
+ SelectPatternFlavor LSPF = matchSelectPattern(LHSI, LHSA, LHSB).Flavor;
+ // TODO: We should also detect abs and FP min/max.
+ if (LSPF == SPF_SMIN || LSPF == SPF_SMAX ||
+ LSPF == SPF_UMIN || LSPF == SPF_UMAX) {
+ Value *RHSA, *RHSB;
+ SelectPatternFlavor RSPF = matchSelectPattern(RHSI, RHSA, RHSB).Flavor;
+ return (LSPF == RSPF && ((LHSA == RHSA && LHSB == RHSB) ||
+ (LHSA == RHSB && LHSB == RHSA)));
+ }
+
return false;
}
diff --git a/test/Transforms/EarlyCSE/commute.ll b/test/Transforms/EarlyCSE/commute.ll
index dcdcdae6465..3adee77ec3d 100644
--- a/test/Transforms/EarlyCSE/commute.ll
+++ b/test/Transforms/EarlyCSE/commute.ll
@@ -78,8 +78,7 @@ define i8 @smin_commute(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %b, %a
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT: [[R:%.*]] = mul i8 [[M1]], [[M2]]
+; CHECK-NEXT: [[R:%.*]] = mul i8 [[M1]], [[M1]]
; CHECK-NEXT: ret i8 [[R]]
;
%cmp1 = icmp slt i8 %a, %b
@@ -97,9 +96,7 @@ define i1 @smin_swapped(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[M2]], [[M1]]
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 true
;
%cmp1 = icmp sgt i8 %a, %b
%cmp2 = icmp slt i8 %a, %b
@@ -114,9 +111,7 @@ define i8 @smax_commute(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %b, %a
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[M2]], [[M1]]
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
%cmp1 = icmp sgt i8 %a, %b
%cmp2 = icmp sgt i8 %b, %a
@@ -131,9 +126,7 @@ define i8 @smax_swapped(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[M1]], [[M2]]
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 1
;
%cmp1 = icmp slt i8 %a, %b
%cmp2 = icmp sgt i8 %a, %b
@@ -148,9 +141,7 @@ define i8 @umin_commute(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %b, %a
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT: [[R:%.*]] = sub i8 [[M2]], [[M1]]
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
%cmp1 = icmp ult i8 %a, %b
%cmp2 = icmp ult i8 %b, %a
@@ -167,9 +158,7 @@ define <2 x i8> @umin_swapped(<2 x i8> %a, <2 x i8> %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i8> %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult <2 x i8> %a, %b
; CHECK-NEXT: [[M1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> %b, <2 x i8> %a
-; CHECK-NEXT: [[M2:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> %a, <2 x i8> %b
-; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[M2]], [[M1]]
-; CHECK-NEXT: ret <2 x i8> [[R]]
+; CHECK-NEXT: ret <2 x i8> zeroinitializer
;
%cmp1 = icmp ugt <2 x i8> %a, %b
%cmp2 = icmp ult <2 x i8> %a, %b
@@ -184,9 +173,7 @@ define i8 @umax_commute(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %b, %a
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT: [[R:%.*]] = udiv i8 [[M1]], [[M2]]
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 1
;
%cmp1 = icmp ugt i8 %a, %b
%cmp2 = icmp ugt i8 %b, %a
@@ -201,8 +188,7 @@ define i8 @umax_swapped(i8 %a, i8 %b) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT: [[R:%.*]] = add i8 [[M2]], [[M1]]
+; CHECK-NEXT: [[R:%.*]] = add i8 [[M1]], [[M1]]
; CHECK-NEXT: ret i8 [[R]]
;
%cmp1 = icmp ult i8 %a, %b
@@ -213,3 +199,22 @@ define i8 @umax_swapped(i8 %a, i8 %b) {
ret i8 %r
}
+; Min/max may exist with non-canonical operands. Value tracking can match those.
+
+define i8 @smax_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: @smax_nsw(
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 %a, %b
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 [[SUB]], 0
+; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 0, i8 [[SUB]]
+; CHECK-NEXT: ret i8 0
+;
+ %sub = sub nsw i8 %a, %b
+ %cmp1 = icmp slt i8 %a, %b
+ %cmp2 = icmp sgt i8 %sub, 0
+ %m1 = select i1 %cmp1, i8 0, i8 %sub
+ %m2 = select i1 %cmp2, i8 %sub, i8 0
+ %r = sub i8 %m2, %m1
+ ret i8 %r
+}
+