[llvm-commits] [PATCH] Patch (WIP) to custom-lower 64-bit relational comparisons on x86-32

Eli Friedman eli.friedman at gmail.com
Wed Feb 16 16:25:14 PST 2011


Example of what the attached patch does (x86-32):

C code:
int foo();
int bar(long long x, long long y) { if (x < y) foo(); }

Current generated code:
	subl	$12, %esp
	movl	16(%esp), %eax
	movl	20(%esp), %ecx
	cmpl	24(%esp), %eax
	setae	%al
	cmpl	28(%esp), %ecx
	setge	%cl
	je	.LBB0_2
	movb	%cl, %al
.LBB0_2:
	testb	%al, %al
	jne	.LBB0_4
	calll	foo
.LBB0_4:
	addl	$12, %esp
	ret

New generated code:
	subl	$12, %esp
	movl	16(%esp), %eax
	movl	20(%esp), %ecx
	subl	24(%esp), %eax
	sbbl	28(%esp), %ecx
	jge	.LBB0_2
	calll	foo
.LBB0_2:
	addl	$12, %esp
	ret

I initially wrote this patch a couple years ago, but the backend
choked on it before some recent changes.

The reason this works is that on x86, comparisons are fundamentally
just subtraction.  So to do a wide comparison, all that is necessary
is to split the subtraction, and use the flag results of the top half.
 A bit of trickiness is required because the ZF flag isn't set in a
useful way, but that's straightforward to solve: don't lower equality
comparisons with this method and commute other comparisons that look
at the ZF flag.

I'm mainly looking for feedback as to whether this seems like
generally a good idea... I haven't seen any compiler use this
particular implementation of relational comparisons.

-Eli
-------------- next part --------------
Index: X86/X86ISelLowering.cpp
===================================================================
--- X86/X86ISelLowering.cpp	(revision 125651)
+++ X86/X86ISelLowering.cpp	(working copy)
@@ -446,6 +446,7 @@
   setOperationAction(ISD::SETCC           , MVT::i8   , Custom);
   setOperationAction(ISD::SETCC           , MVT::i16  , Custom);
   setOperationAction(ISD::SETCC           , MVT::i32  , Custom);
+  setOperationAction(ISD::SETCC           , MVT::i64  , Custom);
   setOperationAction(ISD::SETCC           , MVT::f32  , Custom);
   setOperationAction(ISD::SETCC           , MVT::f64  , Custom);
   setOperationAction(ISD::SETCC           , MVT::f80  , Custom);
@@ -7402,6 +7403,38 @@
   if (X86CC == X86::COND_INVALID)
     return SDValue();
 
+  if (!Subtarget->is64Bit() && Op0.getValueType() == MVT::i64) {
+    if (X86CC == X86::COND_E || X86CC == X86::COND_NE)
+      return SDValue();
+    if (X86CC == X86::COND_A) {
+      X86CC = X86::COND_B;
+      std::swap(Op0, Op1);
+    } else if (X86CC == X86::COND_BE) {
+      X86CC = X86::COND_AE;
+      std::swap(Op0, Op1);
+    } else if (X86CC == X86::COND_G) {
+      X86CC = X86::COND_L;
+      std::swap(Op0, Op1);
+    } else if (X86CC == X86::COND_LE) {
+      X86CC = X86::COND_GE;
+      std::swap(Op0, Op1);
+    }
+    SDValue Op0Low = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
+                                 Op0, DAG.getIntPtrConstant(0));
+    SDValue Op1Low = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
+                                 Op1, DAG.getIntPtrConstant(0));
+    SDValue Op0High = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
+                                  Op0, DAG.getIntPtrConstant(1));
+    SDValue Op1High = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
+                                  Op1, DAG.getIntPtrConstant(1));
+    SDValue res1, res2;
+    SDVTList VTList = DAG.getVTList(MVT::i32, MVT::i32);
+    res1 = SDValue(DAG.getNode(X86ISD::SUB, dl, VTList, Op0Low, Op1Low).getNode(), 1);
+    res2 = SDValue(DAG.getNode(X86ISD::SBB, dl, VTList, Op0High, Op1High, res1).getNode(), 1);
+    return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
+                       DAG.getConstant(X86CC, MVT::i8), res2);
+  }
+
   SDValue EFLAGS = EmitCmp(Op0, Op1, X86CC, DAG);
   return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
                      DAG.getConstant(X86CC, MVT::i8), EFLAGS);


More information about the llvm-commits mailing list