gen-insn-attr-x86.awk 11 KB

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