[Sockets]: Always reset internal SAEA completion when reattempting connection in...
[mono-project.git] / mono / mini / genmdesc.py
blob7a20260e81ec8e3dda0810d0eb0cdbda51bdb9ea
1 #!/usr/bin/env python3
4 # This tool is used to generate the cpu-<ARCH>.h files used by the JIT. The input is the
5 # cpu-<ARCH>.md file, along with the instruction metadata in mini-ops.h.
8 import sys
9 import os
10 import re
12 # Keep it in sync with mini.h
13 MONO_INST_DEST = 0
14 MONO_INST_SRC1 = 1
15 MONO_INST_SRC2 = 2
16 MONO_INST_SRC3 = 3
17 MONO_INST_LEN = 4
18 MONO_INST_CLOB = 5
19 MONO_INST_MAX = 6
21 allowed_defines = { "TARGET_X86" : 1,
22 "TARGET_AMD64" : 1,
23 "TARGET_ARM" : 1,
24 "TARGET_ARM64" : 1,
25 "TARGET_POWERPC" : 1,
26 "TARGET_SPARC" : 1,
27 "TARGET_S390X" : 1,
28 "TARGET_MIPS" : 1,
29 "TARGET_RISCV" : 1,
30 "TARGET_RISCV32" : 1,
31 "TARGET_RISCV64" : 1,
32 "TARGET_WASM" : 1
35 class OpDef:
36 def __init__ (self, num, name, dest_def, src1_def, src2_def):
37 # num is the opcode value/index
38 self.num = num
39 self.name = name
40 self.dest_def = dest_def
41 self.src1_def = src1_def
42 self.src2_def = src2_def
43 self.used = False
44 # Data read from the cpu descriptor file
45 self.spec = ["", "", "", "", "", "", "", "", "", ""]
46 self.desc_idx = 0
48 def usage ():
49 print ("Usage: genmdesc.py <target define> <srcdir> <output file name> <c symbol name> <input file name>")
51 def parse_mini_ops (target_define):
52 opcodes = {}
53 opcode_id = 0
54 enabled = [target_define]
55 is_enabled = True
56 opcode_file = open (os.path.join (srcdir, "mini-ops.h"))
58 # Implement a subset of a c preprocessor, only handling #ifdef/#endif directives
60 for line in opcode_file:
61 line = line.strip ()
62 # print ("{0} {1}".format (line, is_enabled))
63 m = re.search (r'^\s*#if (.+)', line)
64 # FIXME: Check list of defines against an allowed list
65 if m != None:
66 is_enabled = False
67 parts = m.group (1).split ("||")
68 for part in parts:
69 part = part.strip ()
70 m = re.search (r'defined\((.+)\)', part)
71 if m == None:
72 print ("Unknown #ifdef line {0}".format (line))
73 exit (1)
74 define = m.group (1)
75 # Check that the file only contains TARGET_... defines
76 if not define in allowed_defines:
77 print ("Unknown define '{0}' in mini-ops.h".format (define))
78 exit (1)
79 for d in enabled:
80 if d == define:
81 is_enabled = True
82 elif line == "#endif":
83 is_enabled = True
84 else:
85 if is_enabled and line.startswith ("MINI_OP"):
86 m = re.search (r"MINI_OP\(\w+\s*\,\s*\"([^\"]+)\", (\w+), (\w+), (\w+)\)", line)
87 if m != None:
88 opcodes [m.group (1)] = OpDef(opcode_id, m.group (1), m.group (2), m.group (3), m.group (4))
89 else:
90 m = re.search (r"MINI_OP3\(\w+\s*\,\s*\"([^\"]+)\", (\w+), (\w+), (\w+), (\w+)\)", line)
91 if m != None:
92 opcodes [m.group (1)] = OpDef(opcode_id, m.group (1), m.group (2), m.group (3), m.group (4))
93 else:
94 print ("Unable to parse line: '{0}'".format (line))
95 exit (1)
96 opcode_id += 1
97 opcode_file.close ()
98 return opcodes
100 def parse_input(infile, opcodes):
102 # Comments are pound sign to end of string.
103 remove_comments = re.compile ("#.*")
105 for line in infile:
106 line = line.strip ()
107 # remove comments
108 line = re.sub (remove_comments, "", line)
110 # Ignore empty lines -- including it was just a comment.
111 if line == "":
112 continue
113 # Lines look like:
114 # expand_i2: dest:x src1:i len:18
115 parts = line.split (" ")
116 op_name = parts [0][:-1]
117 if not op_name in opcodes:
118 print ("Unknown opcode '{0}'".format (op_name))
119 exit (1)
120 opcode = opcodes [op_name]
121 opcode.used = True
122 for part in parts[1:]:
123 part = part.strip ()
124 if part == "":
125 continue
126 [spec, value] = part.split (":")
127 if spec == "dest":
128 if opcode.dest_def == "NONE":
129 print ("Inconsistent dreg for opcode '{0}'".format (op_name))
130 opcode.spec [MONO_INST_DEST] = value
131 elif spec == "src1":
132 if opcode.src1_def == "NONE":
133 print ("Inconsistent src1 for opcode '{0}'".format (op_name))
134 opcode.spec [MONO_INST_SRC1] = value
135 elif spec == "src2":
136 if opcode.src2_def == "NONE":
137 print ("Inconsistent src2 for opcode '{0}'".format (op_name))
138 opcode.spec [MONO_INST_SRC2] = value
139 elif spec == "src3":
140 opcode.spec [MONO_INST_SRC3] = value
141 elif spec == "len":
142 opcode.spec [MONO_INST_LEN] = chr(int(value))
143 elif spec == "clob":
144 opcode.spec [MONO_INST_CLOB] = value
145 else:
146 print ("Unknown specifier '{0}' for opcode '{0}'".format (spec))
147 exit (1)
149 def gen_output(f, opcodes):
150 sorted_opcodes = []
151 for op in opcodes.values ():
152 sorted_opcodes.append (op)
153 sorted_opcodes.sort (key=lambda op: op.num)
155 f.write ("/* File automatically generated by genmdesc.py, don't change */\n\n")
157 # Write desc table
159 f.write ("const MonoInstSpec mono_{0} [] = {{\n".format (symbol_name))
160 f.write (" {{")
162 for i in range(MONO_INST_MAX):
163 f.write (" 0")
164 if i != MONO_INST_MAX - 1:
165 f.write (", ")
166 f.write ("}}, // null entry\n")
167 idx = 1
168 row = 40
169 for op in sorted_opcodes:
170 if not op.used:
171 continue
172 try:
173 if row == 40:
174 f.write("// dest src1 src2 src3 len clob\n");
175 f.write("// ----- ----- ----- ---- ----- -----\n");
176 row = 0
177 else:
178 row += 1
179 f.write (" {{")
180 j = 0
181 for c in op.spec[:MONO_INST_MAX]:
182 j += 1
183 if c == "":
184 f.write (" 0")
185 elif c.isalnum () and ord (c) < 0x80:
186 f.write (" '%c'" % c)
187 elif ord (c) >= 0 and ord (c) <= 9:
188 f.write (" %d" % ord (c))
189 else:
190 f.write ("0x%02x" % ord (c))
191 if j < MONO_INST_MAX:
192 f.write (", ")
193 f.write ("}}, // %s\n" % op.name)
194 op.desc_idx = idx
195 idx += 1
196 except:
197 print ("Error emitting opcode '{0}': '{1}'.".format (op.name, sys.exc_info()))
198 f.write ("};\n")
200 # Write index table
201 f.write ("const guint16 mono_{0}_idx [] = {{\n".format (symbol_name))
202 for op in sorted_opcodes:
203 if not op.used:
204 f.write (" 0, // {0}\n".format (op.name))
205 else:
206 f.write (" {0}, // {1}\n".format (op.desc_idx, op.name))
207 f.write ("};\n\n")
210 # MAIN
213 if len (sys.argv) != 6:
214 usage ()
215 exit (1)
217 target_define = sys.argv [1]
218 srcdir = sys.argv [2]
219 outfile_name = sys.argv [3]
220 symbol_name = sys.argv [4]
221 infile_name = sys.argv [5]
223 # Parse mini-ops.h file for opcode metadata
224 opcodes = parse_mini_ops(target_define)
226 # Parse input file
227 infile = open (infile_name, 'r')
228 parse_input (infile, opcodes)
230 # Generate output
231 f = open (outfile_name, 'w')
232 gen_output (f, opcodes)
233 f.close ()