inline abort

John Carr jfc@mit.edu
Sat Apr 18 17:53:00 GMT 1998


These changes cause abort calls to be compiled to inline trap
instructions.  This generally reduces code size and gives the
compiler more optimization opportunities by making basic blocks
longer.  Depending on chip and cache hit rates an untaken
conditional trap instruction may be faster or slower than a
conditional branch.

There is an assumption, which could be changed, that traps are
unrecoverable.

I include an implementation for SPARC and RS/6000.  The RS/6000
version may have sufferred some bit rot.  I haven't bootstrapped
it in a long time.

jump_optimize needs rewriting but I think everyone is afraid to touch it.
"temp" ... "temp4" are not good choices for variable names.


Sat Apr 18 15:58:35 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 value BUILT_IN_ABORT.
	* c-decl.c (init_decl_processing): abort is a builtin function.
	* cp/decl.c (init_decl_processing): abort is a builtin function.
	* expr.c (expand_builtin): Handle BUILT_IN_ABORT.
	* stmt.c (expand_end_bindings): Use trap instruction instead of
	calling abort.

*** haifa-sched.c~	Fri Apr 17 15:57:04 1998
--- haifa-sched.c	Sat Apr 18 15:56:25 1998
***************
*** 2579,2584 ****
--- 2579,2588 ----
  	      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);
***************
*** 2604,2609 ****
--- 2608,2617 ----
  	  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;
***************
*** 3510,3519 ****
  	return;
        }
  
      case ASM_OPERANDS:
      case ASM_INPUT:
      case UNSPEC_VOLATILE:
