1 /* PRU target specific passes 2 Copyright (C) 2017-2020 Free Software Foundation, Inc. 3 Dimitar Dimitrov <dimitar@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 79 structure having a pointer to function type as one of its fields. 80 Otherwise return 0. */ 81 static bool 82 chkp_type_has_function_pointer (const_tree type) 83 { 84 bool res = false; 85 86 if (POINTER_TYPE_P (type) && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (type))) 87 res = true; 88 else if (RECORD_OR_UNION_TYPE_P (type)) 89 { 90 tree field; 91 92 for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 93 if (TREE_CODE (field) == FIELD_DECL) 94 res = res || chkp_type_has_function_pointer (TREE_TYPE (field)); 95 } 96 else if (TREE_CODE (type) == ARRAY_TYPE) 97 res = chkp_type_has_function_pointer (TREE_TYPE (type)); 98 99 return res; 100 } 101 102 /* Check the function declaration FNTYPE for TI ABI compatibility. */ 103 static void 104 chk_function_decl (const_tree fntype, location_t call_location) 105 { 106 /* GCC does not check if the RETURN VALUE pointer is NULL, 107 so do not allow GCC functions with large return values. */ 108 if (!VOID_TYPE_P (TREE_TYPE (fntype)) 109 && pru_return_in_memory (TREE_TYPE (fntype), fntype)) 110 error_at (call_location, 111 "large return values not supported with %<-mabi=ti%> option"); 112 113 /* Check this function's arguments. */ 114 for (tree p = TYPE_ARG_TYPES (fntype); p; p = TREE_CHAIN (p)) 115 { 116 tree arg_type = TREE_VALUE (p); 117 if (chkp_type_has_function_pointer (arg_type)) 118 error_at (call_location, 119 "function pointers not supported with %<-mabi=ti%> option"); 120 } 121 } 122 123 /* Callback for walk_gimple_seq that checks TP tree for TI ABI compliance. */ 124 static tree 125 check_op_callback (tree *tp, int *walk_subtrees, void *data) 126 { 127 struct walk_stmt_info *wi = (struct walk_stmt_info *) data; 128 129 if (RECORD_OR_UNION_TYPE_P (*tp) || TREE_CODE (*tp) == ENUMERAL_TYPE) 130 { 131 /* Forward declarations have NULL tree type. Skip them. */ 132 if (TREE_TYPE (*tp) == NULL) 133 return NULL; 134 } 135 136 /* TODO - why C++ leaves INTEGER_TYPE forward declarations around? */ 137 if (TREE_TYPE (*tp) == NULL) 138 return NULL; 139 140 const tree type = TREE_TYPE (*tp); 141 142 /* Direct function calls are allowed, obviously. */ 143 gcall *call = dyn_cast <gcall *> (gsi_stmt (wi->gsi)); 144 if (call 145 && tp == gimple_call_fn_ptr (call) 146 && gimple_call_fndecl (call)) 147 return NULL; 148 149 switch (TREE_CODE (type)) 150 { 151 case FUNCTION_TYPE: 152 case METHOD_TYPE: 153 { 154 /* Note: Do not enforce a small return value. It is safe to 155 call any TI ABI function from GCC, since GCC will 156 never pass NULL. */ 157 158 /* Check arguments for function pointers. */ 159 for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p)) 160 { 161 tree arg_type = TREE_VALUE (p); 162 if (chkp_type_has_function_pointer (arg_type)) 163 error_at (gimple_location (wi->stmt), "function pointers " 164 "not supported with %<-mabi=ti%> option"); 165 } 166 break; 167 } 168 case RECORD_TYPE: 169 case UNION_TYPE: 170 case QUAL_UNION_TYPE: 171 case POINTER_TYPE: 172 { 173 if (chkp_type_has_function_pointer (type)) 174 { 175 error_at (gimple_location (wi->stmt), 176 "function pointers not supported with " 177 "%<-mabi=ti%> option"); 178 *walk_subtrees = false; 179 } 180 break; 181 } 182 default: 183 break; 184 } 185 return NULL; 186 } 187 188 /* Pass implementation. */ 189 unsigned 190 pass_tiabi_check::execute (function *fun) 191 { 192 struct walk_stmt_info wi; 193 const_tree fntype = TREE_TYPE (fun->decl); 194 195 gimple_seq body = gimple_body (current_function_decl); 196 197 memset (&wi, 0, sizeof (wi)); 198 wi.info = NULL; 199 wi.want_locations = true; 200 201 /* Check the function body. */ 202 walk_gimple_seq (body, NULL, check_op_callback, &wi); 203 204 /* Check the function declaration. */ 205 chk_function_decl (fntype, fun->function_start_locus); 206 207 return 0; 208 } 209 210 } // anon namespace 211 212 gimple_opt_pass * 213 make_pass_tiabi_check (gcc::context *ctxt) 214 { 215 return new pass_tiabi_check (ctxt); 216 } 217 218 /* Register as early as possible. */ 219 void 220 pru_register_abicheck_pass (void) 221 { 222 opt_pass *tiabi_check = make_pass_tiabi_check (g); 223 struct register_pass_info tiabi_check_info 224 = { tiabi_check, "*warn_unused_result", 225 1, PASS_POS_INSERT_AFTER 226 }; 227 register_pass (&tiabi_check_info); 228 } 229