]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/pru/pru-passes.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / config / pru / pru-passes.cc
CommitLineData
8d2af3a2 1/* PRU target specific passes
a945c346 2 Copyright (C) 2017-2024 Free Software Foundation, Inc.
8d2af3a2
DD
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
42namespace {
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. */
47const 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. */
61class pass_tiabi_check : public gimple_opt_pass
62{
63public:
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\f
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. */
81static bool
82chkp_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. */
103static void
104chk_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. */
124static tree
125check_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. */
189unsigned
190pass_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
212gimple_opt_pass *
213make_pass_tiabi_check (gcc::context *ctxt)
214{
215 return new pass_tiabi_check (ctxt);
216}
217
218/* Register as early as possible. */
219void
220pru_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}