* haifa-sched.c (haifa_classify_insn): TRAP_IF is risky.
(sched_analyze_2): Allow scheduling TRAP_IF.
* reorg.c (mark_referenced_resources): Examine operands of TRAP_IF.
* rtl.h (TRAP_CODE): New macro.
* rtl.def (TRAP_IF): Change second operand type to rtx.
* optabs.c (gen_cond_trap): New function.
(init_traps): New function.
(init_optabs): Call init_traps.
* expr.h: Declare gen_cond_trap.
* jump.c (jump_optimize): Optimize jumps to and around traps.
* sparc.md: Define trap instructions.
* rs6000.md: Define trap instructions.
* rs6000.c (print_operand): New code 'V' for trap condition.
(trap_comparison_operator): New function.
* m88k.md: Update use of TRAP_IF.
* tree.h (enum built_in_function): New function code BUILT_IN_TRAP.
* c-decl.c (init_decl_processing): New builtin __builtin_trap.
* expr.c (expand_builtin): Handle BUILT_IN_TRAP.
* expr.c (expand_builtin): Error if __builtin_longjmp second argument
is not 1.
From-SVN: r20543
+Wed Jun 17 19:05:03 1998 John Carr <jfc@mit.edu>
+
+ * haifa-sched.c (haifa_classify_insn): TRAP_IF is risky.
+ (sched_analyze_2): Allow scheduling TRAP_IF.
+
+ * reorg.c (mark_referenced_resources): Examine operands of TRAP_IF.
+
+ * rtl.h (TRAP_CODE): New macro.
+
+ * rtl.def (TRAP_IF): Change second operand type to rtx.
+
+ * optabs.c (gen_cond_trap): New function.
+ (init_traps): New function.
+ (init_optabs): Call init_traps.
+ * expr.h: Declare gen_cond_trap.
+
+ * jump.c (jump_optimize): Optimize jumps to and around traps.
+
+ * sparc.md: Define trap instructions.
+
+ * rs6000.md: Define trap instructions.
+ * rs6000.c (print_operand): New code 'V' for trap condition.
+ (trap_comparison_operator): New function.
+
+ * m88k.md: Update use of TRAP_IF.
+
+ * tree.h (enum built_in_function): New function code BUILT_IN_TRAP.
+ * c-decl.c (init_decl_processing): New builtin __builtin_trap.
+ * expr.c (expand_builtin): Handle BUILT_IN_TRAP.
+
+ * expr.c (expand_builtin): Error if __builtin_longjmp second argument
+ is not 1.
+
Wed Jun 17 15:20:00 PDT 1998 Catherine Moore <clm@cygnus.com>
* reload1.c (spill_hard_reg): Check mode of register when
integer_type_node,
endlink))),
BUILT_IN_LONGJMP, NULL_PTR);
+ builtin_function ("__builtin_trap",
+ build_function_type (void_type_node, endlink),
+ BUILT_IN_TRAP, NULL_PTR);
/* In an ANSI C program, it is okay to supply built-in meanings
for these functions, since applications cannot validly use them
;; Division by 0 trap
(define_insn "trap_divide_by_zero"
- [(trap_if (const_int 1) 503)]
+ [(trap_if (const_int 1) (const_int 503))]
""
"tb0 0,%#r0,503"
[(set_attr "type" "weird")])
(const_int 0))
(pc)
(match_operand 1 "" "")))
- (trap_if (const_int 1) 503)]
+ (trap_if (const_int 1) (const_int 503))]
""
"
{
(define_insn "tbnd"
[(trap_if (gtu (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "arith_operand" "rI"))
- 7)]
+ (const_int 7))]
""
"tbnd %r0,%1"
[(set_attr "type" "weird")])
;; Just in case the optimizer decides to fold away the test.
(define_insn ""
- [(trap_if (const_int 1) 7)]
+ [(trap_if (const_int 1) (const_int 7))]
""
"tbnd %#r31,0"
[(set_attr "type" "weird")])
return 1;
}
+
+int
+trap_comparison_operator (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ return (GET_RTX_CLASS (GET_CODE (op)) == '<'
+ || GET_CODE (op) == EQ || GET_CODE (op) == NE);
+}
\f
/* Return 1 if ANDOP is a mask that has no bits on that are not in the
mask required to convert the result of a rotate insn into a shift
putc ('u', file);
return;
+ case 'V':
+ /* Print the trap code for this operand. */
+ switch (GET_CODE (x))
+ {
+ case EQ:
+ fputs ("eq", file); /* 4 */
+ break;
+ case NE:
+ fputs ("ne", file); /* 24 */
+ break;
+ case LT:
+ fputs ("lt", file); /* 16 */
+ break;
+ case LE:
+ fputs ("le", file); /* 20 */
+ break;
+ case GT:
+ fputs ("gt", file); /* 8 */
+ break;
+ case GE:
+ fputs ("ge", file); /* 12 */
+ break;
+ case LTU:
+ fputs ("llt", file); /* 2 */
+ break;
+ case LEU:
+ fputs ("lle", file); /* 6 */
+ break;
+ case GTU:
+ fputs ("lgt", file); /* 1 */
+ break;
+ case GEU:
+ fputs ("lge", file); /* 5 */
+ break;
+ default:
+ abort ();
+ }
+ break;
+
case 'w':
/* If constant, low-order 16 bits of constant, signed. Otherwise, write
normally. */
"
{ operands[7] = gen_rtx (GET_CODE (operands[2]), VOIDmode, operands[3],
const0_rtx); }")
+\f
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 0))]
+ ""
+ "{t 31,0,0|trap}")
+
+(define_expand "conditional_trap"
+ [(trap_if (match_operator 0 "trap_comparison_operator"
+ [(match_dup 2) (match_dup 3)])
+ (match_operand 1 "const_int_operand" ""))]
+ ""
+ "if (rs6000_compare_fp_p || operands[1] != const0_rtx) FAIL;
+ operands[2] = rs6000_compare_op0;
+ operands[3] = rs6000_compare_op1;")
+
+(define_insn ""
+ [(trap_if (match_operator 0 "trap_comparison_operator"
+ [(match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")])
+ (const_int 0))]
+ ""
+ "t%V0%I2 %1,%2")
[(unspec_volatile [(const_int 0)] 4)]
"flag_pic"
"")
+\f
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 5))]
+ ""
+ "ta 5"
+ [(set_attr "type" "misc")])
+
+(define_expand "conditional_trap"
+ [(trap_if (match_operator 0 "noov_compare_op"
+ [(match_dup 2) (match_dup 3)])
+ (match_operand:SI 1 "arith_operand" ""))]
+ ""
+ "operands[2] = gen_compare_reg (GET_CODE (operands[0]),
+ sparc_compare_op0, sparc_compare_op1);
+ operands[3] = const0_rtx;")
+
+(define_insn ""
+ [(trap_if (match_operator 0 "noov_compare_op" [(reg:CC 100) (const_int 0)])
+ (match_operand:SI 1 "arith_operand" "rM"))]
+ ""
+ "t%C0 %1"
+ [(set_attr "type" "misc")])
+
+(define_insn ""
+ [(trap_if (match_operator 0 "noov_compare_op" [(reg:CCX 100) (const_int 0)])
+ (match_operand:SI 1 "arith_operand" "rM"))]
+ "TARGET_V9"
+ "t%C0 %%xcc,%1"
+ [(set_attr "type" "misc")])
+
VOIDmode, 0);
rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
NULL_RTX, VOIDmode, 0);
+
+ if (value != const1_rtx)
+ {
+ error ("__builtin_longjmp second argument must be 1");
+ return const0_rtx;
+ }
+
expand_builtin_longjmp (buf_addr, value);
return const0_rtx;
}
+ case BUILT_IN_TRAP:
+#ifdef HAVE_trap
+ if (HAVE_trap)
+ emit_insn (gen_trap ());
+ else
+#endif
+ error ("__builtin_trap not supported by this target");
+ emit_barrier ();
+ return const0_rtx;
+
/* Various hooks for the DWARF 2 __throw routine. */
case BUILT_IN_UNWIND_INIT:
expand_builtin_unwind_init ();
/* Given a JUMP_INSN, return a description of the test being made. */
extern rtx get_condition PROTO((rtx, rtx *));
+
+/* Generate a conditional trap instruction. */
+extern rtx gen_cond_trap PROTO((enum rtx_code, rtx, rtx, rtx));
\f
/* Functions from expr.c: */
tmp_class =
WORST_CLASS (tmp_class,
may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)), 0));
+ break;
+ case TRAP_IF:
+ tmp_class = TRAP_RISKY;
+ break;
default:;
}
insn_class = WORST_CLASS (insn_class, tmp_class);
tmp_class =
WORST_CLASS (tmp_class,
may_trap_exp (SET_SRC (pat), 0));
+ break;
+ case TRAP_IF:
+ tmp_class = TRAP_RISKY;
+ break;
default:;
}
insn_class = tmp_class;
return;
}
+ /* Force pending stores to memory in case a trap handler needs them. */
+ case TRAP_IF:
+ flush_pending_lists (insn, 1);
+ break;
+
case ASM_OPERANDS:
case ASM_INPUT:
case UNSPEC_VOLATILE:
- case TRAP_IF:
{
rtx u;
continue;
}
}
+#ifdef HAVE_trap
+ /* Detect a conditional jump jumping over an unconditional trap. */
+ else if (HAVE_trap
+ && this_is_condjump && ! this_is_simplejump
+ && reallabelprev != 0
+ && GET_CODE (reallabelprev) == INSN
+ && GET_CODE (PATTERN (reallabelprev)) == TRAP_IF
+ && TRAP_CONDITION (PATTERN (reallabelprev)) == const_true_rtx
+ && prev_active_insn (reallabelprev) == insn
+ && no_labels_between_p (insn, reallabelprev)
+ && (temp2 = get_condition (insn, &temp4))
+ && can_reverse_comparison_p (temp2, insn))
+ {
+ rtx new = gen_cond_trap (reverse_condition (GET_CODE (temp2)),
+ XEXP (temp2, 0), XEXP (temp2, 1),
+ TRAP_CODE (PATTERN (reallabelprev)));
+
+ if (new)
+ {
+ emit_insn_before (new, temp4);
+ delete_insn (reallabelprev);
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ }
+ /* Detect a jump jumping to an unconditional trap. */
+ else if (HAVE_trap && this_is_condjump
+ && (temp = next_active_insn (JUMP_LABEL (insn)))
+ && GET_CODE (temp) == INSN
+ && GET_CODE (PATTERN (temp)) == TRAP_IF
+ && (this_is_simplejump
+ || (temp2 = get_condition (insn, &temp4))))
+ {
+ rtx tc = TRAP_CONDITION (PATTERN (temp));
+
+ if (tc == const_true_rtx
+ || (! this_is_simplejump && rtx_equal_p (temp2, tc)))
+ {
+ rtx new;
+ /* Replace an unconditional jump to a trap with a trap. */
+ if (this_is_simplejump)
+ {
+ emit_barrier_after (emit_insn_before (gen_trap (), insn));
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ new = gen_cond_trap (GET_CODE (temp2), XEXP (temp2, 0),
+ XEXP (temp2, 1),
+ TRAP_CODE (PATTERN (temp)));
+ if (new)
+ {
+ emit_insn_before (new, temp4);
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ }
+ /* If the trap condition and jump condition are mutually
+ exclusive, redirect the jump to the following insn. */
+ else if (GET_RTX_CLASS (GET_CODE (tc)) == '<'
+ && ! this_is_simplejump
+ && swap_condition (GET_CODE (temp2)) == GET_CODE (tc)
+ && rtx_equal_p (XEXP (tc, 0), XEXP (temp2, 0))
+ && rtx_equal_p (XEXP (tc, 1), XEXP (temp2, 1))
+ && redirect_jump (insn, get_label_after (temp)))
+ {
+ changed = 1;
+ continue;
+ }
+ }
+#endif
+
/* Detect a conditional jump jumping over an unconditional jump. */
else if ((this_is_condjump || this_is_condjump_in_parallel)
static void init_libfuncs PROTO((optab, int, int, char *, int));
static void init_integral_libfuncs PROTO((optab, char *, int));
static void init_floating_libfuncs PROTO((optab, char *, int));
+static void init_traps PROTO((void));
\f
/* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to
the result of operation CODE applied to OP0 (and OP1 if it is a binary
chkr_check_exec_libfunc = gen_rtx (SYMBOL_REF, VOIDmode, "chkr_check_exec");
chkr_check_str_libfunc = gen_rtx (SYMBOL_REF, VOIDmode, "chkr_check_str");
+#ifdef HAVE_conditional_trap
+ init_traps ();
+#endif
+
#ifdef INIT_TARGET_OPTABS
/* Allow the target to add more libcalls or rename some, etc. */
INIT_TARGET_OPTABS;
return x;
}
#endif /* BROKEN_LDEXP */
+\f
+#ifdef HAVE_conditional_trap
+/* The insn generating function can not take an rtx_code argument.
+ TRAP_RTX is used as an rtx argument. Its code is replaced with
+ the code to be used in the trap insn and all other fields are
+ ignored.
+
+ ??? Will need to change to support garbage collection. */
+static rtx trap_rtx;
+
+static void
+init_traps ()
+{
+ if (HAVE_conditional_trap)
+ trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+}
+#endif
+
+/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
+ CODE. Return 0 on failure. */
+
+rtx
+gen_cond_trap (code, op1, op2, tcode)
+ enum rtx_code code;
+ rtx op1, op2, tcode;
+{
+ enum machine_mode mode = GET_MODE (op1);
+ enum insn_code icode;
+
+ if (mode == VOIDmode)
+ return 0;
+
+#ifdef HAVE_conditional_trap
+ if (HAVE_conditional_trap
+ && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ rtx insn;
+ emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
+ PUT_CODE (trap_rtx, code);
+ insn = gen_conditional_trap (trap_rtx, tcode);
+ if (insn)
+ return insn;
+ }
+#endif
+
+ return 0;
+}
case UNSPEC_VOLATILE:
case ASM_INPUT:
- case TRAP_IF:
/* Traditional asm's are always volatile. */
res->volatil = 1;
return;
+ case TRAP_IF:
+ res->volatil = 1;
+ break;
+
case ASM_OPERANDS:
res->volatil = MEM_VOLATILE_P (x);
Operand 1 is the condition.
Operand 2 is the trap code.
For an unconditional trap, make the condition (const_int 1). */
-DEF_RTL_EXPR(TRAP_IF, "trap_if", "ei", 'x')
+DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", 'x')
/* ----------------------------------------------------------------------
Primitive values for use in expressions.
/* For a TRAP_IF rtx, TRAP_CONDITION is an expression. */
#define TRAP_CONDITION(RTX) ((RTX)->fld[0].rtx)
+#define TRAP_CODE(RTX) (RTX)->fld[1].rtx
/* 1 in a SYMBOL_REF if it addresses this function's constants pool. */
#define CONSTANT_POOL_ADDRESS_P(RTX) ((RTX)->unchanging)
BUILT_IN_RETURN,
BUILT_IN_SETJMP,
BUILT_IN_LONGJMP,
+ BUILT_IN_TRAP,
/* Various hooks for the DWARF 2 __throw routine. */
BUILT_IN_FP, BUILT_IN_SP,