gen-insn-attr-x86.awk 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #!/bin/awk -f
  2. # gen-insn-attr-x86.awk: Instruction attribute table generator
  3. # Written by Masami Hiramatsu <mhiramat@redhat.com>
  4. #
  5. # Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
  6. # Awk implementation sanity check
  7. function check_awk_implement() {
  8. if (sprintf("%x", 0) != "0")
  9. return "Your awk has a printf-format problem."
  10. return ""
  11. }
  12. # Clear working vars
  13. function clear_vars() {
  14. delete table
  15. delete lptable2
  16. delete lptable1
  17. delete lptable3
  18. eid = -1 # escape id
  19. gid = -1 # group id
  20. aid = -1 # AVX id
  21. tname = ""
  22. }
  23. BEGIN {
  24. # Implementation error checking
  25. awkchecked = check_awk_implement()
  26. if (awkchecked != "") {
  27. print "Error: " awkchecked > "/dev/stderr"
  28. print "Please try to use gawk." > "/dev/stderr"
  29. exit 1
  30. }
  31. # Setup generating tables
  32. print "/* x86 opcode map generated from x86-opcode-map.txt */"
  33. print "/* Do not change this code. */\n"
  34. ggid = 1
  35. geid = 1
  36. gaid = 0
  37. delete etable
  38. delete gtable
  39. delete atable
  40. opnd_expr = "^[A-Za-z/]"
  41. ext_expr = "^\\("
  42. sep_expr = "^\\|$"
  43. group_expr = "^Grp[0-9A-Za-z]+"
  44. imm_expr = "^[IJAOL][a-z]"
  45. imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  46. imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  47. imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
  48. imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
  49. imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
  50. imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
  51. imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
  52. imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
  53. imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
  54. imm_flag["Ob"] = "INAT_MOFFSET"
  55. imm_flag["Ov"] = "INAT_MOFFSET"
  56. imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  57. modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
  58. force64_expr = "\\([df]64\\)"
  59. rex_expr = "^REX(\\.[XRWB]+)*"
  60. fpu_expr = "^ESC" # TODO
  61. lprefix1_expr = "\\((66|!F3)\\)"
  62. lprefix2_expr = "\\(F3\\)"
  63. lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
  64. lprefix_expr = "\\((66|F2|F3)\\)"
  65. max_lprefix = 4
  66. # All opcodes starting with lower-case 'v' or with (v1) superscript
  67. # accepts VEX prefix
  68. vexok_opcode_expr = "^v.*"
  69. vexok_expr = "\\(v1\\)"
  70. # All opcodes with (v) superscript supports *only* VEX prefix
  71. vexonly_expr = "\\(v\\)"
  72. prefix_expr = "\\(Prefix\\)"
  73. prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
  74. prefix_num["REPNE"] = "INAT_PFX_REPNE"
  75. prefix_num["REP/REPE"] = "INAT_PFX_REPE"
  76. prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
  77. prefix_num["XRELEASE"] = "INAT_PFX_REPE"
  78. prefix_num["LOCK"] = "INAT_PFX_LOCK"
  79. prefix_num["SEG=CS"] = "INAT_PFX_CS"
  80. prefix_num["SEG=DS"] = "INAT_PFX_DS"
  81. prefix_num["SEG=ES"] = "INAT_PFX_ES"
  82. prefix_num["SEG=FS"] = "INAT_PFX_FS"
  83. prefix_num["SEG=GS"] = "INAT_PFX_GS"
  84. prefix_num["SEG=SS"] = "INAT_PFX_SS"
  85. prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
  86. prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
  87. prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
  88. clear_vars()
  89. }
  90. function semantic_error(msg) {
  91. print "Semantic error at " NR ": " msg > "/dev/stderr"
  92. exit 1
  93. }
  94. function debug(msg) {
  95. print "DEBUG: " msg
  96. }
  97. function array_size(arr, i,c) {
  98. c = 0
  99. for (i in arr)
  100. c++
  101. return c
  102. }
  103. /^Table:/ {
  104. print "/* " $0 " */"
  105. if (tname != "")
  106. semantic_error("Hit Table: before EndTable:.");
  107. }
  108. /^Referrer:/ {
  109. if (NF != 1) {
  110. # escape opcode table
  111. ref = ""
  112. for (i = 2; i <= NF; i++)
  113. ref = ref $i
  114. eid = escape[ref]
  115. tname = sprintf("inat_escape_table_%d", eid)
  116. }
  117. }
  118. /^AVXcode:/ {
  119. if (NF != 1) {
  120. # AVX/escape opcode table
  121. aid = $2
  122. if (gaid <= aid)
  123. gaid = aid + 1
  124. if (tname == "") # AVX only opcode table
  125. tname = sprintf("inat_avx_table_%d", $2)
  126. }
  127. if (aid == -1 && eid == -1) # primary opcode table
  128. tname = "inat_primary_table"
  129. }
  130. /^GrpTable:/ {
  131. print "/* " $0 " */"
  132. if (!($2 in group))
  133. semantic_error("No group: " $2 )
  134. gid = group[$2]
  135. tname = "inat_group_table_" gid
  136. }
  137. function print_table(tbl,name,fmt,n)
  138. {
  139. print "const insn_attr_t " name " = {"
  140. for (i = 0; i < n; i++) {
  141. id = sprintf(fmt, i)
  142. if (tbl[id])
  143. print " [" id "] = " tbl[id] ","
  144. }
  145. print "};"
  146. }
  147. /^EndTable/ {
  148. if (gid != -1) {
  149. # print group tables
  150. if (array_size(table) != 0) {
  151. print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
  152. "0x%x", 8)
  153. gtable[gid,0] = tname
  154. }
  155. if (array_size(lptable1) != 0) {
  156. print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
  157. "0x%x", 8)
  158. gtable[gid,1] = tname "_1"
  159. }
  160. if (array_size(lptable2) != 0) {
  161. print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
  162. "0x%x", 8)
  163. gtable[gid,2] = tname "_2"
  164. }
  165. if (array_size(lptable3) != 0) {
  166. print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
  167. "0x%x", 8)
  168. gtable[gid,3] = tname "_3"
  169. }
  170. } else {
  171. # print primary/escaped tables
  172. if (array_size(table) != 0) {
  173. print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
  174. "0x%02x", 256)
  175. etable[eid,0] = tname
  176. if (aid >= 0)
  177. atable[aid,0] = tname
  178. }
  179. if (array_size(lptable1) != 0) {
  180. print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
  181. "0x%02x", 256)
  182. etable[eid,1] = tname "_1"
  183. if (aid >= 0)
  184. atable[aid,1] = tname "_1"
  185. }
  186. if (array_size(lptable2) != 0) {
  187. print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
  188. "0x%02x", 256)
  189. etable[eid,2] = tname "_2"
  190. if (aid >= 0)
  191. atable[aid,2] = tname "_2"
  192. }
  193. if (array_size(lptable3) != 0) {
  194. print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
  195. "0x%02x", 256)
  196. etable[eid,3] = tname "_3"
  197. if (aid >= 0)
  198. atable[aid,3] = tname "_3"
  199. }
  200. }
  201. print ""
  202. clear_vars()
  203. }
  204. function add_flags(old,new) {
  205. if (old && new)
  206. return old " | " new
  207. else if (old)
  208. return old
  209. else
  210. return new
  211. }
  212. # convert operands to flags.
  213. function convert_operands(count,opnd, i,j,imm,mod)
  214. {
  215. imm = null
  216. mod = null
  217. for (j = 1; j <= count; j++) {
  218. i = opnd[j]
  219. if (match(i, imm_expr) == 1) {
  220. if (!imm_flag[i])
  221. semantic_error("Unknown imm opnd: " i)
  222. if (imm) {
  223. if (i != "Ib")
  224. semantic_error("Second IMM error")
  225. imm = add_flags(imm, "INAT_SCNDIMM")
  226. } else
  227. imm = imm_flag[i]
  228. } else if (match(i, modrm_expr))
  229. mod = "INAT_MODRM"
  230. }
  231. return add_flags(imm, mod)
  232. }
  233. /^[0-9a-f]+\:/ {
  234. if (NR == 1)
  235. next
  236. # get index
  237. idx = "0x" substr($1, 1, index($1,":") - 1)
  238. if (idx in table)
  239. semantic_error("Redefine " idx " in " tname)
  240. # check if escaped opcode
  241. if ("escape" == $2) {
  242. if ($3 != "#")
  243. semantic_error("No escaped name")
  244. ref = ""
  245. for (i = 4; i <= NF; i++)
  246. ref = ref $i
  247. if (ref in escape)
  248. semantic_error("Redefine escape (" ref ")")
  249. escape[ref] = geid
  250. geid++
  251. table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
  252. next
  253. }
  254. variant = null
  255. # converts
  256. i = 2
  257. while (i <= NF) {
  258. opcode = $(i++)
  259. delete opnds
  260. ext = null
  261. flags = null
  262. opnd = null
  263. # parse one opcode
  264. if (match($i, opnd_expr)) {
  265. opnd = $i
  266. count = split($(i++), opnds, ",")
  267. flags = convert_operands(count, opnds)
  268. }
  269. if (match($i, ext_expr))
  270. ext = $(i++)
  271. if (match($i, sep_expr))
  272. i++
  273. else if (i < NF)
  274. semantic_error($i " is not a separator")
  275. # check if group opcode
  276. if (match(opcode, group_expr)) {
  277. if (!(opcode in group)) {
  278. group[opcode] = ggid
  279. ggid++
  280. }
  281. flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
  282. }
  283. # check force(or default) 64bit
  284. if (match(ext, force64_expr))
  285. flags = add_flags(flags, "INAT_FORCE64")
  286. # check REX prefix
  287. if (match(opcode, rex_expr))
  288. flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
  289. # check coprocessor escape : TODO
  290. if (match(opcode, fpu_expr))
  291. flags = add_flags(flags, "INAT_MODRM")
  292. # check VEX codes
  293. if (match(ext, vexonly_expr))
  294. flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
  295. else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
  296. flags = add_flags(flags, "INAT_VEXOK")
  297. # check prefixes
  298. if (match(ext, prefix_expr)) {
  299. if (!prefix_num[opcode])
  300. semantic_error("Unknown prefix: " opcode)
  301. flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
  302. }
  303. if (length(flags) == 0)
  304. continue
  305. # check if last prefix
  306. if (match(ext, lprefix1_expr)) {
  307. lptable1[idx] = add_flags(lptable1[idx],flags)
  308. variant = "INAT_VARIANT"
  309. }
  310. if (match(ext, lprefix2_expr)) {
  311. lptable2[idx] = add_flags(lptable2[idx],flags)
  312. variant = "INAT_VARIANT"
  313. }
  314. if (match(ext, lprefix3_expr)) {
  315. lptable3[idx] = add_flags(lptable3[idx],flags)
  316. variant = "INAT_VARIANT"
  317. }
  318. if (!match(ext, lprefix_expr)){
  319. table[idx] = add_flags(table[idx],flags)
  320. }
  321. }
  322. if (variant)
  323. table[idx] = add_flags(table[idx],variant)
  324. }
  325. END {
  326. if (awkchecked != "")
  327. exit 1
  328. # print escape opcode map's array
  329. print "/* Escape opcode map array */"
  330. print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
  331. "[INAT_LSTPFX_MAX + 1] = {"
  332. for (i = 0; i < geid; i++)
  333. for (j = 0; j < max_lprefix; j++)
  334. if (etable[i,j])
  335. print " ["i"]["j"] = "etable[i,j]","
  336. print "};\n"
  337. # print group opcode map's array
  338. print "/* Group opcode map array */"
  339. print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
  340. "[INAT_LSTPFX_MAX + 1] = {"
  341. for (i = 0; i < ggid; i++)
  342. for (j = 0; j < max_lprefix; j++)
  343. if (gtable[i,j])
  344. print " ["i"]["j"] = "gtable[i,j]","
  345. print "};\n"
  346. # print AVX opcode map's array
  347. print "/* AVX opcode map array */"
  348. print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
  349. "[INAT_LSTPFX_MAX + 1] = {"
  350. for (i = 0; i < gaid; i++)
  351. for (j = 0; j < max_lprefix; j++)
  352. if (atable[i,j])
  353. print " ["i"]["j"] = "atable[i,j]","
  354. print "};"
  355. }