[llvm] r232572 - DAGCombiner: fold (xor (shl 1, x), -1) -> (rotl ~1, x)

David Majnemer david.majnemer at gmail.com
Tue Mar 17 17:03:37 PDT 2015


Author: majnemer
Date: Tue Mar 17 19:03:36 2015
New Revision: 232572

URL: http://llvm.org/viewvc/llvm-project?rev=232572&view=rev
Log:
DAGCombiner: fold (xor (shl 1, x), -1) -> (rotl ~1, x)

Targets which provide a rotate make it possible to replace a sequence of
(XOR (SHL 1, x), -1) with (ROTL ~1, x).  This saves an instruction on
architectures like X86 and POWER(64).

Differential Revision: http://reviews.llvm.org/D8350

Modified:
    llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
    llvm/trunk/test/CodeGen/X86/xor.ll

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=232572&r1=232571&r2=232572&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Tue Mar 17 19:03:36 2015
@@ -3980,6 +3980,32 @@ SDValue DAGCombiner::visitXOR(SDNode *N)
   if (N0 == N1)
     return tryFoldToZero(SDLoc(N), TLI, VT, DAG, LegalOperations, LegalTypes);
 
+  // fold (xor (shl 1, x), -1) -> (rotl ~1, x)
+  // Here is a concrete example of this equivalence:
+  // i16   x ==  14
+  // i16 shl ==   1 << 14  == 16384 == 0b0100000000000000
+  // i16 xor == ~(1 << 14) == 49151 == 0b1011111111111111
+  //
+  // =>
+  //
+  // i16     ~1      == 0b1111111111111110
+  // i16 rol(~1, 14) == 0b1011111111111111
+  //
+  // Some additional tips to help conceptualize this transform:
+  // - Try to see the operation as placing a single zero in a value of all ones.
+  // - There exists no value for x which would allow the result to contain zero.
+  // - Values of x larger than the bitwidth are undefined and do not require a
+  //   consistent result.
+  // - Pushing the zero left requires shifting one bits in from the right.
+  // A rotate left of ~1 is a nice way of achieving the desired result.
+  if (TLI.isOperationLegalOrCustom(ISD::ROTL, VT))
+    if (auto *N1C = dyn_cast<ConstantSDNode>(N1.getNode()))
+      if (N0.getOpcode() == ISD::SHL)
+        if (auto *ShlLHS = dyn_cast<ConstantSDNode>(N0.getOperand(0)))
+          if (N1C->isAllOnesValue() && ShlLHS->isOne())
+            return DAG.getNode(ISD::ROTL, SDLoc(N), VT, DAG.getConstant(~1, VT),
+                               N0.getOperand(1));
+
   // Simplify: xor (op x...), (op y...)  -> (op (xor x, y))
   if (N0.getOpcode() == N1.getOpcode()) {
     SDValue Tmp = SimplifyBinOpWithSameOpcodeHands(N);

Modified: llvm/trunk/test/CodeGen/X86/xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/xor.ll?rev=232572&r1=232571&r2=232572&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/xor.ll (original)
+++ llvm/trunk/test/CodeGen/X86/xor.ll Tue Mar 17 19:03:36 2015
@@ -181,3 +181,15 @@ define i32 @PR17487(i1 %tobool) {
 ; X32-LABEL: PR17487:
 ; X32: andn
 }
+
+define i32 @test11(i32 %b) {
+  %shl = shl i32 1, %b
+  %neg = xor i32 %shl, -1
+  ret i32 %neg
+; X64-LABEL: test11:
+; X64: movl    $-2, %[[REG:.*]]
+; X64: roll    %{{.*}}, %[[REG]]
+; X32-LABEL: test11:
+; X32: movl    $-2, %[[REG:.*]]
+; X32: roll    %{{.*}}, %[[REG]]
+}





More information about the llvm-commits mailing list