-     case TRAP_IF:
        {
  	rtx u;
  
--- 3518,3531 ----
  	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:
        {
  	rtx u;
  
*** rtl.h~	Fri Apr 17 19:10:04 1998
--- rtl.h	Sat Apr 18 08:23:07 1998
***************
*** 578,583 ****
--- 578,584 ----
  
  /* 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)
*** rtl.def~	Sat Apr  4 04:04:08 1998
--- rtl.def	Sat Apr 18 08:23:16 1998
***************
*** 502,508 ****
     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')
  
  /* ----------------------------------------------------------------------
     Primitive values for use in expressions.
--- 502,508 ----
     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", "ee", 'x')
  
  /* ----------------------------------------------------------------------
     Primitive values for use in expressions.
*** m88k.md~	Wed Apr  1 18:18:54 1998
--- m88k.md	Sat Apr 18 09:06:11 1998
***************
*** 2810,2816 ****
  
  ;; Division by 0 trap
  (define_insn "trap_divide_by_zero"
!   [(trap_if (const_int 1) 503)]
    ""
    "tb0 0,%#r0,503"
    [(set_attr "type" "weird")])
--- 2810,2816 ----
  
  ;; Division by 0 trap
  (define_insn "trap_divide_by_zero"
!   [(trap_if (const_int 1) (const_int 503))]
    ""
    "tb0 0,%#r0,503"
    [(set_attr "type" "weird")])
***************
*** 2822,2828 ****
  			  (const_int 0))
  		      (pc)
  		      (match_operand 1 "" "")))
!    (trap_if (const_int 1) 503)]
    ""
    "
  {
--- 2822,2828 ----
  			  (const_int 0))
  		      (pc)
  		      (match_operand 1 "" "")))
!    (trap_if (const_int 1) (const_int 503))]
    ""
    "
  {
***************
*** 3451,3457 ****
  (define_insn "tbnd"
    [(trap_if (gtu (match_operand:SI 0 "register_operand" "r")
  		 (match_operand:SI 1 "arith_operand" "rI"))
! 	    7)]
    ""
    "tbnd %r0,%1"
    [(set_attr "type" "weird")])
--- 3451,3457 ----
  (define_insn "tbnd"
    [(trap_if (gtu (match_operand:SI 0 "register_operand" "r")
  		 (match_operand:SI 1 "arith_operand" "rI"))
! 	    (const_int 7))]
    ""
    "tbnd %r0,%1"
    [(set_attr "type" "weird")])
***************
*** 3458,3464 ****
  
  ;; Just in case the optimizer decides to fold away the test.
  (define_insn ""
!   [(trap_if (const_int 1) 7)]
    ""
    "tbnd %#r31,0"
    [(set_attr "type" "weird")])
--- 3458,3464 ----
  
  ;; Just in case the optimizer decides to fold away the test.
  (define_insn ""
!   [(trap_if (const_int 1) (const_int 7))]
    ""
    "tbnd %#r31,0"
    [(set_attr "type" "weird")])
*** expr.h~	Sat Apr  4 14:53:20 1998
--- expr.h	Sat Apr 18 08:24:30 1998
***************
*** 660,665 ****
--- 660,668 ----
  
  /* 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));
  
  /* Functions from expr.c:  */
  
*** expr.c~	Fri Apr 17 15:55:16 1998
--- expr.c	Sat Apr 18 09:10:09 1998
***************
*** 8782,8787 ****
--- 8782,8797 ----
        break;
  #endif
  
+     case BUILT_IN_ABORT:
+ #ifdef HAVE_trap
+       if (HAVE_trap)
+ 	emit_insn (gen_trap ());
+       else
+ #endif
+ 	expand_call (exp, NULL_RTX, 1);
+       emit_barrier ();
+       return const0_rtx;
+ 
      case BUILT_IN_SETJMP:
        if (arglist == 0
  	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
*** c-decl.c~	Sat Apr  4 14:52:50 1998
--- c-decl.c	Sat Apr 18 09:09:47 1998
***************
*** 3425,3431 ****
  	 to avoid spurious "control drops through" warnings.  */
        /* Don't specify the argument types, to avoid errors
  	 from certain code which isn't valid in ANSI but which exists.  */
!       temp = builtin_function ("abort", void_ftype_any, NOT_BUILT_IN,
  			       NULL_PTR);
        TREE_THIS_VOLATILE (temp) = 1;
        TREE_SIDE_EFFECTS (temp) = 1;
--- 3425,3431 ----
  	 to avoid spurious "control drops through" warnings.  */
        /* Don't specify the argument types, to avoid errors
  	 from certain code which isn't valid in ANSI but which exists.  */
!       temp = builtin_function ("abort", void_ftype_any, BUILT_IN_ABORT,
  			       NULL_PTR);
        TREE_THIS_VOLATILE (temp) = 1;
        TREE_SIDE_EFFECTS (temp) = 1;
*** tree.h~	Fri Apr 17 18:46:57 1998
--- tree.h	Sat Apr 18 09:09:20 1998
***************
*** 108,113 ****
--- 108,114 ----
    BUILT_IN_RETURN,
    BUILT_IN_SETJMP,
    BUILT_IN_LONGJMP,
+   BUILT_IN_ABORT,
  
    /* Various hooks for the DWARF 2 __throw routine.  */
    BUILT_IN_FP, BUILT_IN_SP,
*** reorg.c~	Fri Apr 17 15:57:25 1998
--- reorg.c	Sat Apr 18 09:47:11 1998
***************
*** 340,350 ****
  
      case UNSPEC_VOLATILE:
      case ASM_INPUT:
-     case TRAP_IF:
        /* Traditional asm's are always volatile.  */
        res->volatil = 1;
        return;
  
      case ASM_OPERANDS:
        res->volatil = MEM_VOLATILE_P (x);
  
--- 340,353 ----
  
      case UNSPEC_VOLATILE:
      case ASM_INPUT:
        /* 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);
  
*** stmt.c~	Fri Apr 17 15:57:26 1998
--- stmt.c	Sat Apr 18 09:10:29 1998
***************
*** 2960,2967 ****
  	    emit_label (not_this);
  	  }
        /* If label is not recognized, abort.  */
!       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
! 			 VOIDmode, 0);
        emit_barrier ();
        emit_label (afterward);
      }
--- 2960,2972 ----
  	    emit_label (not_this);
  	  }
        /* If label is not recognized, abort.  */
