IA MCU psABI support: changes to libraries
[gcc.git] / gcc / explow.c
index 1cfc411a3466b8a97b4774a353b015481e60f9c1..adc17a31a3a9d2f0ca50abb56b95b388123f868e 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,23 +24,27 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "diagnostic-core.h"
 #include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
 #include "stor-layout.h"
 #include "tm_p.h"
 #include "flags.h"
 #include "except.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
 #include "hard-reg-set.h"
-#include "input.h"
 #include "function.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "libfuncs.h"
-#include "insn-config.h"
-#include "ggc.h"
 #include "recog.h"
 #include "langhooks.h"
 #include "target.h"
@@ -53,12 +57,13 @@ static rtx break_out_memory_refs (rtx);
 /* Truncate and perhaps sign-extend C as appropriate for MODE.  */
 
 HOST_WIDE_INT
-trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
+trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
 {
   int width = GET_MODE_PRECISION (mode);
 
   /* You want to truncate to a _what_?  */
-  gcc_assert (SCALAR_INT_MODE_P (mode));
+  gcc_assert (SCALAR_INT_MODE_P (mode)
+             || POINTER_BOUNDS_MODE_P (mode));
 
   /* Canonicalize BImode to 0 and STORE_FLAG_VALUE.  */
   if (mode == BImode)
@@ -83,7 +88,7 @@ trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
    if it must be treated as immutable.  */
 
 rtx
-plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c,
+plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
               bool inplace)
 {
   RTX_CODE code;
@@ -115,7 +120,9 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c,
        {
          tem = plus_constant (mode, get_pool_constant (XEXP (x, 0)), c);
          tem = force_const_mem (GET_MODE (x), tem);
-         if (memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+         /* Targets may disallow some constants in the constant pool, thus
+            force_const_mem may return NULL_RTX.  */
+         if (tem && memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
            return tem;
        }
       break;
@@ -222,58 +229,6 @@ eliminate_constant_term (rtx x, rtx *constptr)
   return x;
 }
 
-/* Returns a tree for the size of EXP in bytes.  */
-
-static tree
-tree_expr_size (const_tree exp)
-{
-  if (DECL_P (exp)
-      && DECL_SIZE_UNIT (exp) != 0)
-    return DECL_SIZE_UNIT (exp);
-  else
-    return size_in_bytes (TREE_TYPE (exp));
-}
-
-/* Return an rtx for the size in bytes of the value of EXP.  */
-
-rtx
-expr_size (tree exp)
-{
-  tree size;
-
-  if (TREE_CODE (exp) == WITH_SIZE_EXPR)
-    size = TREE_OPERAND (exp, 1);
-  else
-    {
-      size = tree_expr_size (exp);
-      gcc_assert (size);
-      gcc_assert (size == SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp));
-    }
-
-  return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL);
-}
-
-/* Return a wide integer for the size in bytes of the value of EXP, or -1
-   if the size can vary or is larger than an integer.  */
-
-HOST_WIDE_INT
-int_expr_size (tree exp)
-{
-  tree size;
-
-  if (TREE_CODE (exp) == WITH_SIZE_EXPR)
-    size = TREE_OPERAND (exp, 1);
-  else
-    {
-      size = tree_expr_size (exp);
-      gcc_assert (size);
-    }
-
-  if (size == 0 || !tree_fits_shwi_p (size))
-    return -1;
-
-  return tree_to_shwi (size);
-}
 \f
 /* Return a copy of X in which all memory references
    and all constants that involve symbol refs
@@ -319,7 +274,7 @@ break_out_memory_refs (rtx x)
    a CONST.  */
 
 static rtx
