[PATCH] Handle __builtin_expect in gimple_boolify (PR middle-end/42233)

Jakub Jelinek jakub@redhat.com
Thu Feb 18 20:08:00 GMT 2010


Hi!

On
extern void likely ();
extern void unlikely ();
void
test_expect (char *a, char *b, char *c, char *d)
{
  if (__builtin_expect ((a == b && c == d), 0))
    unlikely ();
  else
    likely ();
}
gcc generates (IMHO) significantly worse code on x86_64 with the
__builtin_expect than with -D'__builtin_expect(a,b)=a' at -O2:
        cmpq    %rcx, %rdx
        je      .L4
.L2:    xorl    %eax, %eax
        jmp     likely
        .p2align 4,,10
        .p2align 3
.L4:    cmpq    %rsi, %rdi
        jne     .L2
        xorl    %eax, %eax
        jmp     unlikely
with __builtin_expect defined away and:
        cmpq    %rcx, %rdx
        sete    %dl
        xorl    %eax, %eax
        cmpq    %rsi, %rdi
        movzbl  %dl, %edx
        sete    %al
        testl   %eax, %edx
        jne     .L4
        xorl    %eax, %eax
        jmp     likely
.L4:    xorl    %eax, %eax
        jmp     unlikely
when __builtin_expect is used.  The problem is that without __builtin_expect
gimple_boolify changes types of the condition to _Bool and therefore at
expansion time gcc is able to optimize &&, while with __builtin_expect
gimple_boolify just boolifies it by casing __builtin_expect result to _Bool.

The following patch fixes it by boolifying also first __builtin_expect
argument to make sure __builtin_expect is less intrusive.

Bootstrapped/regtested on x86_64-linux and i686-linux, will commit to trunk
tomorrow unless somebody objects.

2010-02-18  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/42233
	* gimplify.c (gimple_boolify): For __builtin_expect call
	gimple_boolify also on its first argument.

--- gcc/gimplify.c.jj	2010-02-09 19:17:08.000000000 +0100
+++ gcc/gimplify.c	2010-02-18 12:45:21.000000000 +0100
@@ -2720,6 +2720,32 @@ gimple_boolify (tree expr)
   tree type = TREE_TYPE (expr);
   location_t loc = EXPR_LOCATION (expr);
 
+  if (TREE_CODE (expr) == NE_EXPR
+      && TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR
+      && integer_zerop (TREE_OPERAND (expr, 1)))
+    {
+      tree call = TREE_OPERAND (expr, 0);
+      tree fn = get_callee_fndecl (call);
+
+      /* For __builtin_expect ((long) (x), y) recurse into x as well.  */
+      if (fn
+	  && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+	  && DECL_FUNCTION_CODE (fn) == BUILT_IN_EXPECT
+	  && call_expr_nargs (call) == 2)
+	{
+	  tree arg = CALL_EXPR_ARG (call, 0);
+	  if (arg)
+	    {
+	      if (TREE_CODE (arg) == NOP_EXPR
+		  && TREE_TYPE (arg) == TREE_TYPE (call))
+		arg = TREE_OPERAND (arg, 0);
+	      arg = gimple_boolify (arg);
+	      CALL_EXPR_ARG (call, 0)
+		= fold_convert_loc (loc, TREE_TYPE (call), arg);
+	    }
+	}
+    }
+
   if (TREE_CODE (type) == BOOLEAN_TYPE)
     return expr;
 


	Jakub



More information about the Gcc-patches mailing list