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