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]

Re: Rewrite some jump.c routines to use flags


Eric Botcazou <ebotcazou@adacore.com> writes:
>> AIUI, neither ORDERED nor UNEQ trap on signalling NaNs.  Without this,
>> the follow-on patch would fold
>> 
>>    (and (ordered x y) (uneq x y)) -> (eq x y)
>> 
>> which is the same thing for quiet NaNs but not for signalling NaNs.
>
> Note that GCC defaults to -fno-signaling-nans and the transformation would be 
> valid in this mode.

OK, how about this version?  Tested on aarch64-linux-gnu so far.

Thanks,
Richard


2019-07-15  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* jump.c (FLAGS_EQ, FLAGS_LT, FLAGS_GT, FLAGS_UNORDERED, FLAGS_ORDER)
	(FLAGS_SIGNED, FLAGS_UNSIGNED, FLAGS_SIGN_AGNOSTIC, FLAGS_SIGNEDNESS)
	(FLAGS_TRAP_QNANS, FLAGS_TRAP_SNANS, FLAGS_TRAP_NANS, FLAGS_TRAP_NONE)
	(FLAGS_TRAPS): New constants.
	(condition_to_flags, flags_to_condition): New functions.
	(swap_condition, unsigned_condition, signed_condition)
	(comparison_dominates_p): Use them.

