Teach instcombine to preserve the nsw bit by doing an after-the-fact analysis
authorNick Lewycky <nicholas@mxc.ca>
Sun, 14 Aug 2011 01:45:19 +0000 (01:45 +0000)
committerNick Lewycky <nicholas@mxc.ca>
Sun, 14 Aug 2011 01:45:19 +0000 (01:45 +0000)
when combining add and sub instructions. Patch by Pranav Bhandarkar!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137570 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/InstCombine/InstructionCombining.cpp
test/Transforms/InstCombine/nsw.ll

index 5bc7b0b85391c562b52611e524fff7f37cb67c7a..85091afaf268d91956dcc051326569bee64ff633 100644 (file)
@@ -108,6 +108,44 @@ bool InstCombiner::ShouldChangeType(Type *From, Type *To) const {
   return true;
 }
 
+// Return true, if No Signed Wrap should be maintained for I.
+// The No Signed Wrap flag can be kept if the operation "B (I.getOpcode) C",
+// where both B and C should be ConstantInts, results in a constant that does
+// not overflow. This function only handles the Add and Sub opcodes. For
+// all other opcodes, the function conservatively returns false.
+static bool MaintainNoSignedWrap(BinaryOperator &I, Value *B, Value *C) {
+  OverflowingBinaryOperator *OBO = dyn_cast<OverflowingBinaryOperator>(&I);
+  if (!OBO || !OBO->hasNoSignedWrap()) {
+    return false;
+  }
+
+  // We reason about Add and Sub Only.
+  Instruction::BinaryOps Opcode = I.getOpcode();
+  if (Opcode != Instruction::Add && 
+      Opcode != Instruction::Sub) {
+    return false;
+  }
+
+  ConstantInt *CB = dyn_cast<ConstantInt>(B);
+  ConstantInt *CC = dyn_cast<ConstantInt>(C);
+
+  if (!CB || !CC) {
+    return false;
+  }
+
+  const APInt &BVal = CB->getValue();
+  const APInt &CVal = CC->getValue();
+  bool Overflow = false;
+
+  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 +197,13 @@ bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
           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;
@@ -241,14 +285,21 @@ bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
         Constant *C2 = cast<Constant>(Op1->getOperand(1));
 
         Constant *Folded = ConstantExpr::get(Opcode, C1, C2);
-        Instruction *New = BinaryOperator::Create(Opcode, A, B);
+        BinaryOperator *New = BinaryOperator::Create(Opcode, A, B);
         InsertNewInstWith(New, I);
         New->takeName(Op1);
         I.setOperand(0, New);
         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);
+          New->setHasNoSignedWrap(true);
+        } else {
+          I.clearSubclassOptionalData();
+        }
+
         Changed = true;
         continue;
       }
index 681bdc234b7d971f33523a66c6a23ac5e91ccae2..698296384ae2e78d4721c5f214013dba2332cf1f 100644 (file)
@@ -37,3 +37,19 @@ define i64 @shl1(i64 %X, i64* %P) nounwind {
   %B = shl i64 %A, 8
   ret i64 %B
 }
+
+; CHECK: @preserve1
+; CHECK: add nsw i32 %x, 5
+define i32 @preserve1(i32 %x) nounwind {
+  %add = add nsw i32 %x, 2
+  %add3 = add nsw i32 %add, 3
+  ret i32 %add3
+}
+
+; CHECK: @nopreserve1
+; CHECK: add i8 %x, -126
+define i8 @nopreserve1(i8 %x) nounwind {
+  %add = add nsw i8 %x, 127
+  %add3 = add nsw i8 %add, 3
+  ret i8 %add3
+}
\ No newline at end of file