gen_tables.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #!/usr/bin/python3
  2. #
  3. # gen_tables.py - generate blank table or load (default) table into cu_main.c
  4. #
  5. # Copyright (C) 2013,2016-2017,2021 Matthew R. Wette
  6. #
  7. # usage for new ../VEX/pub/libvex_ir.h (new release)
  8. # $ ./gen_tables.py -d # this generated cuts/zero.cut.new
  9. # In cuts, update default.cut from zero.cut.new
  10. # Then execute the following:
  11. # usage for working cuts/default.cut table
  12. # $ ./gen_tables.py
  13. #
  14. # This program is free software; you can redistribute it and/or
  15. # modify it under the terms of the GNU General Public License as
  16. # published by the Free Software Foundation; either version 2 of the
  17. # License, or (at your option) any later version.
  18. #
  19. # This program is distributed in the hope that it will be useful, but
  20. # WITHOUT ANY WARRANTY; without even the implied warranty of
  21. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. # General Public License for more details.
  23. #
  24. # You should have received a copy of the GNU General Public License
  25. # along with this program; if not, see <http://www.gnu.org/licenses/>
  26. #
  27. # The GNU General Public License is contained in the file COPYING.
  28. #
  29. # v170626a - mwette@alumni.caltech.edu
  30. import sys, os, re
  31. from string import whitespace
  32. import pdb
  33. from gen_utils import write_w_fill, replace_in_code, move_if_changed
  34. #typedef
  35. # enum
  36. # {
  37. # Iop_INVALID=0x12345, Iop_First, ...
  38. # }
  39. # IROp;
  40. rx0 = re.compile(r"^((?:[^/]|(?:/[^/]))*)//.*")
  41. rx1c = re.compile(r"^((?:[^*]|(?:\*[^/]))*)(/\*(?:[^*]|(?:\*[^/]))*\*/)(.*)$")
  42. def readin_ir(name):
  43. """
  44. Read libvex_ir.h and load lines from guts of the Iop enum to get all ops.
  45. """
  46. startname = name + "_INVALID"
  47. lines = []
  48. f0 = open("../VEX/pub/libvex_ir.h", "r")
  49. l0 = f0.readline()
  50. while l0:
  51. l = l0.strip()
  52. if l.find(startname) >= 0:
  53. break
  54. l0 = f0.readline()
  55. while l0:
  56. l = l0.strip()
  57. if l.startswith("}"):
  58. break
  59. m = rx0.match(l)
  60. if m:
  61. l = m.group(1)
  62. lines.append(l)
  63. l0 = f0.readline()
  64. f0.close()
  65. return lines
  66. def parse_enum(lines):
  67. """
  68. Given lines from enum guts, return list of enum names.
  69. """
  70. text0 = " ".join(lines)
  71. while True:
  72. m = rx1c.match(text0)
  73. if not m:
  74. break
  75. text0 = m.group(1) + m.group(3)
  76. text1 = ""
  77. for c in text0:
  78. if c in whitespace:
  79. continue
  80. else:
  81. text1 += c
  82. enums = text1.split(",")
  83. return enums
  84. def get_enums(name):
  85. lines = readin_ir(name)
  86. enums = parse_enum(lines)
  87. #
  88. e,val0 = enums[0].split("=")
  89. enums[0] = e
  90. return enums
  91. def dump_blank_counts(lenums, oenums, filename):
  92. f1 = open(filename, 'w')
  93. f1.write("# valgrind/cputil count table\n")
  94. f1.write("#\n")
  95. f1.write("1\tdivisor\n")
  96. f1.write("#\n")
  97. f1.write("# load types\n")
  98. for e in lenums[1:]:
  99. f1.write("%d\t%s\n" % (0, e))
  100. f1.write("# other ops\n")
  101. for e in oenums[1:]:
  102. f1.write("%d\t%s\n" % (0, e))
  103. f1.close()
  104. pass
  105. propl = ('divisor')
  106. def read_counts(filename, lenums, oenums):
  107. """
  108. Read lines from filename.
  109. Skip until first lenum found, then match lines to lenum names.
  110. Skip until first oenum found, then match lines to oenum names.
  111. If mismatch, raise exception. The lines should be of the form:
  112. # <comment>
  113. or
  114. <count> <opname>
  115. Return two lists: [(ldop,val),...],[(enum, val),...]
  116. The list elements are tuples of (string,string).
  117. """
  118. nld = len(lenums)
  119. nop = len(oenums)
  120. tdict = {}
  121. ty_pairs = []
  122. op_pairs = []
  123. #
  124. f0 = open(filename, "r"); n0 = 0
  125. l0 = f0.readline(); n0 += 1
  126. # read properties
  127. while l0:
  128. if l0[0] == '#':
  129. l0 = f0.readline(); n0 += 1
  130. continue
  131. c,s = l0.split()
  132. if s not in propl:
  133. break
  134. tdict[s] = c
  135. l0 = f0.readline(); n0 += 1
  136. pass
  137. # read load statements
  138. while l0:
  139. if l0[0] == '#':
  140. l0 = f0.readline(); n0 += 1
  141. continue
  142. c,s = l0.split()
  143. if s == lenums[1]: # skip INVALID = lenums[0]
  144. break
  145. l0 = f0.readline(); n0 += 1
  146. pass
  147. ty_pairs = [(lenums[0], "0")]
  148. i = 1 # skip INVALID
  149. while l0:
  150. c,s = l0.split()
  151. if s != lenums[i]:
  152. raise Exception("%s: line %d: mismatch: %s" % (filename, n0, s))
  153. ty_pairs.append((s,c))
  154. i = i + 1
  155. if i >= nld:
  156. break
  157. l0 = f0.readline(); n0 += 1
  158. if len(ty_pairs) != nld:
  159. raise Exception("count mismatch")
  160. tdict['ty_pairs'] = ty_pairs
  161. # read operations
  162. l0 = f0.readline(); n0 += 1
  163. while l0:
  164. if l0[0] == '#':
  165. l0 = f0.readline(); n0 += 1
  166. continue
  167. c,s = l0.split()
  168. if s == oenums[1]: # skip INVALID = lenums[0]
  169. break
  170. l0 = f0.readline(); n0 += 1
  171. op_pairs = [(oenums[0], "0")]
  172. i = 1 # skip INVALID
  173. while l0:
  174. c,s = l0.split()
  175. if s != oenums[i]:
  176. raise Exception("%s: line %d: mismatch: %s" % (filename, n0, s))
  177. op_pairs.append((s,c))
  178. i = i + 1
  179. if i >= nop:
  180. break
  181. l0 = f0.readline(); n0 += 1
  182. pass
  183. if len(op_pairs) != nop:
  184. pdb.set_trace()
  185. raise Exception("count mismatch")
  186. tdict['op_pairs'] = op_pairs
  187. #
  188. f0.close()
  189. #
  190. return tdict
  191. def fill_names(tag, names, f1):
  192. """
  193. Write out list of enum names as array of C-strings.
  194. """
  195. f1.write("#define NUM_%s %d\n" % (tag.upper(), len(names)))
  196. if not names[0].endswith("INVALID"):
  197. raise Exception("expecting INVALID as first element")
  198. f1.write("static const HChar *cu_%s_names[] = {\n " % (tag,))
  199. col = 2
  200. for e in names:
  201. col = write_w_fill(f1, col, " \"%s\"," % (e,))
  202. f1.write("\n};\n")
  203. def fill_counts(tag, vals, f1):
  204. """
  205. Write out count array.
  206. """
  207. f1.write("static UShort cu_%s_counts[] = {\n " % (tag,))
  208. col = 2
  209. for c in vals:
  210. col = write_w_fill(f1, col, " %s," % (c,))
  211. f1.write("\n};\n")
  212. def fill_all(tdict, f1):
  213. lpairs = tdict['ty_pairs']
  214. opairs = tdict['op_pairs']
  215. divizr = tdict['divisor']
  216. fill_names("op", list(map(lambda p: p[0], opairs)), f1)
  217. f1.write("\n")
  218. fill_counts("op", list(map(lambda p: p[1], opairs)), f1)
  219. f1.write("\n")
  220. fill_names("ld", list(map(lambda p: p[0], lpairs)), f1)
  221. f1.write("\n")
  222. fill_counts("ld", list(map(lambda p: p[1], lpairs)), f1)
  223. f1.write("\n")
  224. f1.write("static UWord cu_divisor = %s;\n" % divizr)
  225. # ========================================
  226. ty_enums = None
  227. op_enums = None
  228. def get_all_enums():
  229. global ty_enums, op_enums
  230. if not op_enums:
  231. op_enums = get_enums("Iop")
  232. if not ty_enums:
  233. ty_enums = get_enums("Ity")
  234. from getopt import getopt
  235. if True:
  236. opts, args = getopt(sys.argv[1:], "d")
  237. for opt in opts:
  238. k,v = opt
  239. if k == "-d":
  240. print("dumping to cuts/zero.cut.new ...")
  241. get_all_enums()
  242. dump_blank_counts(ty_enums, op_enums, "cuts/zero.cut.new")
  243. sys.exit(0)
  244. else:
  245. print("updating cu_main.c ...")
  246. get_all_enums()
  247. tdict = read_counts("cuts/default.cut", ty_enums, op_enums)
  248. replace_in_code(tdict, "cu_main.c", "count_tables", fill_all)
  249. res = move_if_changed("cu_main.c")
  250. if res:
  251. print("cu_main.c changed")
  252. else:
  253. print("cu_main.c not changed")
  254. # --- last line of gen_tables.py ---