1 # Copyright (C) 2013-2023 Free Software Foundation, Inc.
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
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.
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/>.
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
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);
28 # The various instances of
29 # NEXT_PASS (pass_copy_prop);
31 # NEXT_PASS (pass_copy_prop, 1);
33 # NEXT_PASS (pass_copy_prop, 8);
34 # (currently there are 8 instances of that pass)
36 # INSERT_PASS_AFTER (pass_copy_prop, 1, pass_stv);
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.
46 # Usage: awk -f gen-pass-instances.awk passes.def
49 print "/* This file is auto-generated by gen-pass-instances.awk";
50 print " from passes.def. */";
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
,
61 # Find call expression.
62 call_starts_at =
match(line
, fnname
" \\(.+\\)");
63 if (call_starts_at ==
0)
66 # Length of the call expression.
67 len_of_call =
RLENGTH;
69 len_of_start =
length(fnname
" (");
70 len_of_open =
length("(");
71 len_of_close =
length(")");
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
, ",");
79 # Find call expression prefix
80 len_of_prefix = call_starts_at
- 1;
81 prefix =
substr(line
, 1, len_of_prefix
);
83 # Find call expression postfix
84 postfix_starts_at = call_starts_at
+ len_of_call
;
85 postfix =
substr(line
, postfix_starts_at
);
89 function adjust_linenos
(above
, increment
, p
, i
)
92 if (pass_lines
[p
] >= above
)
93 pass_lines
[p
] += increment
;
95 for (i = lineno
- 1; i
>= above
; i
--)
96 lines
[i
+ increment
] = lines
[i
];
98 for (i = above
; i
< lineno
; i
++)
99 lines
[i
+ increment
] = lines
[i
];
103 function insert_remove_pass
(line
, fnname
, arg3
)
105 parse_line
($
0, fnname
);
107 if (pass_name ==
"PASS")
109 pass_num = args
[2] + 0;
111 sub(/^
[ \t]*/, "", arg3
);
112 new_line = prefix
"NEXT_PASS (" arg3
;
114 new_line = new_line
"," args
[4];
115 new_line = new_line
")" postfix
;
116 if (!pass_lines
[pass_name
, pass_num
])
118 print "ERROR: Can't locate instance of the pass mentioned in " fnname
;
124 function insert_pass
(line
, fnname
, after
, num
)
126 if (insert_remove_pass
(line
, fnname
))
128 num = pass_lines
[pass_name
, pass_num
];
129 adjust_linenos
(num
+ after
, 1);
132 if (args
[3] in pass_counts
)
133 pass_counts
[pass_name
]++;
135 pass_counts
[pass_name
] =
1;
137 pass_lines
[pass_name
, pass_counts
[pass_name
]] = num
+ after
;
138 lines
[num
+ after
] = new_line
;
141 function replace_pass
(line
, fnname
, num
, i
)
143 if (insert_remove_pass
(line
, "REPLACE_PASS"))
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
];
152 pass_counts
[pass_name
]--;
156 if (args
[3] in pass_counts
)
157 pass_counts
[pass_name
]++;
159 pass_counts
[pass_name
] =
1;
161 pass_lines
[pass_name
, pass_counts
[pass_name
]] = num
;
162 lines
[num
] = new_line
;
165 /INSERT_PASS_AFTER \
(.
+\
)/ {
166 insert_pass
($
0, "INSERT_PASS_AFTER", 1);
170 /INSERT_PASS_BEFORE \
(.
+\
)/ {
171 insert_pass
($
0, "INSERT_PASS_BEFORE", 0);
175 /REPLACE_PASS \
(.
+\
)/ {
176 replace_pass
($
0, "REPLACE_PASS");
181 ret = parse_line
($
0, "NEXT_PASS");
187 if (pass_name in pass_counts
)
188 pass_counts
[pass_name
]++;
190 pass_counts
[pass_name
] =
1;
192 pass_lines
[pass_name
, pass_counts
[pass_name
]] = lineno
;
194 lines
[lineno
++] = $
0;
198 for (i =
1; i
< lineno
; i
++)
200 ret = parse_line
(lines
[i
], "NEXT_PASS");
203 # Set pass_name argument, an optional with_arg argument
207 # Set pass_final_counts
208 if (pass_name in pass_final_counts
)
209 pass_final_counts
[pass_name
]++;
211 pass_final_counts
[pass_name
] =
1;
213 pass_num = pass_final_counts
[pass_name
];
215 # Print call expression with extra pass_num argument
218 printf "NEXT_PASS_WITH_ARG";
221 printf " (%s, %s", pass_name
, pass_num
;
223 printf ",%s", with_arg
;
224 printf ")%s\n", postfix
;