1#!/usr/bin/env python3 2 3## 4## Copyright(c) 2019-2023 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 20import sys 21import re 22import string 23 24behdict = {} # tag ->behavior 25semdict = {} # tag -> semantics 26attribdict = {} # tag -> attributes 27macros = {} # macro -> macro information... 28attribinfo = {} # Register information and misc 29tags = [] # list of all tags 30overrides = {} # tags with helper overrides 31idef_parser_enabled = {} # tags enabled for idef-parser 32 33 34# We should do this as a hash for performance, 35# but to keep order let's keep it as a list. 36def uniquify(seq): 37 seen = set() 38 seen_add = seen.add 39 return [x for x in seq if x not in seen and not seen_add(x)] 40 41 42regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") 43immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") 44reg_or_immre = re.compile( 45 r"(((?<!DUP)[MNRCOPQXSGVZA])([stuvwxyzdefg]+)" 46 + "([.]?[LlHh]?)(\d+S?))|([#]([rRsSuUm])(\d+)[:]?(\d+)?)" 47) 48relimmre = re.compile(r"[#]([rR])(\d+)(?:[:](\d+))?") 49absimmre = re.compile(r"[#]([sSuUm])(\d+)(?:[:](\d+))?") 50 51finished_macros = set() 52 53 54def expand_macro_attribs(macro, allmac_re): 55 if macro.key not in finished_macros: 56 # Get a list of all things that might be macros 57 l = allmac_re.findall(macro.beh) 58 for submacro in l: 59 if not submacro: 60 continue 61 if not macros[submacro]: 62 raise Exception(f"Couldn't find macro: <{l}>") 63 macro.attribs |= expand_macro_attribs(macros[submacro], allmac_re) 64 finished_macros.add(macro.key) 65 return macro.attribs 66 67 68# When qemu needs an attribute that isn't in the imported files, 69# we'll add it here. 70def add_qemu_macro_attrib(name, attrib): 71 macros[name].attribs.add(attrib) 72 73 74immextre = re.compile(r"f(MUST_)?IMMEXT[(]([UuSsRr])") 75 76 77def is_cond_jump(tag): 78 if tag == "J2_rte": 79 return False 80 if "A_HWLOOP0_END" in attribdict[tag] or "A_HWLOOP1_END" in attribdict[tag]: 81 return False 82 return re.compile(r"(if.*fBRANCH)|(if.*fJUMPR)").search(semdict[tag]) != None 83 84 85def is_cond_call(tag): 86 return re.compile(r"(if.*fCALL)").search(semdict[tag]) != None 87 88 89def calculate_attribs(): 90 add_qemu_macro_attrib("fREAD_PC", "A_IMPLICIT_READS_PC") 91 add_qemu_macro_attrib("fTRAP", "A_IMPLICIT_READS_PC") 92 add_qemu_macro_attrib("fWRITE_P0", "A_WRITES_PRED_REG") 93 add_qemu_macro_attrib("fWRITE_P1", "A_WRITES_PRED_REG") 94 add_qemu_macro_attrib("fWRITE_P2", "A_WRITES_PRED_REG") 95 add_qemu_macro_attrib("fWRITE_P3", "A_WRITES_PRED_REG") 96 add_qemu_macro_attrib("fSET_OVERFLOW", "A_IMPLICIT_WRITES_USR") 97 add_qemu_macro_attrib("fSET_LPCFG", "A_IMPLICIT_WRITES_USR") 98 add_qemu_macro_attrib("fLOAD", "A_SCALAR_LOAD") 99 add_qemu_macro_attrib("fSTORE", "A_SCALAR_STORE") 100 101 # Recurse down macros, find attributes from sub-macros 102 macroValues = list(macros.values()) 103 allmacros_restr = "|".join(set([m.re.pattern for m in macroValues])) 104 allmacros_re = re.compile(allmacros_restr) 105 for macro in macroValues: 106 expand_macro_attribs(macro, allmacros_re) 107 # Append attributes to all instructions 108 for tag in tags: 109 for macname in allmacros_re.findall(semdict[tag]): 110 if not macname: 111 continue 112 macro = macros[macname] 113 attribdict[tag] |= set(macro.attribs) 114 # Figure out which instructions write predicate registers 115 tagregs = get_tagregs() 116 for tag in tags: 117 regs = tagregs[tag] 118 for regtype, regid, toss, numregs in regs: 119 if regtype == "P" and is_written(regid): 120 attribdict[tag].add("A_WRITES_PRED_REG") 121 # Mark conditional jumps and calls 122 # Not all instructions are properly marked with A_CONDEXEC 123 for tag in tags: 124 if is_cond_jump(tag) or is_cond_call(tag): 125 attribdict[tag].add("A_CONDEXEC") 126 127 128def SEMANTICS(tag, beh, sem): 129 # print tag,beh,sem 130 behdict[tag] = beh 131 semdict[tag] = sem 132 attribdict[tag] = set() 133 tags.append(tag) # dicts have no order, this is for order 134 135 136def ATTRIBUTES(tag, attribstring): 137 attribstring = attribstring.replace("ATTRIBS", "").replace("(", "").replace(")", "") 138 if not attribstring: 139 return 140 attribs = attribstring.split(",") 141 for attrib in attribs: 142 attribdict[tag].add(attrib.strip()) 143 144 145class Macro(object): 146 __slots__ = ["key", "name", "beh", "attribs", "re"] 147 148 def __init__(self, name, beh, attribs): 149 self.key = name 150 self.name = name 151 self.beh = beh 152 self.attribs = set(attribs) 153 self.re = re.compile("\\b" + name + "\\b") 154 155 156def MACROATTRIB(macname, beh, attribstring): 157 attribstring = attribstring.replace("(", "").replace(")", "") 158 if attribstring: 159 attribs = attribstring.split(",") 160 else: 161 attribs = [] 162 macros[macname] = Macro(macname, beh, attribs) 163 164 165def compute_tag_regs(tag): 166 return uniquify(regre.findall(behdict[tag])) 167 168 169def compute_tag_immediates(tag): 170 return uniquify(immre.findall(behdict[tag])) 171 172 173## 174## tagregs is the main data structure we'll use 175## tagregs[tag] will contain the registers used by an instruction 176## Within each entry, we'll use the regtype and regid fields 177## regtype can be one of the following 178## C control register 179## N new register value 180## P predicate register 181## R GPR register 182## M modifier register 183## Q HVX predicate vector 184## V HVX vector register 185## O HVX new vector register 186## regid can be one of the following 187## d, e destination register 188## dd destination register pair 189## s, t, u, v, w source register 190## ss, tt, uu, vv source register pair 191## x, y read-write register 192## xx, yy read-write register pair 193## 194def get_tagregs(): 195 return dict(zip(tags, list(map(compute_tag_regs, tags)))) 196 197 198def get_tagimms(): 199 return dict(zip(tags, list(map(compute_tag_immediates, tags)))) 200 201 202def is_pair(regid): 203 return len(regid) == 2 204 205 206def is_single(regid): 207 return len(regid) == 1 208 209 210def is_written(regid): 211 return regid[0] in "dexy" 212 213 214def is_writeonly(regid): 215 return regid[0] in "de" 216 217 218def is_read(regid): 219 return regid[0] in "stuvwxy" 220 221 222def is_readwrite(regid): 223 return regid[0] in "xy" 224 225 226def is_scalar_reg(regtype): 227 return regtype in "RPC" 228 229 230def is_hvx_reg(regtype): 231 return regtype in "VQ" 232 233 234def is_old_val(regtype, regid, tag): 235 return regtype + regid + "V" in semdict[tag] 236 237 238def is_new_val(regtype, regid, tag): 239 return regtype + regid + "N" in semdict[tag] 240 241 242def need_slot(tag): 243 if ( 244 ("A_CONDEXEC" in attribdict[tag] and "A_JUMP" not in attribdict[tag]) 245 or "A_STORE" in attribdict[tag] 246 or "A_LOAD" in attribdict[tag] 247 ): 248 return 1 249 else: 250 return 0 251 252 253def need_part1(tag): 254 return re.compile(r"fPART1").search(semdict[tag]) 255 256 257def need_ea(tag): 258 return re.compile(r"\bEA\b").search(semdict[tag]) 259 260 261def need_PC(tag): 262 return "A_IMPLICIT_READS_PC" in attribdict[tag] 263 264 265def helper_needs_next_PC(tag): 266 return "A_CALL" in attribdict[tag] 267 268 269def need_pkt_has_multi_cof(tag): 270 return "A_COF" in attribdict[tag] 271 272 273def need_condexec_reg(tag, regs): 274 if "A_CONDEXEC" in attribdict[tag]: 275 for regtype, regid, toss, numregs in regs: 276 if is_writeonly(regid) and not is_hvx_reg(regtype): 277 return True 278 return False 279 280 281def skip_qemu_helper(tag): 282 return tag in overrides.keys() 283 284 285def is_tmp_result(tag): 286 return "A_CVI_TMP" in attribdict[tag] or "A_CVI_TMP_DST" in attribdict[tag] 287 288 289def is_new_result(tag): 290 return "A_CVI_NEW" in attribdict[tag] 291 292 293def is_idef_parser_enabled(tag): 294 return tag in idef_parser_enabled 295 296 297def imm_name(immlett): 298 return f"{immlett}iV" 299 300 301def read_semantics_file(name): 302 eval_line = "" 303 for line in open(name, "rt").readlines(): 304 if not line.startswith("#"): 305 eval_line += line 306 if line.endswith("\\\n"): 307 eval_line.rstrip("\\\n") 308 else: 309 eval(eval_line.strip()) 310 eval_line = "" 311 312 313def read_attribs_file(name): 314 attribre = re.compile( 315 r"DEF_ATTRIB\(([A-Za-z0-9_]+), ([^,]*), " 316 + r'"([A-Za-z0-9_\.]*)", "([A-Za-z0-9_\.]*)"\)' 317 ) 318 for line in open(name, "rt").readlines(): 319 if not attribre.match(line): 320 continue 321 (attrib_base, descr, rreg, wreg) = attribre.findall(line)[0] 322 attrib_base = "A_" + attrib_base 323 attribinfo[attrib_base] = {"rreg": rreg, "wreg": wreg, "descr": descr} 324 325 326def read_overrides_file(name): 327 overridere = re.compile("#define fGEN_TCG_([A-Za-z0-9_]+)\(.*") 328 for line in open(name, "rt").readlines(): 329 if not overridere.match(line): 330 continue 331 tag = overridere.findall(line)[0] 332 overrides[tag] = True 333 334 335def read_idef_parser_enabled_file(name): 336 global idef_parser_enabled 337 with open(name, "r") as idef_parser_enabled_file: 338 lines = idef_parser_enabled_file.read().strip().split("\n") 339 idef_parser_enabled = set(lines) 340