1# Copyright (C) 2013-2021 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 48BEGIN { 49 print "/* This file is auto-generated by gen-pass-instances.awk"; 50 print " from passes.def. */"; 51 lineno = 1; 52} 53 54function 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 89function 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 103function 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 124function 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 141function 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 197END { 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: 235