! #ifdef HAVE_trap
!       if (HAVE_trap)
! 	emit_insn (gen_trap ());
!       else
! #endif
! 	emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
! 			   VOIDmode, 0);
        emit_barrier ();
        emit_label (afterward);
      }
*** jump.c	1998/04/16 23:56:11	1.17
--- jump.c	1998/04/18 20:17:12
*************** jump_optimize (f, cross_jump, noop_moves
*** 1897,1902 ****
--- 1897,1976 ----
  		  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)
*** cp/decl.c~	Fri Apr 17 15:57:42 1998
--- cp/decl.c	Sat Apr 18 17:42:48 1998
***************
*** 5466,5472 ****
        /* Declare these functions volatile
  	 to avoid spurious "control drops through" warnings.  */
        temp = builtin_function ("abort", void_ftype,
! 			       NOT_BUILT_IN, NULL_PTR);
        TREE_THIS_VOLATILE (temp) = 1;
        TREE_SIDE_EFFECTS (temp) = 1;
        /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
--- 5466,5472 ----
        /* Declare these functions volatile
  	 to avoid spurious "control drops through" warnings.  */
        temp = builtin_function ("abort", void_ftype,
! 			       BUILT_IN_ABORT, NULL_PTR);
        TREE_THIS_VOLATILE (temp) = 1;
        TREE_SIDE_EFFECTS (temp) = 1;
        /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
*** sparc.md~	Sat Apr 18 07:46:12 1998
--- sparc.md	Sat Apr 18 17:34:20 1998
***************
*** 6607,6609 ****
--- 6607,6645 ----
    [(unspec_volatile [(const_int 0)] 4)]
    "flag_pic"
    "")
+ 
+ (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")])
+ 
+ ;; A noop move of the condition register must be recognized even though
+ ;; it will be deleted. 
+ (define_insn ""
+   [(set (reg 100) (reg 100))]
+   ""
+   "")
*** optabs.c.orig	Sat Apr 18 16:59:33 1998
--- optabs.c	Sat Apr 18 17:23:58 1998
***************
*** 246,251 ****
--- 246,252 ----
  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));
  
  /* 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
***************
*** 4379,4385 ****
    chkr_copy_bitmap_libfunc = gen_rtx (SYMBOL_REF, VOIDmode, "chkr_copy_bitmap");
    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 INIT_TARGET_OPTABS
    /* Allow the target to add more libcalls or rename some, etc.  */
    INIT_TARGET_OPTABS;
--- 4380,4388 ----
    chkr_copy_bitmap_libfunc = gen_rtx (SYMBOL_REF, VOIDmode, "chkr_copy_bitmap");
    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;
***************
*** 4402,4404 ****
--- 4405,4452 ----
    return x;
  }
  #endif /* BROKEN_LDEXP */
+ 
+ #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.  */
+ 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;
+ }
*** rs6000.md~	Wed Apr  1 18:18:57 1998
--- rs6000.md	Sat Apr 18 17:21:10 1998
***************
*** 9661,9663 ****
--- 9661,9685 ----
    "
  { operands[7] = gen_rtx (GET_CODE (operands[2]), VOIDmode, operands[3],
  			 const0_rtx); }")
+ 
+ (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")
*** rs6000.c~	Sat Apr  4 14:54:45 1998
--- rs6000.c	Sat Apr 18 17:39:51 1998
***************
*** 1969,1974 ****
--- 1969,1985 ----
  
    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);
+ }
  
  /* 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
***************
*** 2867,2872 ****
--- 2878,2923 ----
  		     reg_names[SMALL_DATA_REG]);
  	}
        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 0:
        if (GET_CODE (x) == REG)



More information about the Gcc mailing list