[DAGCombine] fold (X >>?,exact C1) << C2 --> X << (C2-C1)
authorBenjamin Kramer <benny.kra@googlemail.com>
Fri, 26 Jun 2015 14:51:36 +0000 (14:51 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Fri, 26 Jun 2015 14:51:36 +0000 (14:51 +0000)
Instcombine also does this but many opportunities only become visible
after GEPs are lowered.

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

lib/CodeGen/SelectionDAG/DAGCombiner.cpp
test/CodeGen/X86/shift-combine.ll

index 8e0e0fe28220c35a4932468161a41f0425e6e37d..8388a95b8cf6c23c36c9cb9a9d44c4a6aa51fa12 100644 (file)
@@ -4362,6 +4362,22 @@ SDValue DAGCombiner::visitSHL(SDNode *N) {
     }
   }
 
+  // fold (shl (sr[la] exact X,  C1), C2) -> (shl    X, (C2-C1)) if C1 <= C2
+  // fold (shl (sr[la] exact X,  C1), C2) -> (sr[la] X, (C2-C1)) if C1  > C2
+  if (N1C && (N0.getOpcode() == ISD::SRL || N0.getOpcode() == ISD::SRA) &&
+      cast<BinaryWithFlagsSDNode>(N0)->Flags.hasExact()) {
+    if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) {
+      uint64_t C1 = N0C1->getZExtValue();
+      uint64_t C2 = N1C->getZExtValue();
+      SDLoc DL(N);
+      if (C1 <= C2)
+        return DAG.getNode(ISD::SHL, DL, VT, N0.getOperand(0),
+                           DAG.getConstant(C2 - C1, DL, N1.getValueType()));
+      return DAG.getNode(N0.getOpcode(), DL, VT, N0.getOperand(0),
+                         DAG.getConstant(C1 - C2, DL, N1.getValueType()));
+    }
+  }
+
   // fold (shl (srl x, c1), c2) -> (and (shl x, (sub c2, c1), MASK) or
   //                               (and (srl x, (sub c1, c2), MASK)
   // Only fold this if the inner shift has no other uses -- if it does, folding
index ec62bcdcdba1b1f73b76a6e649c2d16668c7af3c..7fb19a6cad056c3fb699bb472e2c26617a2e6900 100644 (file)
@@ -17,3 +17,52 @@ entry:
   ret i32 %tmp5
 }
 
+define i32* @test_exact1(i32 %a, i32 %b, i32* %x)  {
+; CHECK-LABEL: test_exact1:
+; CHECK: sarl %
+
+  %sub = sub i32 %b, %a
+  %shr = ashr exact i32 %sub, 3
+  %gep = getelementptr inbounds i32, i32* %x, i32 %shr
+  ret i32* %gep
+}
+
+define i32* @test_exact2(i32 %a, i32 %b, i32* %x)  {
+; CHECK-LABEL: test_exact2:
+; CHECK: sarl %
+
+  %sub = sub i32 %b, %a
+  %shr = ashr exact i32 %sub, 3
+  %gep = getelementptr inbounds i32, i32* %x, i32 %shr
+  ret i32* %gep
+}
+
+define i32* @test_exact4(i32 %a, i32 %b, i32* %x)  {
+; CHECK-LABEL: test_exact4:
+; CHECK: shrl %
+
+  %sub = sub i32 %b, %a
+  %shr = lshr exact i32 %sub, 3
+  %gep = getelementptr inbounds i32, i32* %x, i32 %shr
+  ret i32* %gep
+}
+
+define i32* @test_exact5(i32 %a, i32 %b, i32* %x)  {
+; CHECK-LABEL: test_exact5:
+; CHECK: shrl %
+
+  %sub = sub i32 %b, %a
+  %shr = lshr exact i32 %sub, 3
+  %gep = getelementptr inbounds i32, i32* %x, i32 %shr
+  ret i32* %gep
+}
+
+define i32* @test_exact6(i32 %a, i32 %b, i32* %x)  {
+; CHECK-LABEL: test_exact6:
+; CHECK-NOT: shrl
+
+  %sub = sub i32 %b, %a
+  %shr = lshr exact i32 %sub, 2
+  %gep = getelementptr inbounds i32, i32* %x, i32 %shr
+  ret i32* %gep
+}