if (RHS->isAllOnesValue())
return BinaryOperator::CreateNeg(Op0);
- // -X/C -> X/-C
- if (Value *LHSNeg = dyn_castNegVal(Op0))
- return BinaryOperator::CreateSDiv(LHSNeg, ConstantExpr::getNeg(RHS));
+ ConstantInt *RHSNeg = cast<ConstantInt>(ConstantExpr::getNeg(RHS));
+
+ // -X/C -> X/-C, if and only if negation doesn't overflow.
+ if ((RHS->getSExtValue() < 0 &&
+ RHS->getSExtValue() < RHSNeg->getSExtValue()) ||
+ (RHS->getSExtValue() > 0 &&
+ RHS->getSExtValue() > RHSNeg->getSExtValue())) {
+ if (Value *LHSNeg = dyn_castNegVal(Op0)) {
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(LHSNeg)) {
+ ConstantInt *CINeg = cast<ConstantInt>(ConstantExpr::getNeg(CI));
+
+ if ((CI->getSExtValue() < 0 &&
+ CI->getSExtValue() < CINeg->getSExtValue()) ||
+ (CI->getSExtValue() > 0 &&
+ CI->getSExtValue() > CINeg->getSExtValue()))
+ return BinaryOperator::CreateSDiv(LHSNeg,
+ ConstantExpr::getNeg(RHS));
+ }
+ }
+ }
}
// If the sign bits of both operands are zero (i.e. we can prove they are
;
; RUN: llvm-as < %s | opt -instcombine | llvm-dis | \
-; RUN: grep -v {sub i19 %Cok, %Bok} | not grep sub
+; RUN: grep -v {sub i19 %Cok, %Bok} | grep -v {sub i25 0, %Aok} | not grep sub
; END.
define i23 @test1(i23 %A) {
ret i51 %Y
}
-define i25 @test17(i25 %A) {
- %B = sub i25 0, %A ; <i25> [#uses=1]
+; Can't fold subtract here because negation it might oveflow.
+; PR3142
+define i25 @test17(i25 %Aok) {
+ %B = sub i25 0, %Aok ; <i25> [#uses=1]
%C = sdiv i25 %B, 1234 ; <i25> [#uses=1]
ret i25 %C
}
--- /dev/null
+; RUN: llvm-as < %s | opt -instcombine -inline | llvm-dis | grep {715827882} | count 2
+; PR3142
+
+define i32 @a(i32 %X) nounwind readnone {
+entry:
+ %0 = sub i32 0, %X
+ %1 = sdiv i32 %0, -3
+ ret i32 %1
+}
+
+define i32 @b(i32 %X) nounwind readnone {
+entry:
+ %0 = call i32 @a(i32 -2147483648)
+ ret i32 %0
+}
+
+define i32 @c(i32 %X) nounwind readnone {
+entry:
+ %0 = sub i32 0, -2147483648
+ %1 = sdiv i32 %0, -3
+ ret i32 %1
+}
; This test makes sure that these instructions are properly eliminated.
;
; RUN: llvm-as < %s | opt -instcombine | llvm-dis | \
-; RUN: grep -v {sub i32 %Cok, %Bok} | not grep sub
+; RUN: grep -v {sub i32 %Cok, %Bok} | grep -v {sub i32 0, %Aok} | not grep sub
define i32 @test1(i32 %A) {
%B = sub i32 %A, %A ; <i32> [#uses=1]
ret i32 %Y
}
-define i32 @test17(i32 %A) {
- %B = sub i32 0, %A ; <i32> [#uses=1]
+; Can't fold subtract here because negation it might oveflow.
+; PR3142
+define i32 @test17(i32 %Aok) {
+ %B = sub i32 0, %Aok ; <i32> [#uses=1]
%C = sdiv i32 %B, 1234 ; <i32> [#uses=1]
ret i32 %C
}