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]

PATCH: conditional traps for MIPS


This works for SImode operands (test program that compiles & assembles
appended), but I have low confidence that it is the proper way to do
it.  Please advise on how it can be improved.

In particular, I am displeased by some manipulations of the code.  For
example, consider this statement:

    if (x < 10)
      __builtin_trap ();

MIPS conditional trap machine instructions don't directly handle
the conditional operators LE and GT, so the operands must be swapped
and the operators converted to GE and LT respectively.

The above statement seems tailor-made for a conditional-trap LT
with immediate operand 10.  However, the loop-opt pass converts
constant 10 to 9, swaps the operands and changes the op to GE
(I'll investigate tomorrow).  Now, stupid mips_gen_conditional_trap
fixes-up by forcing 9 into a register and we do a register-register
GE conditional trap rather than the more compact register-immediate
LT conditional trap.

Anyway, here's the patch:

Index: gcc/config/mips/mips-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips-protos.h,v
retrieving revision 1.4
diff -u -p -r1.4 mips-protos.h
--- mips-protos.h	2000/08/08 01:17:06	1.4
+++ mips-protos.h	2000/09/05 09:44:30
@@ -67,6 +67,8 @@ extern void		mips_select_section PARAMS 
 extern int		arith32_operand PARAMS ((rtx, enum machine_mode));
 extern int		arith_operand PARAMS ((rtx, enum machine_mode));
 extern int		cmp_op PARAMS ((rtx, enum machine_mode));
+extern int		trap_sign_cmp_op PARAMS ((rtx, enum machine_mode));
+extern int		trap_unsign_cmp_op PARAMS ((rtx, enum machine_mode));
 extern int		const_float_1_operand PARAMS ((rtx, enum machine_mode));
 extern void		expand_block_move PARAMS ((rtx []));
 extern int		equality_op PARAMS ((rtx, enum machine_mode));
@@ -77,6 +79,7 @@ extern void		init_cumulative_args PARAMS
 #endif /* TREE_CODE */
 extern void		gen_conditional_branch PARAMS ((rtx[], enum rtx_code));
 extern void		gen_conditional_move PARAMS ((rtx *));
+extern void		mips_gen_conditional_trap PARAMS ((rtx *));
 extern int		large_int PARAMS ((rtx, enum machine_mode));
 extern void		machine_dependent_reorg PARAMS ((rtx));
 extern int		mips_address_cost PARAMS ((rtx));
Index: gcc/config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips.c,v
retrieving revision 1.98
diff -u -p -r1.98 mips.c
--- mips.c	2000/08/24 20:31:35	1.98
+++ mips.c	2000/09/05 09:44:32
@@ -92,7 +92,7 @@ static int mips16_simple_memory_operand	
 							enum machine_mode));
 static int m16_check_op				PARAMS ((rtx, int, int, int));
 static void block_move_loop			PARAMS ((rtx, rtx,
-							 unsigned int, 
+							 unsigned int,
 							 int,
 							 rtx, rtx));
 static void block_move_call			PARAMS ((rtx, rtx, rtx));
@@ -188,8 +188,8 @@ int num_refs[3];
 /* registers to check for load delay */
 rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4;
 
-/* Cached operands, and operator to compare for use in set/branch on
-   condition codes.  */
+/* Cached operands, and operator to compare for use in set/branch/trap
+   on condition codes.  */
 rtx branch_cmp[2];
 
 /* what type of branch to use */
@@ -964,6 +964,57 @@ cmp_op (op, mode)
   return GET_RTX_CLASS (GET_CODE (op)) == '<';
 }
 
+/* Return nonzero if the code is a relational operation suitable for a
+   conditional trap instructuion (only EQ, NE, LT, LTU, GE, GEU) */
+
+int
+trap_sign_cmp_op (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != GET_MODE (op))
+    return 0;
+
+  switch (GET_CODE (op))
+    {
+    case EQ:
+    case NE:
+    case LT:
+    case LTU:
+    case GE:
+    case GEU:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Return nonzero if the code is a relational operation suitable for a
+   conditional trap instructuion with unsigned immediate operands
+   (only LT, LTU, GE, GEU) */
+
+int
+trap_unsign_cmp_op (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != GET_MODE (op))
+    return 0;
+
+  switch (GET_CODE (op))
+    {
+    case LT:
+    case LTU:
+    case GE:
+    case GEU:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
 /* Return nonzero if the operand is either the PC or a label_ref.  */
 
 int
@@ -3138,6 +3189,46 @@ gen_conditional_move (operands)
 							 cmp_reg,
 							 CONST0_RTX (SImode)),
 						operands[2], operands[3])));