Index: gcc/jump.c
===================================================================
--- gcc/jump.c	2019-07-15 16:22:55.000000000 +0100
+++ gcc/jump.c	2019-07-15 16:22:55.342699887 +0100
@@ -65,6 +65,99 @@ static void mark_jump_label_asm (rtx, rt
 static void redirect_exp_1 (rtx *, rtx, rtx, rtx_insn *);
 static int invert_exp_1 (rtx, rtx_insn *);
 
+/* Flags that describe when a condition is true.  */
+const int FLAGS_EQ = 0x1;
+const int FLAGS_LT = 0x2;
+const int FLAGS_GT = 0x4;
+const int FLAGS_UNORDERED = 0x8;
+const int FLAGS_ORDER = 0xf;
+
+/* When describing an existing condition, these flags say whether the
+   inputs are interpreted as signed and whether they are interpreted as
+   unsigned.  When asking for a new condition, the flags say whether
+   the comparison must handle signed values and whether it must handle
+   unsigned values.  Floats are treated as signed in both cases.  */
+const int FLAGS_SIGNED = 0x10;
+const int FLAGS_UNSIGNED = 0x20;
+const int FLAGS_SIGN_AGNOSTIC = 0;
+const int FLAGS_SIGNEDNESS = FLAGS_SIGNED | FLAGS_UNSIGNED;
+
+/* When describing an existing condition, these flag say whether the
+   comparison traps for quiet NaNs and signaling NaNs.  When asking for
+   a new condition, the flag says whether the comparison is allowed to
+   trap for such NaNs.  */
+const int FLAGS_TRAP_QNANS = 0x40;
+const int FLAGS_TRAP_SNANS = 0x80;
+const int FLAGS_TRAP_NANS = FLAGS_TRAP_SNANS | FLAGS_TRAP_QNANS;
+const int FLAGS_TRAP_NONE = 0;
+const int FLAGS_TRAPS = FLAGS_TRAP_SNANS | FLAGS_TRAP_QNANS;
+
+/* Invoke T (CODE, ORDER, SIGNEDNESS, TRAPS) for each comparison, where:
+
+   - CODE is the rtl comparison code
+   - ORDER is the OR of the conditions under which CODE returns true
+   - SIGNEDNESS is the FLAGS_* suffix describing the sigedness of COND
+   - TRAPS is the FLAGS_* suffix describing when COND can trap.  */
+#define FOR_MAPPING(T) \
+  T (EQ,	FLAGS_EQ,			SIGN_AGNOSTIC,	TRAP_SNANS) \
+  T (NE,	~FLAGS_EQ,			SIGN_AGNOSTIC,	TRAP_SNANS) \
+  T (LTGT,	FLAGS_LT | FLAGS_GT,		SIGNED,		TRAP_NANS) \
+  T (LT,	FLAGS_LT,			SIGNED,		TRAP_NANS) \
+  T (LE,	FLAGS_LT | FLAGS_EQ,		SIGNED,		TRAP_NANS) \
+  T (GT,	FLAGS_GT,			SIGNED,		TRAP_NANS) \
+  T (GE,	FLAGS_GT | FLAGS_EQ,		SIGNED,		TRAP_NANS) \
+  T (LTU,	FLAGS_LT,			UNSIGNED,	TRAP_NONE) \
+  T (LEU,	FLAGS_LT | FLAGS_EQ,		UNSIGNED,	TRAP_NONE) \
+  T (GTU,	FLAGS_GT,			UNSIGNED,	TRAP_NONE) \
+  T (GEU,	FLAGS_GT | FLAGS_EQ,		UNSIGNED,	TRAP_NONE) \
+  T (ORDERED,	~FLAGS_UNORDERED,		SIGNED,		TRAP_NONE) \
+  T (UNORDERED,	FLAGS_UNORDERED,		SIGNED,		TRAP_NONE) \
+  T (UNEQ,	FLAGS_UNORDERED | FLAGS_EQ,	SIGNED,		TRAP_NONE) \
+  T (UNLT,	FLAGS_UNORDERED | FLAGS_LT,	SIGNED,		TRAP_NONE) \
+  T (UNLE,	~FLAGS_GT,			SIGNED,		TRAP_NONE) \
+  T (UNGT,	FLAGS_UNORDERED | FLAGS_GT,	SIGNED,		TRAP_NONE) \
+  T (UNGE,	~FLAGS_LT,			SIGNED,		TRAP_NONE)
+
+/* Describe comparison CODE as a bitmask of FLAGS_*.  */
+
+static unsigned int
+condition_to_flags (rtx_code code)
+{
+#define CASE(CODE, ORDER, SIGNEDNESS, TRAPS)		\
+  case CODE:						\
+    return ((ORDER) & FLAGS_ORDER) | FLAGS_##SIGNEDNESS | FLAGS_##TRAPS;
+
+  switch (code)
+    {
+    FOR_MAPPING (CASE);
+    default:
+      gcc_unreachable ();
+    }
+
+#undef CASE
+}
+
+/* Return the comparison code that implements FLAGS_* bitmask FLAGS.
+   Assert on failure if FORCE, otherwise return UNKNOWN.  */
+
+static rtx_code
+flags_to_condition (unsigned int flags, bool force)
+{
+#define TEST(CODE, ORDER, SIGNEDNESS, TRAPS)				\
+  if (((flags ^ (ORDER)) & FLAGS_ORDER) == 0				\
+      && (FLAGS_##SIGNEDNESS == 0					\
+	  || ((FLAGS_##SIGNEDNESS ^ flags) & FLAGS_SIGNEDNESS) == 0)	\
+      && (FLAGS_##TRAPS & ~flags & FLAGS_TRAPS) == 0)			\
+    return CODE;
+
+  FOR_MAPPING (TEST);
+
+  gcc_assert (!force);
+  return UNKNOWN;
+#undef TEST
+}
+#undef FOR_MAPPING
+
 /* Worker for rebuild_jump_labels and rebuild_jump_labels_chain.  */
 static void
 rebuild_jump_labels_1 (rtx_insn *f, bool count_forced)
@@ -583,44 +676,11 @@ reverse_condition_maybe_unordered (enum
 enum rtx_code
 swap_condition (enum rtx_code code)
 {
-  switch (code)
-    {
-    case EQ:
-    case NE:
-    case UNORDERED:
-    case ORDERED:
-    case UNEQ:
-    case LTGT:
-      return code;
-
-    case GT:
-      return LT;
-    case GE:
-      return LE;
-    case LT:
-      return GT;
-    case LE:
-      return GE;
-    case GTU:
-      return LTU;
-    case GEU:
-      return LEU;
-    case LTU:
-      return GTU;
-    case LEU:
-      return GEU;
-    case UNLT:
-      return UNGT;
-    case UNLE:
-      return UNGE;
-    case UNGT:
-      return UNLT;
-    case UNGE:
-      return UNLE;
-
-    default:
-      gcc_unreachable ();
-    }
+  unsigned int flags = condition_to_flags (code);
+  flags = ((flags & ~(FLAGS_GT | FLAGS_LT))
+	   | (flags & FLAGS_GT ? FLAGS_LT : 0)
+	   | (flags & FLAGS_LT ? FLAGS_GT : 0));
+  return flags_to_condition (flags, true);
 }
 
 /* Given a comparison CODE, return the corresponding unsigned comparison.
@@ -630,28 +690,8 @@ swap_condition (enum rtx_code code)
 enum rtx_code
 unsigned_condition (enum rtx_code code)
 {
-  switch (code)
-    {
-    case EQ:
-    case NE:
-    case GTU:
-    case GEU:
-    case LTU:
-    case LEU:
-      return code;
-
-    case GT:
-      return GTU;
-    case GE:
-      return GEU;
-    case LT:
-      return LTU;
-    case LE:
-      return LEU;
-
-    default:
-      gcc_unreachable ();
-    }
+  unsigned int flags = condition_to_flags (code);
+  return flags_to_condition ((flags & ~FLAGS_SIGNED) | FLAGS_UNSIGNED, true);
 }
 
 /* Similarly, return the signed version of a comparison.  */
@@ -659,28 +699,8 @@ unsigned_condition (enum rtx_code code)
 enum rtx_code
 signed_condition (enum rtx_code code)
 {
-  switch (code)
-    {
-    case EQ:
-    case NE:
-    case GT:
-    case GE:
-    case LT:
-    case LE:
-      return code;
-
-    case GTU:
-      return GT;
-    case GEU:
-      return GE;
-    case LTU:
-      return LT;
-    case LEU:
-      return LE;
-
-    default:
-      gcc_unreachable ();
-    }
+  unsigned int flags = condition_to_flags (code);
+  return flags_to_condition ((flags & ~FLAGS_UNSIGNED) | FLAGS_SIGNED, true);
 }
 
 /* Return nonzero if CODE1 is more strict than CODE2, i.e., if the
@@ -695,74 +715,12 @@ comparison_dominates_p (enum rtx_code co
   if (code1 == UNKNOWN || code2 == UNKNOWN)
     return 0;
 
-  if (code1 == code2)
-    return 1;
-
-  switch (code1)
-    {
-    case UNEQ:
-      if (code2 == UNLE || code2 == UNGE)
-	return 1;
-      break;
-
-    case EQ:
-      if (code2 == LE || code2 == LEU || code2 == GE || code2 == GEU
-	  || code2 == ORDERED)
-	return 1;
-      break;
-
-    case UNLT:
-      if (code2 == UNLE || code2 == NE)
-	return 1;
-      break;
-
-    case LT:
-      if (code2 == LE || code2 == NE || code2 == ORDERED || code2 == LTGT)
-	return 1;
-      break;
-
-    case UNGT:
-      if (code2 == UNGE || code2 == NE)
-	return 1;
-      break;
-
-    case GT:
-      if (code2 == GE || code2 == NE || code2 == ORDERED || code2 == LTGT)
-	return 1;
-      break;
-
-    case GE:
-    case LE:
-      if (code2 == ORDERED)
-	return 1;
-      break;
-
-    case LTGT:
-      if (code2 == NE || code2 == ORDERED)
-	return 1;
-      break;
-
-    case LTU:
-      if (code2 == LEU || code2 == NE)
-	return 1;
-      break;
-
-    case GTU:
-      if (code2 == GEU || code2 == NE)
-	return 1;
-      break;
-
-    case UNORDERED:
-      if (code2 == NE || code2 == UNEQ || code2 == UNLE || code2 == UNLT
-	  || code2 == UNGE || code2 == UNGT)
-	return 1;
-      break;
-
-    default:
-      break;
-    }
-
-  return 0;
+  unsigned int flags1 = condition_to_flags (code1);
+  unsigned int flags2 = condition_to_flags (code2);
+  /* Make sure that the conditions do not use different sign interpretations
+     and that FLAGS2 contains every condition that FLAGS1 contains.  */
+  return (((flags1 | flags2) & FLAGS_SIGNEDNESS) != FLAGS_SIGNEDNESS
+	  && (flags1 & ~flags2 & FLAGS_ORDER) == 0);
 }
 
 /* Return 1 if INSN is an unconditional jump and nothing else.  */


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