Home | History | Annotate | Line # | Download | only in pru
      1  1.1  mrg /* PRU target specific passes
      2  1.1  mrg    Copyright (C) 2017-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Dimitar Dimitrov <dimitar (at) dinux.eu>
      4  1.1  mrg 
      5  1.1  mrg    This file is part of GCC.
      6  1.1  mrg 
      7  1.1  mrg    GCC is free software; you can redistribute it and/or modify it
      8  1.1  mrg    under the terms of the GNU General Public License as published
      9  1.1  mrg    by the Free Software Foundation; either version 3, or (at your
     10  1.1  mrg    option) any later version.
     11  1.1  mrg 
     12  1.1  mrg    GCC is distributed in the hope that it will be useful, but WITHOUT
     13  1.1  mrg    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14  1.1  mrg    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15  1.1  mrg    License for more details.
     16  1.1  mrg 
     17  1.1  mrg    You should have received a copy of the GNU General Public License
     18  1.1  mrg    along with GCC; see the file COPYING3.  If not see
     19  1.1  mrg    <http://www.gnu.org/licenses/>.  */
     20  1.1  mrg 
     21  1.1  mrg #define IN_TARGET_CODE 1
     22  1.1  mrg 
     23  1.1  mrg #include "config.h"
     24  1.1  mrg #include "system.h"
     25  1.1  mrg #include "coretypes.h"
     26  1.1  mrg #include "backend.h"
     27  1.1  mrg #include "context.h"
     28  1.1  mrg #include "tm.h"
     29  1.1  mrg #include "alias.h"
     30  1.1  mrg #include "symtab.h"
     31  1.1  mrg #include "tree.h"
     32  1.1  mrg #include "diagnostic-core.h"
     33  1.1  mrg #include "function.h"
     34  1.1  mrg #include "gimple.h"
     35  1.1  mrg #include "gimple-iterator.h"
     36  1.1  mrg #include "gimple-walk.h"
     37  1.1  mrg #include "gimple-expr.h"
     38  1.1  mrg #include "tree-pass.h"
     39  1.1  mrg 
     40  1.1  mrg #include "pru-protos.h"
     41  1.1  mrg 
     42  1.1  mrg namespace {
     43  1.1  mrg 
     44  1.1  mrg /* Scan the tree to ensure that the compiled code by GCC
     45  1.1  mrg    conforms to the TI ABI specification.  If GCC cannot
     46  1.1  mrg    output a conforming code, raise an error.  */
     47  1.1  mrg const pass_data pass_data_tiabi_check =
     48  1.1  mrg {
     49  1.1  mrg   GIMPLE_PASS, /* type */
     50  1.1  mrg   "*tiabi_check", /* name */
     51  1.1  mrg   OPTGROUP_NONE, /* optinfo_flags */
     52  1.1  mrg   TV_NONE, /* tv_id */
     53  1.1  mrg   PROP_gimple_any, /* properties_required */
     54  1.1  mrg   0, /* properties_provided */
     55  1.1  mrg   0, /* properties_destroyed */
     56  1.1  mrg   0, /* todo_flags_start */
     57  1.1  mrg   0, /* todo_flags_finish */
     58  1.1  mrg };
     59  1.1  mrg 
     60  1.1  mrg /* Implementation class for the TI ABI compliance-check pass.  */
     61  1.1  mrg class pass_tiabi_check : public gimple_opt_pass
     62  1.1  mrg {
     63  1.1  mrg public:
     64  1.1  mrg   pass_tiabi_check (gcc::context *ctxt)
     65  1.1  mrg     : gimple_opt_pass (pass_data_tiabi_check, ctxt)
     66  1.1  mrg   {}
     67  1.1  mrg 
     68  1.1  mrg   /* opt_pass methods: */
     69  1.1  mrg   virtual unsigned int execute (function *);
     70  1.1  mrg 
     71  1.1  mrg   virtual bool gate (function *fun ATTRIBUTE_UNUSED)
     72  1.1  mrg   {
     73  1.1  mrg     return pru_current_abi == PRU_ABI_TI;
     74  1.1  mrg   }
     75  1.1  mrg 
     76  1.1  mrg }; // class pass_tiabi_check
     77  1.1  mrg 
     78  1.1  mrg /* Return 1 if type TYPE is a pointer to function type or a
     80  1.1  mrg    structure having a pointer to function type as one of its fields.
     81  1.1  mrg    Otherwise return 0.  */
     82  1.1  mrg static bool
     83  1.1  mrg chkp_type_has_function_pointer (const_tree type)
     84  1.1  mrg {
     85  1.1  mrg   bool res = false;
     86  1.1  mrg 
     87  1.1  mrg   if (POINTER_TYPE_P (type) && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (type)))
     88  1.1  mrg     res = true;
     89  1.1  mrg   else if (RECORD_OR_UNION_TYPE_P (type))
     90  1.1  mrg     {
     91  1.1  mrg       tree field;
     92  1.1  mrg 
     93  1.1  mrg       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     94  1.1  mrg 	if (TREE_CODE (field) == FIELD_DECL)
     95  1.1  mrg 	  res = res || chkp_type_has_function_pointer (TREE_TYPE (field));
     96  1.1  mrg     }
     97  1.1  mrg   else if (TREE_CODE (type) == ARRAY_TYPE)
     98  1.1  mrg     res = chkp_type_has_function_pointer (TREE_TYPE (type));
     99  1.1  mrg 
    100  1.1  mrg   return res;
    101  1.1  mrg }
    102  1.1  mrg 
    103  1.1  mrg /* Check the function declaration FNTYPE for TI ABI compatibility.  */
    104  1.1  mrg static void
    105  1.1  mrg chk_function_decl (const_tree fntype, location_t call_location)
    106  1.1  mrg {
    107  1.1  mrg   /* GCC does not check if the RETURN VALUE pointer is NULL,
    108  1.1  mrg      so do not allow GCC functions with large return values.  */
    109  1.1  mrg   if (!VOID_TYPE_P (TREE_TYPE (fntype))
    110  1.1  mrg       && pru_return_in_memory (TREE_TYPE (fntype), fntype))
    111  1.1  mrg     error_at (call_location,
    112  1.1  mrg 	      "large return values not supported with %<-mabi=ti%> option");
    113  1.1  mrg 
    114  1.1  mrg   /* Check this function's arguments.  */
    115  1.1  mrg   for (tree p = TYPE_ARG_TYPES (fntype); p; p = TREE_CHAIN (p))
    116  1.1  mrg     {
    117  1.1  mrg       tree arg_type = TREE_VALUE (p);
    118  1.1  mrg       if (chkp_type_has_function_pointer (arg_type))
    119  1.1  mrg 	error_at (call_location,
    120  1.1  mrg 		  "function pointers not supported with %<-mabi=ti%> option");
    121  1.1  mrg     }
    122  1.1  mrg }
    123  1.1  mrg 
    124  1.1  mrg /* Callback for walk_gimple_seq that checks TP tree for TI ABI compliance.  */
    125  1.1  mrg static tree
    126  1.1  mrg check_op_callback (tree *tp, int *walk_subtrees, void *data)
    127  1.1  mrg {
    128  1.1  mrg   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
    129  1.1  mrg 
    130  1.1  mrg   if (RECORD_OR_UNION_TYPE_P (*tp) || TREE_CODE (*tp) == ENUMERAL_TYPE)
    131  1.1  mrg     {
    132  1.1  mrg       /* Forward declarations have NULL tree type.  Skip them.  */
    133  1.1  mrg       if (TREE_TYPE (*tp) == NULL)
    134  1.1  mrg 	return NULL;
    135  1.1  mrg     }
    136  1.1  mrg 
    137  1.1  mrg   /* TODO - why C++ leaves INTEGER_TYPE forward declarations around?  */
    138  1.1  mrg   if (TREE_TYPE (*tp) == NULL)
    139  1.1  mrg     return NULL;
    140  1.1  mrg 
    141  1.1  mrg   const tree type = TREE_TYPE (*tp);
    142  1.1  mrg 
    143  1.1  mrg   /* Direct function calls are allowed, obviously.  */
    144  1.1  mrg   gcall *call = dyn_cast <gcall *> (gsi_stmt (wi->gsi));
    145  1.1  mrg   if (call
    146  1.1  mrg       && tp == gimple_call_fn_ptr (call)
    147  1.1  mrg       && gimple_call_fndecl (call))
    148  1.1  mrg     return NULL;
    149  1.1  mrg 
    150  1.1  mrg   switch (TREE_CODE (type))
    151  1.1  mrg     {
    152  1.1  mrg     case FUNCTION_TYPE:
    153  1.1  mrg     case METHOD_TYPE:
    154  1.1  mrg 	{
    155  1.1  mrg 	  /* Note: Do not enforce a small return value.  It is safe to
    156  1.1  mrg 	     call any TI ABI function from GCC, since GCC will
    157  1.1  mrg 	     never pass NULL.  */
    158  1.1  mrg 
    159  1.1  mrg 	  /* Check arguments for function pointers.  */
    160  1.1  mrg 	  for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
    161  1.1  mrg 	    {
    162  1.1  mrg 	      tree arg_type = TREE_VALUE (p);
    163  1.1  mrg 	      if (chkp_type_has_function_pointer (arg_type))
    164  1.1  mrg 		error_at (gimple_location (wi->stmt), "function pointers "
    165  1.1  mrg 			  "not supported with %<-mabi=ti%> option");
    166  1.1  mrg 	    }
    167  1.1  mrg 	  break;
    168  1.1  mrg 	}
    169  1.1  mrg     case RECORD_TYPE:
    170  1.1  mrg     case UNION_TYPE:
    171  1.1  mrg     case QUAL_UNION_TYPE:
    172  1.1  mrg     case POINTER_TYPE:
    173  1.1  mrg 	{
    174  1.1  mrg 	  if (chkp_type_has_function_pointer (type))
    175  1.1  mrg 	    {
    176  1.1  mrg 	      error_at (gimple_location (wi->stmt),
    177  1.1  mrg 			"function pointers not supported with "
    178  1.1  mrg 			"%<-mabi=ti%> option");
    179  1.1  mrg 	      *walk_subtrees = false;
    180  1.1  mrg 	    }
    181  1.1  mrg 	  break;
    182  1.1  mrg 	}
    183  1.1  mrg     default:
    184  1.1  mrg 	  break;
    185  1.1  mrg     }
    186  1.1  mrg   return NULL;
    187  1.1  mrg }
    188  1.1  mrg 
    189  1.1  mrg /* Pass implementation.  */
    190  1.1  mrg unsigned
    191  1.1  mrg pass_tiabi_check::execute (function *fun)
    192  1.1  mrg {
    193  1.1  mrg   struct walk_stmt_info wi;
    194  1.1  mrg   const_tree fntype = TREE_TYPE (fun->decl);
    195  1.1  mrg 
    196  1.1  mrg   gimple_seq body = gimple_body (current_function_decl);
    197  1.1  mrg 
    198  1.1  mrg   memset (&wi, 0, sizeof (wi));
    199  1.1  mrg   wi.info = NULL;
    200  1.1  mrg   wi.want_locations = true;
    201  1.1  mrg 
    202  1.1  mrg   /* Check the function body.  */
    203  1.1  mrg   walk_gimple_seq (body, NULL, check_op_callback, &wi);
    204  1.1  mrg 
    205  1.1  mrg   /* Check the function declaration.  */
    206  1.1  mrg   chk_function_decl (fntype, fun->function_start_locus);
    207  1.1  mrg 
    208  1.1  mrg   return 0;
    209  1.1  mrg }
    210  1.1  mrg 
    211  1.1  mrg } // anon namespace
    212  1.1  mrg 
    213  1.1  mrg gimple_opt_pass *
    214  1.1  mrg make_pass_tiabi_check (gcc::context *ctxt)
    215  1.1  mrg {
    216  1.1  mrg   return new pass_tiabi_check (ctxt);
    217  1.1  mrg }
    218  1.1  mrg 
    219  1.1  mrg /* Register as early as possible.  */
    220  1.1  mrg void
    221  1.1  mrg pru_register_abicheck_pass (void)
    222  1.1  mrg {
    223  1.1  mrg   opt_pass *tiabi_check = make_pass_tiabi_check (g);
    224  1.1  mrg   struct register_pass_info tiabi_check_info
    225  1.1  mrg     = { tiabi_check, "*warn_unused_result",
    226  1.1  mrg 	1, PASS_POS_INSERT_AFTER
    227  1.1  mrg       };
    228  1.1  mrg   register_pass (&tiabi_check_info);
    229           }
    230