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