This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: Fix modes in ctz libcall notes


When compiled with -O2 -mabi=64 on mips64-linux-gnu,
23_containers/bitset/ext/15361.cc has a libcall note of the form:

    (ctz:SI (reg:DI foo))

As things stand, this is invalid rtl: the ctz's mode must be the same
as the operand's[*1].  We determine the FOO is equivalent to 1 << 34,
so end up with:

    (ctz:SI (const_int 0x400000000))

simplify_unary_operand masks the value to SImode[*2] and therefore
treats it in the same way as:

    (ctz:SI (const_int 0))

The mode of the result is different because (quite sensibly) the
ctz-like libcalls return an int, regardless of the operand's width:

      /* All of these functions return small values.  Thus we choose to
	 have them return something that isn't a double-word.  */
      if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
	  || unoptab == popcount_optab || unoptab == parity_optab)
	outmode
	    = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));

But I think the note in this case should use the original mode, and then
be truncated or extended as necessary.  We are still able to optimise
the result to a constant, but this time we pick the right one.

Bootstrapped & regression-tested on x86_64-linux-gnu.  Also
regression-tested on mips64-linux-gnu.  OK to install?

Richard

[*1] And this is a good thing.  It means that (clz:DI (const_int ...))
     is well-defined RTL, and can be simplified to a constant.
     We would have to forbid (clz:MM (const_int ...)) otherwise,
     just as we do for SIGN_EXTEND.

[*2] In other cases, like CLZ, this masking is partly to undo the
     usual sign extension of INTVALs.  The mode has to be right
     regardless of the masking, because we use it when handling
     zero inputs.


gcc/
	* optabs.c (expand_unop): In libcall notes, give ffs, clz, ctz,
	popcount and parity rtxes the same mode as their operand.
	Truncate or extend the result to the return value's mode
	if necessary.

Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2008-01-23 13:19:49.000000000 +0000
+++ gcc/optabs.c	2008-01-23 13:20:33.000000000 +0000
@@ -3273,6 +3273,7 @@ expand_unop (enum machine_mode mode, opt
     {
       rtx insns;
       rtx value;
+      rtx eq_value;
       enum machine_mode outmode = mode;
 
       /* All of these functions return small values.  Thus we choose to
@@ -3292,8 +3293,12 @@ expand_unop (enum machine_mode mode, opt
       end_sequence ();
 
       target = gen_reg_rtx (outmode);
-      emit_libcall_block (insns, target, value,
-			  gen_rtx_fmt_e (unoptab->code, outmode, op0));
+      eq_value = gen_rtx_fmt_e (unoptab->code, mode, op0);
+      if (GET_MODE_SIZE (outmode) < GET_MODE_SIZE (mode))
+	eq_value = gen_rtx_TRUNCATE (outmode, eq_value);
+      else if (GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
+	eq_value = gen_rtx_ZERO_EXTEND (outmode, eq_value);
+      emit_libcall_block (insns, target, value, eq_value);
 
       return target;
     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]