]>
Commit | Line | Data |
---|---|---|
793958c9 TS |
1 | #!/usr/bin/env python3 |
2 | ||
3 | ## | |
4 | ## Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. | |
5 | ## | |
6 | ## This program is free software; you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation; either version 2 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | import sys | |
21 | import re | |
22 | import string | |
23 | ||
24 | behdict = {} # tag ->behavior | |
25 | semdict = {} # tag -> semantics | |
26 | attribdict = {} # tag -> attributes | |
27 | macros = {} # macro -> macro information... | |
28 | attribinfo = {} # Register information and misc | |
29 | tags = [] # list of all tags | |
30 | overrides = {} # tags with helper overrides | |
31 | ||
32 | # We should do this as a hash for performance, | |
33 | # but to keep order let's keep it as a list. | |
34 | def uniquify(seq): | |
35 | seen = set() | |
36 | seen_add = seen.add | |
37 | return [x for x in seq if x not in seen and not seen_add(x)] | |
38 | ||
39 | regre = re.compile( | |
40 | r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") | |
41 | immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") | |
42 | reg_or_immre = \ | |
43 | re.compile(r"(((?<!DUP)[MNRCOPQXSGVZA])([stuvwxyzdefg]+)" + \ | |
44 | "([.]?[LlHh]?)(\d+S?))|([#]([rRsSuUm])(\d+)[:]?(\d+)?)") | |
45 | relimmre = re.compile(r"[#]([rR])(\d+)(?:[:](\d+))?") | |
46 | absimmre = re.compile(r"[#]([sSuUm])(\d+)(?:[:](\d+))?") | |
47 | ||
48 | finished_macros = set() | |
49 | ||
50 | def expand_macro_attribs(macro,allmac_re): | |
51 | if macro.key not in finished_macros: | |
52 | # Get a list of all things that might be macros | |
53 | l = allmac_re.findall(macro.beh) | |
54 | for submacro in l: | |
55 | if not submacro: continue | |
56 | if not macros[submacro]: | |
57 | raise Exception("Couldn't find macro: <%s>" % l) | |
58 | macro.attribs |= expand_macro_attribs( | |
59 | macros[submacro], allmac_re) | |
60 | finished_macros.add(macro.key) | |
61 | return macro.attribs | |
62 | ||
63 | # When qemu needs an attribute that isn't in the imported files, | |
64 | # we'll add it here. | |
65 | def add_qemu_macro_attrib(name, attrib): | |
66 | macros[name].attribs.add(attrib) | |
67 | ||
68 | immextre = re.compile(r'f(MUST_)?IMMEXT[(]([UuSsRr])') | |
69 | def calculate_attribs(): | |
70 | add_qemu_macro_attrib('fREAD_PC', 'A_IMPLICIT_READS_PC') | |
71 | add_qemu_macro_attrib('fTRAP', 'A_IMPLICIT_READS_PC') | |
72 | add_qemu_macro_attrib('fWRITE_P0', 'A_WRITES_PRED_REG') | |
73 | add_qemu_macro_attrib('fWRITE_P1', 'A_WRITES_PRED_REG') | |
74 | add_qemu_macro_attrib('fWRITE_P2', 'A_WRITES_PRED_REG') | |
75 | add_qemu_macro_attrib('fWRITE_P3', 'A_WRITES_PRED_REG') | |
b9dd6ff9 TS |
76 | add_qemu_macro_attrib('fSET_OVERFLOW', 'A_IMPLICIT_WRITES_USR') |
77 | add_qemu_macro_attrib('fSET_LPCFG', 'A_IMPLICIT_WRITES_USR') | |
793958c9 TS |
78 | |
79 | # Recurse down macros, find attributes from sub-macros | |
80 | macroValues = list(macros.values()) | |
81 | allmacros_restr = "|".join(set([ m.re.pattern for m in macroValues ])) | |
82 | allmacros_re = re.compile(allmacros_restr) | |
83 | for macro in macroValues: | |
84 | expand_macro_attribs(macro,allmacros_re) | |
85 | # Append attributes to all instructions | |
86 | for tag in tags: | |
87 | for macname in allmacros_re.findall(semdict[tag]): | |
88 | if not macname: continue | |
89 | macro = macros[macname] | |
90 | attribdict[tag] |= set(macro.attribs) | |
91 | # Figure out which instructions write predicate registers | |
92 | tagregs = get_tagregs() | |
93 | for tag in tags: | |
94 | regs = tagregs[tag] | |
95 | for regtype, regid, toss, numregs in regs: | |
96 | if regtype == "P" and is_written(regid): | |
97 | attribdict[tag].add('A_WRITES_PRED_REG') | |
98 | ||
99 | def SEMANTICS(tag, beh, sem): | |
100 | #print tag,beh,sem | |
101 | behdict[tag] = beh | |
102 | semdict[tag] = sem | |
103 | attribdict[tag] = set() | |
104 | tags.append(tag) # dicts have no order, this is for order | |
105 | ||
106 | def ATTRIBUTES(tag, attribstring): | |
107 | attribstring = \ | |
108 | attribstring.replace("ATTRIBS","").replace("(","").replace(")","") | |
109 | if not attribstring: | |
110 | return | |
111 | attribs = attribstring.split(",") | |
112 | for attrib in attribs: | |
113 | attribdict[tag].add(attrib.strip()) | |
114 | ||
115 | class Macro(object): | |
116 | __slots__ = ['key','name', 'beh', 'attribs', 're'] | |
117 | def __init__(self, name, beh, attribs): | |
118 | self.key = name | |
119 | self.name = name | |
120 | self.beh = beh | |
121 | self.attribs = set(attribs) | |
122 | self.re = re.compile("\\b" + name + "\\b") | |
123 | ||
124 | def MACROATTRIB(macname,beh,attribstring): | |
125 | attribstring = attribstring.replace("(","").replace(")","") | |
126 | if attribstring: | |
127 | attribs = attribstring.split(",") | |
128 | else: | |
129 | attribs = [] | |
130 | macros[macname] = Macro(macname,beh,attribs) | |
131 | ||
132 | def compute_tag_regs(tag): | |
133 | return uniquify(regre.findall(behdict[tag])) | |
134 | ||
135 | def compute_tag_immediates(tag): | |
136 | return uniquify(immre.findall(behdict[tag])) | |
137 | ||
138 | ## | |
139 | ## tagregs is the main data structure we'll use | |
140 | ## tagregs[tag] will contain the registers used by an instruction | |
141 | ## Within each entry, we'll use the regtype and regid fields | |
142 | ## regtype can be one of the following | |
143 | ## C control register | |
144 | ## N new register value | |
145 | ## P predicate register | |
146 | ## R GPR register | |
147 | ## M modifier register | |
144da357 TS |
148 | ## Q HVX predicate vector |
149 | ## V HVX vector register | |
150 | ## O HVX new vector register | |
793958c9 TS |
151 | ## regid can be one of the following |
152 | ## d, e destination register | |
153 | ## dd destination register pair | |
154 | ## s, t, u, v, w source register | |
155 | ## ss, tt, uu, vv source register pair | |
156 | ## x, y read-write register | |
157 | ## xx, yy read-write register pair | |
158 | ## | |
159 | def get_tagregs(): | |
160 | return dict(zip(tags, list(map(compute_tag_regs, tags)))) | |
161 | ||
162 | def get_tagimms(): | |
163 | return dict(zip(tags, list(map(compute_tag_immediates, tags)))) | |
164 | ||
165 | def is_pair(regid): | |
166 | return len(regid) == 2 | |
167 | ||
168 | def is_single(regid): | |
169 | return len(regid) == 1 | |
170 | ||
171 | def is_written(regid): | |
172 | return regid[0] in "dexy" | |
173 | ||
174 | def is_writeonly(regid): | |
175 | return regid[0] in "de" | |
176 | ||
177 | def is_read(regid): | |
178 | return regid[0] in "stuvwxy" | |
179 | ||
180 | def is_readwrite(regid): | |
181 | return regid[0] in "xy" | |
182 | ||
183 | def is_scalar_reg(regtype): | |
184 | return regtype in "RPC" | |
185 | ||
144da357 TS |
186 | def is_hvx_reg(regtype): |
187 | return regtype in "VQ" | |
188 | ||
793958c9 TS |
189 | def is_old_val(regtype, regid, tag): |
190 | return regtype+regid+'V' in semdict[tag] | |
191 | ||
192 | def is_new_val(regtype, regid, tag): | |
193 | return regtype+regid+'N' in semdict[tag] | |
194 | ||
195 | def need_slot(tag): | |
196 | if ('A_CONDEXEC' in attribdict[tag] or | |
197 | 'A_STORE' in attribdict[tag] or | |
198 | 'A_LOAD' in attribdict[tag]): | |
199 | return 1 | |
200 | else: | |
201 | return 0 | |
202 | ||
203 | def need_part1(tag): | |
204 | return re.compile(r"fPART1").search(semdict[tag]) | |
205 | ||
206 | def need_ea(tag): | |
207 | return re.compile(r"\bEA\b").search(semdict[tag]) | |
208 | ||
209 | def skip_qemu_helper(tag): | |
210 | return tag in overrides.keys() | |
211 | ||
144da357 TS |
212 | def is_tmp_result(tag): |
213 | return ('A_CVI_TMP' in attribdict[tag] or | |
214 | 'A_CVI_TMP_DST' in attribdict[tag]) | |
215 | ||
216 | def is_new_result(tag): | |
217 | return ('A_CVI_NEW' in attribdict[tag]) | |
218 | ||
793958c9 TS |
219 | def imm_name(immlett): |
220 | return "%siV" % immlett | |
221 | ||
222 | def read_semantics_file(name): | |
223 | eval_line = "" | |
224 | for line in open(name, 'rt').readlines(): | |
225 | if not line.startswith("#"): | |
226 | eval_line += line | |
227 | if line.endswith("\\\n"): | |
228 | eval_line.rstrip("\\\n") | |
229 | else: | |
230 | eval(eval_line.strip()) | |
231 | eval_line = "" | |
232 | ||
233 | def read_attribs_file(name): | |
234 | attribre = re.compile(r'DEF_ATTRIB\(([A-Za-z0-9_]+), ([^,]*), ' + | |
235 | r'"([A-Za-z0-9_\.]*)", "([A-Za-z0-9_\.]*)"\)') | |
236 | for line in open(name, 'rt').readlines(): | |
237 | if not attribre.match(line): | |
238 | continue | |
239 | (attrib_base,descr,rreg,wreg) = attribre.findall(line)[0] | |
240 | attrib_base = 'A_' + attrib_base | |
241 | attribinfo[attrib_base] = {'rreg':rreg, 'wreg':wreg, 'descr':descr} | |
242 | ||
243 | def read_overrides_file(name): | |
244 | overridere = re.compile("#define fGEN_TCG_([A-Za-z0-9_]+)\(.*") | |
245 | for line in open(name, 'rt').readlines(): | |
246 | if not overridere.match(line): | |
247 | continue | |
248 | tag = overridere.findall(line)[0] | |
249 | overrides[tag] = True |