Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp (revision 137196) +++ lib/Transforms/InstCombine/InstructionCombining.cpp (working copy) @@ -107,8 +107,89 @@ return true; } +// Return true, if NO Signed Wrap should be maintained for I. +// PreCondition - The operation 'B (I.getOpcode) C' has been simplified to 'V' +// +// This function then checks the following +// 1. If 'B', 'C' and 'V' are all ConstantInts +// 2. If so, Perform checks to see if 'V' overflows +// a) If either of B or C is zero then there is no overflow; return True. +// b) If B and C have the same sign +// -> if Opcode = Add, then +// -> if B>0 && V if B<0 && V>B, overflow occurred; return false. +// -> if Opcode = Sub, then +// -> No overflow can occur in this case; return true. +// c) If B and C do not have the same sign +// -> Need to check only for Sub. The checks are the same as Add above +// because sub changes the sign of C in (B - C). +// +static bool MaintainNoSignedWrap (BinaryOperator &I, Value *B, Value *C, Value *V) { + Instruction::BinaryOps Opcode = I.getOpcode(); + OverflowingBinaryOperator *OBO = dyn_cast(&I); + if (!OBO || !OBO->hasNoSignedWrap()) { + return false; + } + if (!isa(B) || !isa(C) || !isa(V)) { + return false; + } + + if (!I.isAssociative()) { + return false; + } + + // We will not reason about Mul for now. + if (Opcode == Instruction::Mul) { + return false; + } + + ConstantInt *CV = dyn_cast(V); + ConstantInt *CB = dyn_cast(B); + ConstantInt *CC = dyn_cast(C); + + if (!CV || !CB || !CC) { + return false; + } + + const APInt &VVal = CV->getValue(); + const APInt &BVal = CB->getValue(); + const APInt &CVal = CC->getValue(); + + // If Either constant is 0, Signed Wrap cannot occur. + if ((BVal == 0) || (CVal == 0)) { + return true; + } + + // Point b above. + if ((BVal.isStrictlyPositive() && CVal.isStrictlyPositive()) || + (BVal.isNegative() && CVal.isNegative())) { + if (Opcode == Instruction::Add) { + if (BVal.isStrictlyPositive() && VVal.slt(BVal)) + return false; + else if (BVal.isNegative() && VVal.sgt(BVal)) + return false; + return true; + } + else if (Opcode == Instruction::Sub) { + // No Overflow can occur if the Opcode is a Sub and the signs are the + // same. + return true; + } + } + // B and C do not have the same sign. Need to check only for sub. + // i.e. Point c above. + else if (Opcode == Instruction::Sub) { + // The effect of the sub is to change the sign of C. + if (BVal.isStrictlyPositive() && VVal.slt(BVal)) + return false; + if (BVal.isNegative() && VVal.sgt(BVal)) + return false; + return true; + } + return false; +} /// SimplifyAssociativeOrCommutative - This performs a few simplifications for /// operators which are associative or commutative: // @@ -159,7 +240,13 @@ I.setOperand(1, V); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. - I.clearSubclassOptionalData(); + if (MaintainNoSignedWrap (I, B, C, V)) { + I.clearSubclassOptionalData(); + I.setHasNoSignedWrap (true); + } + else + I.clearSubclassOptionalData(); + Changed = true; ++NumReassoc; continue; @@ -248,7 +335,14 @@ I.setOperand(1, Folded); // Conservatively clear the optional flags, since they may not be // preserved by the reassociation. - I.clearSubclassOptionalData(); + if (MaintainNoSignedWrap (I, C1, C2, Folded)) { + I.clearSubclassOptionalData(); + I.setHasNoSignedWrap (true); + cast(New)->setHasNoSignedWrap (true); + } + else + I.clearSubclassOptionalData(); + Changed = true; continue; }