+}
+
+/* Emit the common code for conditional moves.  OPERANDS is the array
+   of operands passed to the conditional move defined_expand.  */
+
+void
+mips_gen_conditional_trap (operands)
+     rtx operands[];
+{
+  rtx op0, op1;
+  enum rtx_code cmp_code = GET_CODE (operands[0]);
+  enum machine_mode mode = GET_MODE (branch_cmp[0]);
+
+  /* FIXME: handle 16-bit immediate signed & unsigned */
+
+  /* MIPS conditional trap machine instructions don't have GT or LE
+     flavors, so we must invert the comparison and convert to LT and
+     GE, respectively.  */
+  switch (cmp_code)
+    {
+    case GT: cmp_code = LT; break;
+    case LE: cmp_code = GE; break;
+    case GTU: cmp_code = LTU; break;
+    case LEU: cmp_code = GEU; break;
+    default: break;
+    }
+  if (cmp_code == GET_CODE (operands[0]))
+    {
+      op0 = force_reg (mode, branch_cmp[0]);
+      op1 = branch_cmp[1];
+    }
+  else
+    {
+      op0 = force_reg (mode, branch_cmp[1]);
+      op1 = branch_cmp[0];
+    }
+
+  emit_insn (gen_rtx_TRAP_IF (VOIDmode,
+			      gen_rtx (cmp_code, GET_MODE (operands[0]), op0, op1),
+			      operands[1]));
 }
 
 /* Write a loop to move a constant number of bytes.
Index: gcc/config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips.h,v
retrieving revision 1.102
diff -u -p -r1.102 mips.h
--- mips.h	2000/08/21 14:35:29	1.102
+++ mips.h	2000/09/05 09:44:34
@@ -3713,6 +3713,8 @@ while (0)
   {"equality_op",		{ EQ, NE }},				\
   {"cmp_op",			{ EQ, NE, GT, GE, GTU, GEU, LT, LE,	\
 				  LTU, LEU }},				\
+  {"trap_sign_cmp_op",		{ EQ, NE, GE, GEU, LT, LTU }},		\
+  {"trap_unsign_cmp_bp",	{ GE, GEU, LT, LTU }},			\
   {"pc_or_label_operand",	{ PC, LABEL_REF }},			\
   {"call_insn_operand",		{ CONST_INT, CONST, SYMBOL_REF, REG}},	\
   {"move_operand", 		{ CONST_INT, CONST_DOUBLE, CONST,	\
Index: gcc/config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips.md,v
retrieving revision 1.84
diff -u -p -r1.84 mips.md
--- mips.md	2000/08/08 22:40:49	1.84
+++ mips.md	2000/09/05 09:44:36
@@ -10455,3 +10455,36 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\;j
   [(set_attr "type"	"arith")
    (set_attr "mode"	"DI")
    (set_attr "length"	"40")])
+
+
+(define_insn "trap"
+  [(trap_if (const_int 1) (const_int 0))]
+  ""
+  "teq\\t$0,$0")
+
+(define_expand "conditional_trap"
+  [(trap_if (match_operator 0 "trap_sign_cmp_op"
+			    [(match_dup 2) (match_dup 3)])
+	    (match_operand 1 "const_int_operand" ""))]
+  ""
+  "
+{
+  mips_gen_conditional_trap (operands);
+  DONE;
+}")
+
+(define_insn ""
+  [(trap_if (match_operator 0 "trap_sign_cmp_op"
+                            [(match_operand:SI 1 "reg_or_0_operand" "d")
+                             (match_operand:SI 2 "arith_operand" "dI")])
+	    (const_int 0))]
+  ""
+  "t%C0\\t%z1,%z2")
+
+(define_insn ""
+  [(trap_if (match_operator 0 "trap_unsign_cmp_op"
+                            [(match_operand:SI 1 "reg_or_0_operand" "d")
+                             (match_operand:SI 2 "uns_arith_operand" "dK")])
+	    (const_int 0))]
+  ""
+  "t%C0u\\t%z1,%z2")


test program: This is intended to exercise all possible combinations
of the 6 conditional operators, signed & unsigned regs,
signed-16-bit-immediate and unsigned-16-bit-immediate operands.
------------------------------------------------------------------------------

void
sign_reg_to_sign_reg (int x, int y)
{
    if (x <  y) __builtin_trap ();
    if (x >  y) __builtin_trap ();
    if (x <= y) __builtin_trap ();
    if (x >= y) __builtin_trap ();
    if (x == y) __builtin_trap ();
    if (x != y) __builtin_trap ();
}

void
sign_reg_to_small_neg (int x)
{
    if (x <  -10) __builtin_trap ();
    if (x >  -20) __builtin_trap ();
    if (x <= -30) __builtin_trap ();
    if (x >= -40) __builtin_trap ();
    if (x == -50) __builtin_trap ();
    if (x != -60) __builtin_trap ();
}

void
small_neg_to_sign_reg (int x)
{
    if (-10 <  x) __builtin_trap ();
    if (-20 >  x) __builtin_trap ();
    if (-30 <= x) __builtin_trap ();
    if (-40 >= x) __builtin_trap ();
    if (-50 == x) __builtin_trap ();
    if (-60 != x) __builtin_trap ();
}

void
sign_reg_to_small_pos (int x)
{
    if (x <  10) __builtin_trap ();
    if (x >  20) __builtin_trap ();
    if (x <= 30) __builtin_trap ();
    if (x >= 40) __builtin_trap ();
    if (x == 50) __builtin_trap ();
    if (x != 60) __builtin_trap ();
}

void
small_pos_to_sign_reg (int x)
{
    if (10 <  x) __builtin_trap ();
    if (20 >  x) __builtin_trap ();
    if (30 <= x) __builtin_trap ();
    if (40 >= x) __builtin_trap ();
    if (50 == x) __builtin_trap ();
    if (60 != x) __builtin_trap ();
}

void
sign_reg_to_huge_neg (int x)
{
    if (x <  -100010) __builtin_trap ();
    if (x >  -100020) __builtin_trap ();
    if (x <= -100030) __builtin_trap ();
    if (x >= -100040) __builtin_trap ();
    if (x == -100050) __builtin_trap ();
    if (x != -100060) __builtin_trap ();
}

void
huge_neg_to_sign_reg (int x)
{
    if (-100010 <  x) __builtin_trap ();
    if (-100020 >  x) __builtin_trap ();
    if (-100030 <= x) __builtin_trap ();
    if (-100040 >= x) __builtin_trap ();
    if (-100050 == x) __builtin_trap ();
    if (-100060 != x) __builtin_trap ();
}

void
sign_reg_to_huge_pos (int x)
{
    if (x <  100010) __builtin_trap ();
    if (x >  100020) __builtin_trap ();
    if (x <= 100030) __builtin_trap ();
    if (x >= 100040) __builtin_trap ();
    if (x == 100050) __builtin_trap ();
    if (x != 100060) __builtin_trap ();
}

void
huge_pos_to_sign_reg (int x)
{
    if (100010 <  x) __builtin_trap ();
    if (100020 >  x) __builtin_trap ();
    if (100030 <= x) __builtin_trap ();
    if (100040 >= x) __builtin_trap ();
    if (100050 == x) __builtin_trap ();
    if (100060 != x) __builtin_trap ();
}

void
sign_reg_to_large_pos (int x)
{
    if (x <  40010) __builtin_trap ();
    if (x >  40020) __builtin_trap ();
    if (x <= 40030) __builtin_trap ();
    if (x >= 40040) __builtin_trap ();
    if (x == 40050) __builtin_trap ();
    if (x != 40060) __builtin_trap ();
}

void
large_pos_to_sign_reg (int x)
{
    if (40010 <  x) __builtin_trap ();
    if (40020 >  x) __builtin_trap ();
    if (40030 <= x) __builtin_trap ();
    if (40040 >= x) __builtin_trap ();
    if (40050 == x) __builtin_trap ();
    if (40060 != x) __builtin_trap ();
}


void
unsign_reg_to_unsign_reg (unsigned x, unsigned y)
{
    if (x <  y) __builtin_trap ();
    if (x >  y) __builtin_trap ();
    if (x <= y) __builtin_trap ();
    if (x >= y) __builtin_trap ();
    if (x == y) __builtin_trap ();
    if (x != y) __builtin_trap ();
}

void
unsign_reg_to_small_pos (unsigned x)
{
    if (x <  10) __builtin_trap ();
    if (x >  20) __builtin_trap ();
    if (x <= 30) __builtin_trap ();
    if (x >= 40) __builtin_trap ();
    if (x == 50) __builtin_trap ();
    if (x != 60) __builtin_trap ();
}

void
small_pos_to_unsign_reg (unsigned x)
{
    if (10 <  x) __builtin_trap ();
    if (20 >  x) __builtin_trap ();
    if (30 <= x) __builtin_trap ();
    if (40 >= x) __builtin_trap ();
    if (50 == x) __builtin_trap ();
    if (60 != x) __builtin_trap ();
}

void
unsign_reg_to_huge_pos (unsigned x)
{
    if (x <  100010) __builtin_trap ();
    if (x >  100020) __builtin_trap ();
    if (x <= 100030) __builtin_trap ();
    if (x >= 100040) __builtin_trap ();
    if (x == 100050) __builtin_trap ();
    if (x != 100060) __builtin_trap ();
}

void
huge_pos_to_unsign_reg (unsigned x)
{
    if (100010 <  x) __builtin_trap ();
    if (100020 >  x) __builtin_trap ();
    if (100030 <= x) __builtin_trap ();
    if (100040 >= x) __builtin_trap ();
    if (100050 == x) __builtin_trap ();
    if (100060 != x) __builtin_trap ();
}

void
unsign_reg_to_large_pos (unsigned x)
{
    if (x <  40010) __builtin_trap ();
    if (x >  40020) __builtin_trap ();
    if (x <= 40030) __builtin_trap ();
    if (x >= 40040) __builtin_trap ();
    if (x == 40050) __builtin_trap ();
    if (x != 40060) __builtin_trap ();
}

void
large_pos_to_unsign_reg (unsigned x)
{
    if (40010 <  x) __builtin_trap ();
    if (40020 >  x) __builtin_trap ();
    if (40030 <= x) __builtin_trap ();
    if (40040 >= x) __builtin_trap ();
    if (40050 == x) __builtin_trap ();
    if (40060 != x) __builtin_trap ();
}

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