1 # Copyright (C) 2013-2016 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
] += pass_lines
[p
];
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
)
105 parse_line
($
0, fnname
);
107 if (pass_name ==
"PASS")
109 pass_num = args
[2] + 0;
110 new_line = prefix
"NEXT_PASS (" args
[3];
112 new_line = new_line
", " args
[4];
113 new_line = new_line
")" postfix
;
114 if (!pass_lines
[pass_name
, pass_num
])
116 print "ERROR: Can't locate instance of the pass mentioned in " fnname
;
122 function insert_pass
(line
, fnname
, after
, num
)
124 if (insert_remove_pass
(line
, fnname
))
126 num = pass_lines
[pass_name
, pass_num
];
127 adjust_linenos
(num
+ after
, 1);
130 if (args
[3] in pass_counts
)
131 pass_counts
[pass_name
]++;
133 pass_counts
[pass_name
] =
1;
135 pass_lines
[pass_name
, pass_counts
[pass_name
]] = num
+ after
;
136 lines
[num
+ after
] = new_line
;
139 function replace_pass
(line
, fnname
, num
, i
)
141 if (insert_remove_pass
(line
, "REPLACE_PASS"))
143 num = pass_lines
[pass_name
, pass_num
];
144 for (i = pass_counts
[pass_name
]; i
> pass_num
; i
--)
145 pass_lines
[pass_name
, i
- 1] = pass_lines
[pass_name
, i
];
146 delete pass_lines
[pass_name
, pass_counts
[pass_name
]];
147 if (pass_counts
[pass_name
] ==
1)
148 delete pass_counts
[pass_name
];
150 pass_counts
[pass_name
]--;
154 if (args
[3] in pass_counts
)
155 pass_counts
[pass_name
]++;
157 pass_counts
[pass_name
] =
1;
159 pass_lines
[pass_name
, pass_counts
[pass_name
]] = num
;
160 lines
[num
] = new_line
;
163 /INSERT_PASS_AFTER \
(.
+\
)/ {
164 insert_pass
($
0, "INSERT_PASS_AFTER", 1);
168 /INSERT_PASS_BEFORE \
(.
+\
)/ {
169 insert_pass
($
0, "INSERT_PASS_BEFORE", 0);
173 /REPLACE_PASS \
(.
+\
)/ {
174 replace_pass
($
0, "REPLACE_PASS");
179 ret = parse_line
($
0, "NEXT_PASS");
185 if (pass_name in pass_counts
)
186 pass_counts
[pass_name
]++;
188 pass_counts
[pass_name
] =
1;
190 pass_lines
[pass_name
, pass_counts
[pass_name
]] = lineno
;
192 lines
[lineno
++] = $
0;
196 for (i =
1; i
< lineno
; i
++)
198 ret = parse_line
(lines
[i
], "NEXT_PASS");
201 # Set pass_name argument, an optional with_arg argument
205 # Set pass_final_counts
206 if (pass_name in pass_final_counts
)
207 pass_final_counts
[pass_name
]++;
209 pass_final_counts
[pass_name
] =
1;
211 pass_num = pass_final_counts
[pass_name
];
213 # Print call expression with extra pass_num argument
216 printf "NEXT_PASS_WITH_ARG";
219 printf " (%s, %s", pass_name
, pass_num
;
221 printf ", %s", with_arg
;
222 printf ")%s\n", postfix
;