Index: test/Transforms/InstCombine/not_nsw_preserve.ll =================================================================== --- test/Transforms/InstCombine/not_nsw_preserve.ll (revision 0) +++ test/Transforms/InstCombine/not_nsw_preserve.ll (revision 0) @@ -0,0 +1,23 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +; CHECK: @foo +; CHECK: br i1 %cmp, label %if.then, label %if.else +define i8 @foo(i8 %x) nounwind { +entry: + %retval = alloca i8, align 4 + %add = add nsw i8 %x, 127 + %add3 = add nsw i8 %add, 3 + %cmp = icmp slt i8 %add, %add3 + br i1 %cmp, label %if.then, label %if.else +if.then: + store i8 1, i8* %retval + br label %return + +if.else: + store i8 0, i8* %retval + br label %return + +return: + %0 = load i8* %retval + ret i8 %0 +} Index: test/Transforms/InstCombine/nsw_preserve.ll =================================================================== --- test/Transforms/InstCombine/nsw_preserve.ll (revision 0) +++ test/Transforms/InstCombine/nsw_preserve.ll (revision 0) @@ -0,0 +1,23 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +; CHECK: @foo +; CHECK: br i1 true, label %if.then, label %if.else +define i32 @foo(i32 %x) nounwind { +entry: + %retval = alloca i32, align 4 + %add = add nsw i32 %x, 2 + %add3 = add nsw i32 %add, 3 + %cmp = icmp slt i32 %add, %add3 + br i1 %cmp, label %if.then, label %if.else +if.then: + store i32 1, i32* %retval + br label %return + +if.else: + store i32 0, i32* %retval + br label %return + +return: + %0 = load i32* %retval + ret i32 %0 +} Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp (revision 137258) +++ lib/Transforms/InstCombine/InstructionCombining.cpp (working copy) @@ -107,8 +107,58 @@ 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) { + Instruction::BinaryOps Opcode = I.getOpcode(); + OverflowingBinaryOperator *OBO = dyn_cast(&I); + bool Overflow = false; + if (!OBO || !OBO->hasNoSignedWrap()) { + return false; + } + // We reason about Add and Sub Only. + if (Opcode != Instruction::Add && + Opcode != Instruction::Sub) { + return false; + } + ConstantInt *CB = dyn_cast(B); + ConstantInt *CC = dyn_cast(C); + + if (!CB || !CC) { + return false; + } + + const APInt &BVal = CB->getValue(); + const APInt &CVal = CC->getValue(); + + if (Opcode == Instruction::Add) { + BVal.sadd_ov (CVal, Overflow); + } + else { + BVal.ssub_ov (CVal, Overflow); + } + + return !Overflow; +} + + /// SimplifyAssociativeOrCommutative - This performs a few simplifications for /// operators which are associative or commutative: // @@ -159,7 +209,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)) { + I.clearSubclassOptionalData(); + I.setHasNoSignedWrap (true); + } + else + I.clearSubclassOptionalData(); + Changed = true; ++NumReassoc; continue; @@ -248,7 +304,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)) { + I.clearSubclassOptionalData(); + I.setHasNoSignedWrap (true); + cast(New)->setHasNoSignedWrap (true); + } + else + I.clearSubclassOptionalData(); + Changed = true; continue; }