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]

Rewrite some jump.c routines to use flags


This patch rewrites some jump.c routines to operate on flags that
describe comparisons rather than handling each comparison code
separately.  This in turn makes it easier to add some new routines
in the next patch.

Maybe the change isn't worth it for swap_condition, unsigned_condition
and signed_condition, but it does make comparison_dominates_p simpler.

The patch also has the effect of making signed_condition accept all
FP comparisons, rather than just those that are used for integers.
I don't think that's particularly useful, but it doesn't seem harmful
either, since all FP comparisons are signed.

Tested on aarch64-linux-gnu, aarch64_be-elf and x86_64-linux-gnu.
OK to install?

Richard


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

gcc/
	* jump.c (FLAGS_EQ, FLAGS_LT, FLAGS_GT, FLAGS_UNORDERED, FLAGS_ORDER)
	(FLAGS_SIGNED, FLAGS_UNSIGNED, FLAGS_SIGNEDNESS, FLAGS_CAN_TRAP): New
	defines.
	(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-03-08 18:15:26.828777872 +0000
+++ gcc/jump.c	2019-07-12 09:06:52.043241422 +0100
@@ -65,6 +65,95 @@ 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_SIGNEDNESS = FLAGS_SIGNED | FLAGS_UNSIGNED;
+
+/* When describing an existing condition, this flag says whether the
+   comparison traps for NaNs.  When asking for a new condition, the flag
+   says whether the comparison is allowed to trap for NaNs.  */
+const int FLAGS_CAN_TRAP = 0x40;
+
+/* Invoke T (CODE, ORDER, SIGNEDNESS, CAN_TRAP) 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 signedness of COND, or 0 if it is sign-agnostic
+   - CAN_TRAP is true if CODE can trap on some forms of NaN.  */
+#define FOR_MAPPING(T) \
+  T (EQ,	FLAGS_EQ,			0,		true) \
+  T (NE,	~FLAGS_EQ,			0,		true) \
+  T (LTGT,	FLAGS_LT | FLAGS_GT,		0,		true) \
+  T (LT,	FLAGS_LT,			FLAGS_SIGNED,	true) \
+  T (LE,	FLAGS_LT | FLAGS_EQ,		FLAGS_SIGNED,	true) \
+  T (GT,	FLAGS_GT,			FLAGS_SIGNED,	true) \
+  T (GE,	FLAGS_GT | FLAGS_EQ,		FLAGS_SIGNED,	true) \
+  T (LTU,	FLAGS_LT,			FLAGS_UNSIGNED,	false) \
+  T (LEU,	FLAGS_LT | FLAGS_EQ,		FLAGS_UNSIGNED,	false) \
+  T (GTU,	FLAGS_GT,			FLAGS_UNSIGNED,	false) \
+  T (GEU,	FLAGS_GT | FLAGS_EQ,		FLAGS_UNSIGNED,	false) \
+  T (ORDERED,	~FLAGS_UNORDERED,		FLAGS_SIGNED,	false) \
+  T (UNORDERED,	FLAGS_UNORDERED,		FLAGS_SIGNED,	false) \
+  T (UNEQ,	FLAGS_UNORDERED | FLAGS_EQ,	FLAGS_SIGNED,	false) \
+  T (UNLT,	FLAGS_UNORDERED | FLAGS_LT,	FLAGS_SIGNED,	false) \
+  T (UNLE,	~FLAGS_GT,			FLAGS_SIGNED,	false) \
+  T (UNGT,	FLAGS_UNORDERED | FLAGS_GT,	FLAGS_SIGNED,	false) \
+  T (UNGE,	~FLAGS_LT,			FLAGS_SIGNED,	false)
+
+/* Describe comparison CODE as a bitmask of FLAGS_*.  */
+
+static unsigned int
+condition_to_flags (rtx_code code)
+{
+#define CASE(CODE, ORDER, SIGNEDNESS, CAN_TRAP)		\
+  case CODE:						\
+    return (((ORDER) & FLAGS_ORDER)			\
+            | SIGNEDNESS				\
+            | (CAN_TRAP ? FLAGS_CAN_TRAP : 0));
+
+  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, CAN_TRAP)			\
+  if (((flags ^ (ORDER)) & FLAGS_ORDER) == 0			\
+      && (!SIGNEDNESS						\
+	  || (flags & ~SIGNEDNESS & FLAGS_SIGNEDNESS) == 0)	\
+      && (!CAN_TRAP || (flags & FLAGS_CAN_TRAP) != 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 +672,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 +686,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 +695,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 +711,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]