Index: lib/Transforms/InstCombine/InstCombine.h =================================================================== --- lib/Transforms/InstCombine/InstCombine.h +++ lib/Transforms/InstCombine/InstCombine.h @@ -37,8 +37,8 @@ SPF_SMIN, SPF_UMIN, SPF_SMAX, - SPF_UMAX - // SPF_ABS - TODO. + SPF_UMAX, + SPF_ABS }; /// getComplexity: Assign a complexity or rank value to LLVM Values... Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -31,13 +31,18 @@ ICmpInst *ICI = dyn_cast(SI->getCondition()); if (!ICI) return SPF_UNKNOWN; - LHS = ICI->getOperand(0); - RHS = ICI->getOperand(1); + ICmpInst::Predicate Pred = ICI->getPredicate(); + Value *CmpLHS = ICI->getOperand(0); + Value *CmpRHS = ICI->getOperand(1); + Value *TrueVal = SI->getTrueValue(); + Value *FalseVal = SI->getFalseValue(); + + LHS = CmpLHS; + RHS = CmpRHS; // (icmp X, Y) ? X : Y - if (SI->getTrueValue() == ICI->getOperand(0) && - SI->getFalseValue() == ICI->getOperand(1)) { - switch (ICI->getPredicate()) { + if (TrueVal == CmpLHS && FalseVal == CmpRHS) { + switch (Pred) { default: return SPF_UNKNOWN; // Equality. case ICmpInst::ICMP_UGT: case ICmpInst::ICMP_UGE: return SPF_UMAX; @@ -51,18 +56,41 @@ } // (icmp X, Y) ? Y : X - if (SI->getTrueValue() == ICI->getOperand(1) && - SI->getFalseValue() == ICI->getOperand(0)) { - switch (ICI->getPredicate()) { - default: return SPF_UNKNOWN; // Equality. + if (TrueVal == CmpRHS && FalseVal == CmpLHS) { + switch (Pred) { + default: return SPF_UNKNOWN; // Equality. + case ICmpInst::ICMP_UGT: + case ICmpInst::ICMP_UGE: return SPF_UMIN; + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_SGE: return SPF_SMIN; + case ICmpInst::ICMP_ULT: + case ICmpInst::ICMP_ULE: return SPF_UMAX; + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_SLE: return SPF_SMAX; + } + } + + // (X > -1) ? X : -X + // (X > 0) ? X : -X + // (X < 0) ? -X : X + // (X < 1) ? -X : X + if (ConstantInt *C1 = dyn_cast(CmpRHS)) { + if (match(TrueVal, m_Neg(m_Specific(FalseVal))) || + match(FalseVal, m_Neg(m_Specific(TrueVal)))) { + switch (Pred) { + default: + return SPF_UNKNOWN; case ICmpInst::ICMP_UGT: - case ICmpInst::ICMP_UGE: return SPF_UMIN; case ICmpInst::ICMP_SGT: - case ICmpInst::ICMP_SGE: return SPF_SMIN; + if (CmpLHS == TrueVal && (C1->isZero() || C1->isMinusOne())) + return SPF_ABS; + break; case ICmpInst::ICMP_ULT: - case ICmpInst::ICMP_ULE: return SPF_UMAX; case ICmpInst::ICMP_SLT: - case ICmpInst::ICMP_SLE: return SPF_SMAX; + if (CmpLHS == FalseVal && (C1->isZero() || C1->isOne())) + return SPF_ABS; + break; + } } } @@ -71,7 +99,6 @@ return SPF_UNKNOWN; } - /// GetSelectFoldableOperands - We want to turn code that looks like this: /// %C = or %A, %B /// %D = select %cond, %C, %A @@ -669,6 +696,10 @@ // TODO: MIN(MIN(A, 97), 23) -> MIN(A, 23) // TODO: MAX(MAX(A, 23), 97) -> MAX(A, 97) + + // ABS(ABS(X)) -> ABS(X) + if (SPF1 == SPF_ABS && SPF2 == SPF_ABS) + return ReplaceInstUsesWith(Outer, Inner); return nullptr; } @@ -973,7 +1004,6 @@ // TODO. // ABS(-X) -> ABS(X) - // ABS(ABS(X)) -> ABS(X) } // See if we can fold the select into a phi node if the condition is a select. Index: test/Transforms/InstCombine/select.ll =================================================================== --- test/Transforms/InstCombine/select.ll +++ test/Transforms/InstCombine/select.ll @@ -1078,4 +1078,94 @@ ret i32 %retval ; CHECK-LABEL: @test71( ; CHECK: ret i32 %cond +} + +define i32 @abs_abs_x1(i32 %x) { + %ispos = icmp sgt i32 %x, -1 + %neg = sub i32 0, %x + %cond = select i1 %ispos, i32 %x, i32 %neg + %sub = sub nsw i32 0, %cond + %ispos2 = icmp sgt i32 %sub, -1 + %1 = select i1 %ispos2, i32 %sub, i32 %cond + ret i32 %1 +; CHECK-LABEL: @abs_abs_x1( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 %x, i32 [[NEG]] +; CHECK-NEXT: ret i32 [[SEL]] +} + +define i32 @abs_abs_x2(i32 %x) { + %cmp = icmp sgt i32 %x, -1 + %sub = sub nsw i32 0, %x + %cond = select i1 %cmp, i32 %x, i32 %sub + %cmp1 = icmp sgt i32 %cond, -1 + %sub4 = sub nsw i32 0, %cond + %cond6 = select i1 %cmp1, i32 %cond, i32 %sub4 + ret i32 %cond6 +; CHECK-LABEL: @abs_abs_x2( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub nsw i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 %x, i32 [[NEG]] +; CHECK-NEXT: ret i32 [[SEL]] +} + +define i32 @abs_abs_x3(i32 %x) { + %cmp = icmp sgt i32 %x, -1 + %sub = sub nsw i32 0, %x + %cond = select i1 %cmp, i32 %x, i32 %sub + %sub1 = sub nsw i32 0, %cond + %cmp2 = icmp sgt i32 %cond, 0 + %cond7 = select i1 %cmp2, i32 %cond, i32 %sub1 + ret i32 %cond7 +; CHECK-LABEL: @abs_abs_x3( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub nsw i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 %x, i32 [[NEG]] +; CHECK-NEXT: ret i32 [[SEL]] +} + +define i32 @abs_abs_x4(i32 %x) { + %cmp = icmp sgt i32 %x, -1 + %sub = sub nsw i32 0, %x + %cond = select i1 %cmp, i32 %x, i32 %sub + %cmp1 = icmp slt i32 %cond, 0 + %sub3 = sub nsw i32 0, %cond + %cond6 = select i1 %cmp1, i32 %sub3, i32 %cond + ret i32 %cond6 +; CHECK-LABEL: @abs_abs_x4( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp sgt i32 %x, -1 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub nsw i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 %x, i32 [[NEG]] +; CHECK-NEXT: ret i32 [[SEL]] +} + +define i32 @abs_abs_x5(i32 %x) { + %cmp = icmp slt i32 %x, 0 + %sub = sub nsw i32 0, %x + %cond = select i1 %cmp, i32 %sub, i32 %x + %cmp1 = icmp sgt i32 %cond, -1 + %sub4 = sub nsw i32 0, %cond + %cond6 = select i1 %cmp1, i32 %cond, i32 %sub4 + ret i32 %cond6 +; CHECK-LABEL: @abs_abs_x5( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp slt i32 %x, 0 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub nsw i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 [[NEG]], i32 %x +; CHECK-NEXT: ret i32 [[SEL]] +} + +define i32 @abs_abs_x6(i32 %x) { + %cmp = icmp slt i32 %x, 0 + %sub = sub nsw i32 0, %x + %cond = select i1 %cmp, i32 %sub, i32 %x + %cmp1 = icmp slt i32 %cond, 0 + %sub3 = sub nsw i32 0, %cond + %cond6 = select i1 %cmp1, i32 %sub3, i32 %cond + ret i32 %cond6 +; CHECK-LABEL: @abs_abs_x6( +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp slt i32 %x, 0 +; CHECK-NEXT: [[NEG:%[a-z0-9]+]] = sub nsw i32 0, %x +; CHECK-NEXT: [[SEL:%[a-z0-9]+]] = select i1 [[CMP]], i32 [[NEG]], i32 %x +; CHECK-NEXT: ret i32 [[SEL]] } \ No newline at end of file