pru-passes.cc revision 1.1 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