-convert_memory_address_addr_space_1 (enum machine_mode to_mode ATTRIBUTE_UNUSED,
+convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
                                     rtx x, addr_space_t as ATTRIBUTE_UNUSED,
                                     bool in_const ATTRIBUTE_UNUSED)
 {
@@ -327,7 +282,7 @@ convert_memory_address_addr_space_1 (enum machine_mode to_mode ATTRIBUTE_UNUSED,
   gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
   return x;
 #else /* defined(POINTERS_EXTEND_UNSIGNED) */
-  enum machine_mode pointer_mode, address_mode, from_mode;
+  machine_mode pointer_mode, address_mode, from_mode;
   rtx temp;
   enum rtx_code code;
 
@@ -419,20 +374,21 @@ convert_memory_address_addr_space_1 (enum machine_mode to_mode ATTRIBUTE_UNUSED,
    arithmetic insns can be used.  */
 
 rtx
-convert_memory_address_addr_space (enum machine_mode to_mode, rtx x, addr_space_t as)
+convert_memory_address_addr_space (machine_mode to_mode, rtx x, addr_space_t as)
 {
   return convert_memory_address_addr_space_1 (to_mode, x, as, false);
 }
 \f
+
 /* Return something equivalent to X but valid as a memory address for something
    of mode MODE in the named address space AS.  When X is not itself valid,
    this works by copying X or subexpressions of it into registers.  */
 
 rtx
-memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as)
+memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
 {
   rtx oldx = x;
-  enum machine_mode address_mode = targetm.addr_space.address_mode (as);
+  machine_mode address_mode = targetm.addr_space.address_mode (as);
 
   x = convert_memory_address_addr_space (address_mode, x, as);
 
@@ -560,7 +516,7 @@ use_anchored_address (rtx x)
 {
   rtx base;
   HOST_WIDE_INT offset;
-  enum machine_mode mode;
+  machine_mode mode;
 
   if (!flag_section_anchors)
     return x;
@@ -639,7 +595,7 @@ copy_addr_to_reg (rtx x)
    in case X is a constant.  */
 
 rtx
-copy_to_mode_reg (enum machine_mode mode, rtx x)
+copy_to_mode_reg (machine_mode mode, rtx x)
 {
   rtx temp = gen_reg_rtx (mode);
 
@@ -663,7 +619,7 @@ copy_to_mode_reg (enum machine_mode mode, rtx x)
    since we mark it as a "constant" register.  */
 
 rtx
-force_reg (enum machine_mode mode, rtx x)
+force_reg (machine_mode mode, rtx x)
 {
   rtx temp, set;
   rtx_insn *insn;
@@ -764,7 +720,7 @@ force_not_mem (rtx x)
    MODE is the mode to use for X in case it is a constant.  */
 
 rtx
-copy_to_suggested_reg (rtx x, rtx target, enum machine_mode mode)
+copy_to_suggested_reg (rtx x, rtx target, machine_mode mode)
 {
   rtx temp;
 
@@ -784,8 +740,8 @@ copy_to_suggested_reg (rtx x, rtx target, enum machine_mode mode)
    FOR_RETURN is nonzero if the caller is promoting the return value
    of FNDECL, else it is for promoting args.  */
 
-enum machine_mode
-promote_function_mode (const_tree type, enum machine_mode mode, int *punsignedp,
+machine_mode
+promote_function_mode (const_tree type, machine_mode mode, int *punsignedp,
                       const_tree funtype, int for_return)
 {
   /* Called without a type node for a libcall.  */
@@ -815,8 +771,8 @@ promote_function_mode (const_tree type, enum machine_mode mode, int *punsignedp,
    PUNSIGNEDP points to the signedness of the type and may be adjusted
    to show what signedness to use on extension operations.  */
 
-enum machine_mode
-promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode,
+machine_mode
+promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode,
              int *punsignedp ATTRIBUTE_UNUSED)
 {
 #ifdef PROMOTE_MODE
@@ -868,13 +824,13 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode,
    mode of DECL.  If PUNSIGNEDP is not NULL, store there the unsignedness
    of DECL after promotion.  */
 
-enum machine_mode
+machine_mode
 promote_decl_mode (const_tree decl, int *punsignedp)
 {
   tree type = TREE_TYPE (decl);
   int unsignedp = TYPE_UNSIGNED (type);
-  enum machine_mode mode = DECL_MODE (decl);
-  enum machine_mode pmode;
+  machine_mode mode = DECL_MODE (decl);
+  machine_mode pmode;
 
   if (TREE_CODE (decl) == RESULT_DECL
       || TREE_CODE (decl) == PARM_DECL)
@@ -900,10 +856,9 @@ adjust_stack_1 (rtx adjust, bool anti_p)
   rtx temp;
   rtx_insn *insn;
 
-#ifndef STACK_GROWS_DOWNWARD
   /* Hereafter anti_p means subtract_p.  */
-  anti_p = !anti_p;
-#endif
+  if (!STACK_GROWS_DOWNWARD)
+    anti_p = !anti_p;
 
   temp = expand_binop (Pmode,
                       anti_p ? sub_optab : add_optab,
@@ -1018,8 +973,8 @@ emit_stack_save (enum save_level save_level, rtx *psave)
 {
   rtx sa = *psave;
   /* The default is that we use a move insn and save in a Pmode object.  */
-  rtx (*fcn) (rtx, rtx) = gen_move_insn;
-  enum machine_mode mode = STACK_SAVEAREA_MODE (save_level);
+  rtx (*fcn) (rtx, rtx) = gen_move_insn_uncast;
+  machine_mode mode = STACK_SAVEAREA_MODE (save_level);
 
   /* See if this machine has anything special to do for this kind of save.  */
   switch (save_level)
@@ -1073,7 +1028,7 @@ void
 emit_stack_restore (enum save_level save_level, rtx sa)
 {
   /* The default is that we use a move insn.  */
-  rtx (*fcn) (rtx, rtx) = gen_move_insn;
+  rtx (*fcn) (rtx, rtx) = gen_move_insn_uncast;
 
   /* If stack_realign_drap, the x86 backend emits a prologue that aligns both
      STACK_POINTER and HARD_FRAME_POINTER.
@@ -1130,8 +1085,8 @@ emit_stack_restore (enum save_level save_level, rtx sa)
 }
 
 /* Invoke emit_stack_save on the nonlocal_goto_save_area for the current
-   function.  This function should be called whenever we allocate or
-   deallocate dynamic stack space.  */
+   function.  This should be called whenever we allocate or deallocate
+   dynamic stack space.  */
 
 void
 update_nonlocal_goto_save_area (void)
@@ -1151,6 +1106,21 @@ update_nonlocal_goto_save_area (void)
 
   emit_stack_save (SAVE_NONLOCAL, &r_save);
 }
+
+/* Record a new stack level for the current function.  This should be called
+   whenever we allocate or deallocate dynamic stack space.  */
+
+void
+record_new_stack_level (void)
+{
+  /* Record the new stack level for nonlocal gotos.  */
+  if (cfun->nonlocal_goto_save_area)
+    update_nonlocal_goto_save_area ();
+  /* Record the new stack level for SJLJ exceptions.  */
+  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+    update_sjlj_context ();
+}
 \f
 /* Return an rtx representing the address of an area of memory dynamically
    pushed on the stack.
@@ -1433,24 +1403,23 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
     {
       int saved_stack_pointer_delta;
 
-#ifndef STACK_GROWS_DOWNWARD
-      emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+      if (!STACK_GROWS_DOWNWARD)
+       emit_move_insn (target, virtual_stack_dynamic_rtx);
 
       /* Check stack bounds if necessary.  */
       if (crtl->limit_stack)
        {
          rtx available;
          rtx_code_label *space_available = gen_label_rtx ();
-#ifdef STACK_GROWS_DOWNWARD
-         available = expand_binop (Pmode, sub_optab,
-                                   stack_pointer_rtx, stack_limit_rtx,
-                                   NULL_RTX, 1, OPTAB_WIDEN);
-#else
-         available = expand_binop (Pmode, sub_optab,
-                                   stack_limit_rtx, stack_pointer_rtx,
-                                   NULL_RTX, 1, OPTAB_WIDEN);
-#endif
+         if (STACK_GROWS_DOWNWARD)
+           available = expand_binop (Pmode, sub_optab,
+                                     stack_pointer_rtx, stack_limit_rtx,
+                                     NULL_RTX, 1, OPTAB_WIDEN);
+         else
+           available = expand_binop (Pmode, sub_optab,
+                                     stack_limit_rtx, stack_pointer_rtx,
+                                     NULL_RTX, 1, OPTAB_WIDEN);
+
          emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
                                   space_available);
 #ifdef HAVE_trap
@@ -1475,9 +1444,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
         crtl->preferred_stack_boundary alignment.  */
       stack_pointer_delta = saved_stack_pointer_delta;
 
-#ifdef STACK_GROWS_DOWNWARD
-      emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+      if (STACK_GROWS_DOWNWARD)
+       emit_move_insn (target, virtual_stack_dynamic_rtx);
     }
 
   suppress_reg_args_size = false;
@@ -1513,9 +1481,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
   /* Now that we've committed to a return value, mark its alignment.  */
   mark_reg_pointer (target, required_align);
 
-  /* Record the new stack level for nonlocal gotos.  */
-  if (cfun->nonlocal_goto_save_area != 0)
-    update_nonlocal_goto_save_area ();
+  /* Record the new stack level.  */
+  record_new_stack_level ();
 
   return target;
 }
@@ -1565,7 +1532,7 @@ emit_stack_probe (rtx address)
 
 #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
 
-#ifdef STACK_GROWS_DOWNWARD
+#if STACK_GROWS_DOWNWARD
 #define STACK_GROW_OP MINUS
 #define STACK_GROW_OPTAB sub_optab
 #define STACK_GROW_OFF(off) -(off)
@@ -1883,7 +1850,7 @@ hard_function_value (const_tree valtype, const_tree func, const_tree fntype,
       && GET_MODE (val) == BLKmode)
     {
       unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
-      enum machine_mode tmpmode;
+      machine_mode tmpmode;
 
       /* int_size_in_bytes can return -1.  We don't need a check here
         since the value of bytes will then be large enough that no
@@ -1910,7 +1877,7 @@ hard_function_value (const_tree valtype, const_tree func, const_tree fntype,
    in which a scalar value of mode MODE was returned by a library call.  */
 
 rtx
-hard_libcall_value (enum machine_mode mode, rtx fun)
+hard_libcall_value (machine_mode mode, rtx fun)
 {
   return targetm.calls.libcall_value (mode, fun);
 }