[PATCH] D17973: [DAG]: Combine multiple AssertZexts separated by trunc

Hans Wennborg via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 8 15:59:44 PST 2016


hans created this revision.
hans added subscribers: rnk, llvm-commits.

(Uploading as a work-in-progress in case anyone wants to comment.)

The two AssertZexts situation arises for boolean arguments on X86_64:

  void f(bool x) {

LLVM will copy x from a 32-bit register, insert an AssertZext to capture that bits 8-31 are zero (as byte-sized arguments get extended on x86_64), and then another AssertZext to capture that bits 1-7 are also zero, because that's true for bools.

Combining the two allows us to optimize this code:

  void g(bool);
  void f(bool x) {
    g(x);
  }

Previously:

  movzbl  %dil, %edi
  jmp     _Z1gb

After my patch, no zero-extension is generated, as the value in %edi was already extended by the caller.

This raises a number of questions, though:

1) Are 8- and 16-bit arguments really extended on x86_64? LLVM assumes so since http://reviews.llvm.org/rL34623, but the psABI doesn't seem to actually spell that out?

2) Are bools really extended to 32 bits on x86_64? http://reviews.llvm.org/rL127766 says they are not and "[...] We still insert an i32 ZextAssert when reading a function's arguments, but it is followed by a truncate and another i8 ZextAssert so it is not optimized." The psABI seems to have gone back and forth here(!).


My patch would break Win64, because there it's clear that a bool argument is extended only to 8 bits, not 32 bits. But from what I understand, this isn't represented well: Clang's WinX86_64ABIInfo::classify will slap a "zext" attribute on the x parameter, and we end up with both AssertZexts.

http://reviews.llvm.org/D17973

Files:
  lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -228,6 +228,7 @@
     //   otherwise              - N should be replaced by the returned Operand.
     //
     SDValue visitTokenFactor(SDNode *N);
+    SDValue visitAssertZext(SDNode *N);
     SDValue visitMERGE_VALUES(SDNode *N);
     SDValue visitADD(SDNode *N);
     SDValue visitSUB(SDNode *N);
@@ -1350,6 +1351,7 @@
   switch (N->getOpcode()) {
   default: break;
   case ISD::TokenFactor:        return visitTokenFactor(N);
+  case ISD::AssertZext:         return visitAssertZext(N);
   case ISD::MERGE_VALUES:       return visitMERGE_VALUES(N);
   case ISD::ADD:                return visitADD(N);
   case ISD::SUB:                return visitSUB(N);
@@ -1604,6 +1606,31 @@
   return Result;
 }
 
+SDValue DAGCombiner::visitAssertZext(SDNode *N) {
+  SDValue N0 = N->getOperand(0);
+  EVT VT = N->getValueType(0);
+
+  // Try to fold (assert_zext (trunc (assert_zext x t1)) t2).
+  if (N0.getOpcode() == ISD::TRUNCATE &&
+      N0.getOperand(0)->getOpcode() == ISD::AssertZext) {
+    SDValue Trunc = N0;
+    SDValue AZext1 = N0.getOperand(0);
+    EVT T1 = cast<VTSDNode>(AZext1->getOperand(1))->getVT();
+    EVT T2 = cast<VTSDNode>(N->getOperand(1))->getVT();
+
+    if (Trunc->getValueType(0) == T1 && T2.getSizeInBits() < T1.getSizeInBits()) {
+      // Trunc removes the known zeros of AZext1.
+      SDValue CombinedAssertZext =
+          DAG.getNode(ISD::AssertZext, SDLoc(N), AZext1->getValueType(0),
+                      AZext1->getOperand(0), N->getOperand(1));
+      return DAG.getNode(ISD::TRUNCATE, SDLoc(N), VT, CombinedAssertZext);
+
+    }
+  }
+
+  return SDValue();
+}
+
 /// MERGE_VALUES can always be eliminated.
 SDValue DAGCombiner::visitMERGE_VALUES(SDNode *N) {
   WorklistRemover DeadNodes(*this);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D17973.50078.patch
Type: text/x-patch
Size: 1946 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160308/d7dcd74b/attachment.bin>


More information about the llvm-commits mailing list