analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / gen-pass-instances.awk
1 #  Copyright (C) 2013-2022 Free Software Foundation, Inc.
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by the
5 # Free Software Foundation; either version 3, or (at your option) any
6 # later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; see the file COPYING3.  If not see
15 # <http://www.gnu.org/licenses/>.
16
17 # This Awk script takes passes.def and writes pass-instances.def,
18 # counting the instances of each kind of pass, adding an instance number
19 # to everywhere that NEXT_PASS is used.
20 # Also handle INSERT_PASS_AFTER, INSERT_PASS_BEFORE and REPLACE_PASS
21 # directives.
22 #
23 # For example, the single-instanced pass:
24 #     NEXT_PASS (pass_warn_unused_result);
25 # becomes this in the output:
26 #     NEXT_PASS (pass_warn_unused_result, 1);
27 #
28 # The various instances of
29 #   NEXT_PASS (pass_copy_prop);
30 # become:
31 #   NEXT_PASS (pass_copy_prop, 1);
32 # through:
33 #   NEXT_PASS (pass_copy_prop, 8);
34 # (currently there are 8 instances of that pass)
35 #
36 #     INSERT_PASS_AFTER (pass_copy_prop, 1, pass_stv);
37 # will insert
38 #     NEXT_PASS (pass_stv, 1);
39 # immediately after the NEXT_PASS (pass_copy_prop, 1) line,
40 # similarly INSERT_PASS_BEFORE inserts immediately before that line.
41 #     REPLACE_PASS (pass_copy_prop, 1, pass_stv, true);
42 # will replace NEXT_PASS (pass_copy_prop, 1) line with
43 #     NEXT_PASS (pass_stv, 1, true);
44 # line and renumber all higher pass_copy_prop instances if any.
45
46 # Usage: awk -f gen-pass-instances.awk passes.def
47
48 BEGIN {
49   print "/* This file is auto-generated by gen-pass-instances.awk";
50   print "   from passes.def.  */";
51   lineno = 1;
52 }
53
54 function parse_line(line, fnname,       len_of_call, len_of_start,
55                                         len_of_open, len_of_close,
56                                         len_of_args, args_start_at,
57                                         args_str, len_of_prefix,
58                                         call_starts_at,
59                                         postfix_starts_at)
60 {
61   # Find call expression.
62   call_starts_at = match(line, fnname " \\(.+\\)");
63   if (call_starts_at == 0)
64     return 0;
65
66   # Length of the call expression.
67   len_of_call = RLENGTH;
68
69   len_of_start = length(fnname " (");
70   len_of_open = length("(");
71   len_of_close = length(")");
72
73   # Find arguments
74   len_of_args = len_of_call - (len_of_start + len_of_close);
75   args_start_at = call_starts_at + len_of_start;
76   args_str = substr(line, args_start_at, len_of_args);
77   split(args_str, args, ",");
78
79   # Find call expression prefix
80   len_of_prefix = call_starts_at - 1;
81   prefix = substr(line, 1, len_of_prefix);
82
83   # Find call expression postfix
84   postfix_starts_at = call_starts_at + len_of_call;
85   postfix = substr(line, postfix_starts_at);
86   return 1;
87 }
88
89 function adjust_linenos(above, increment,       p, i)
90 {
91   for (p in pass_lines)
92     if (pass_lines[p] >= above)
93       pass_lines[p] += increment;
94   if (increment > 0)
95     for (i = lineno - 1; i >= above; i--)
96       lines[i + increment] = lines[i];
97   else
98     for (i = above; i < lineno; i++)
99       lines[i + increment] = lines[i];
100   lineno += increment;
101 }
102
103 function insert_remove_pass(line, fnname,       arg3)
104 {
105   parse_line($0, fnname);
106   pass_name = args[1];
107   if (pass_name == "PASS")
108     return 1;
109   pass_num = args[2] + 0;
110   arg3 = args[3];
111   sub(/^[ \t]*/, "", arg3);
112   new_line = prefix "NEXT_PASS (" arg3;
113   if (args[4])
114     new_line = new_line "," args[4];
115   new_line = new_line ")" postfix;
116   if (!pass_lines[pass_name, pass_num])
117     {
118       print "ERROR: Can't locate instance of the pass mentioned in " fnname;
119       return 1;
120     }
121   return 0;
122 }
123
124 function insert_pass(line, fnname, after,               num)
125 {
126   if (insert_remove_pass(line, fnname))
127     return;
128   num = pass_lines[pass_name, pass_num];
129   adjust_linenos(num + after, 1);
130   pass_name = args[3];
131   # Set pass_counts
132   if (args[3] in pass_counts)
133     pass_counts[pass_name]++;
134   else
135     pass_counts[pass_name] = 1;
136
137   pass_lines[pass_name, pass_counts[pass_name]] = num + after;
138   lines[num + after] = new_line;
139 }
140
141 function replace_pass(line, fnname,                     num, i)
142 {
143   if (insert_remove_pass(line, "REPLACE_PASS"))
144     return;
145   num = pass_lines[pass_name, pass_num];
146   for (i = pass_counts[pass_name]; i > pass_num; i--)
147     pass_lines[pass_name, i - 1] = pass_lines[pass_name, i];
148   delete pass_lines[pass_name, pass_counts[pass_name]];
149   if (pass_counts[pass_name] == 1)
150     delete pass_counts[pass_name];
151   else
152     pass_counts[pass_name]--;
153
154   pass_name = args[3];
155   # Set pass_counts
156   if (args[3] in pass_counts)
157     pass_counts[pass_name]++;
158   else
159     pass_counts[pass_name] = 1;
160
161   pass_lines[pass_name, pass_counts[pass_name]] = num;
162   lines[num] = new_line;
163 }
164
165 /INSERT_PASS_AFTER \(.+\)/ {
166   insert_pass($0, "INSERT_PASS_AFTER", 1);
167   next;
168 }
169
170 /INSERT_PASS_BEFORE \(.+\)/ {
171   insert_pass($0, "INSERT_PASS_BEFORE", 0);
172   next;
173 }
174
175 /REPLACE_PASS \(.+\)/ {
176   replace_pass($0, "REPLACE_PASS");
177   next;
178 }
179
180 {
181   ret = parse_line($0, "NEXT_PASS");
182   if (ret)
183     {
184       pass_name = args[1];
185
186       # Set pass_counts
187       if (pass_name in pass_counts)
188         pass_counts[pass_name]++;
189       else
190         pass_counts[pass_name] = 1;
191
192       pass_lines[pass_name, pass_counts[pass_name]] = lineno;
193     }
194   lines[lineno++] = $0;
195 }
196
197 END {
198   for (i = 1; i < lineno; i++)
199     {
200       ret = parse_line(lines[i], "NEXT_PASS");
201       if (ret)
202         {
203           # Set pass_name argument, an optional with_arg argument
204           pass_name = args[1];
205           with_arg = args[2];
206
207           # Set pass_final_counts
208           if (pass_name in pass_final_counts)
209             pass_final_counts[pass_name]++;
210           else
211             pass_final_counts[pass_name] = 1;
212
213           pass_num = pass_final_counts[pass_name];
214
215           # Print call expression with extra pass_num argument
216           printf "%s", prefix;
217           if (with_arg)
218             printf "NEXT_PASS_WITH_ARG";
219           else
220             printf "NEXT_PASS";
221           printf " (%s, %s", pass_name, pass_num;
222           if (with_arg)
223             printf ",%s", with_arg;
224           printf ")%s\n", postfix;
225         }
226       else
227         print lines[i];
228     }
229 }
230
231 # Local Variables:
232 # mode:awk
233 # c-basic-offset:8
234 # End: