Changed current relation from BasicBlock to BasicBlockImpl, and Function
[jitcs.git] / tools / x86_instool.lua
blobac193e46f05ccd912f007402fd51b86a4ba0ff95
1 local _setfenv, _ipairs = setfenv, ipairs
2 local _open = io.open
3 local _match, _gmatch, _fmt = string.match, string.gmatch, string.format
4 local _gsub, _sub = string.gsub, string.sub
5 local _exec = os.execute
7 local function readfile(n)
8 local f = _open(n)
9 local ctnt = f:read("*a")
10 f:close()
11 return ctnt
12 end
14 local validModes = {ins2nasm32 = true, ins2nasm64 = true, nasm2as32 = true, nasm2as64 = true}
16 local MODE, insfile, p1, p2 = ...
17 MODE = string.lower(MODE or "")
18 assert(validModes[MODE], "mode missing")
19 assert(insfile, "insfile missing")
20 local nasmfile, nasmlstfile, asfile
21 if MODE == "ins2nasm32" or MODE == "nasm2as32" then
22 N = 32
23 else
24 N = 64
25 end
26 if MODE == "ins2nasm32" or MODE == "ins2nasm64" then
27 ALG = "ins2nasm"
28 nasmfile = p1
29 assert(nasmfile, ".nasm file not given")
30 else
31 ALG = "nasm2as"
32 nasmlstfile, asfile = p1, p2
33 assert(nasmlstfile and asfile, ".lst and .as file not given")
34 end
36 local prog, progcode = ""
37 local progstats = { scopes = {} }
38 local errors = false
39 local lineno = 1
40 for l in _gmatch(readfile(insfile), "([^\r\n]*)[\r\n]") do
41 --print(l)
42 if _match(l, "^|") then
43 if (_match(l, "^|%s*[Ff][Oo][Rr]%s*(%w+)%s*=%s*%[([^]]-)%]%s*[Dd][Oo]%s*$"))
44 then
45 local var, list = _match(l, "^|%s*[Ff][Oo][Rr]%s*(%w+)%s*=%s*%[([^]]-)%]%s*[Dd][Oo]%s*$")
46 local list2, list3 = {}, nil
47 for e in _gmatch(list, "([^,]+)") do
48 local e2 = _match(e, "^%s*(%S+)%s*$")
49 if e2 then
50 list2[#list2 + 1] = e2;
51 list3 = (list3 and (list3..", ") or "").._fmt("%q", e2)
52 end
53 end
54 if #list2 > 0 then
55 local sn = #progstats.scopes
56 progstats.scopes[sn+1] = {type = "for", start = lineno,
57 var = var, list = list2}
59 prog = prog .. "for k"..sn..",v"..sn.." in ipairs({"..list3.."}) do\n"
60 prog = prog .. " ENV."..var.." = v"..sn.."\n"
61 else
62 errors = true
63 print(lineno .. ": illegal list in for statement")
64 end
67 elseif (_match(l,"^|%s*[Ee][Nn][Dd][Ff][Oo][Rr]%s*$")) then
68 local sn = #progstats.scopes
69 if (sn > 0 and progstats.scopes[sn].type == "for") then
70 progstats.scopes[sn] = nil
71 prog = prog .. "end\n"
72 else
73 errors = true
74 print(lineno .. ": endfor without for scope")
75 end
76 elseif (_match(l,"^|%s*[Ll][Ee][Tt]%s*(%w+)%s*=%s*(.-)%s*$"))
77 then
78 local var, val = _match(l, "^|%s*[Ll][Ee][Tt]%s*(%w+)%s*=%s*(.-)%s*$")
79 prog = prog .. _fmt("ENV.%s = ENV:handleExpr(%q, %q, %d)\n", var, val, l, lineno)
80 else
81 errors = true
82 print(lineno .. ": illegal commandline "..l)
83 end
84 elseif _match(l,"^%s*$") then
85 -- ignore empty lines
86 else
87 prog = prog .. _fmt("ENV:handleLine(%q, %d)",l, lineno) .. "\n"
88 end
89 lineno = lineno + 1
90 end
91 if (#progstats.scopes > 0) then
92 errors = true
93 print(lineno .. ": not all scopes have been closed")
94 end
95 if errors then return end
96 progcode = loadstring(prog)
97 if not progcode then
98 print("cannot compile program")
99 return
101 local ENV = {}
102 function ENV.handleLine(self, line, lineno)
103 local function replacer(expr)
104 local repfnc = loadstring("return "..expr)
105 if not repfnc then
106 errors = true
107 print(lineno .. ": illegal expression "..expr)
108 return "ERROR"
109 else
110 _setfenv(repfnc, self)
111 return repfnc() or ""
114 local function filter(expr)
115 local repfnc = loadstring("return "..expr)
116 if not repfnc then
117 errors = true
118 print(lineno .. ": illegal expression "..expr)
119 return "??"
120 else
121 _setfenv(repfnc, self)
122 return repfnc() and "" or "??"
125 line = _gsub(line, "$(%b())", replacer)
127 if _match(line, "^(%d+):") then
128 local m = _match(line, "^(%d+):")
129 if m ~= "32" and m ~= "64" then
130 errors = true
131 print(lineno .. ": illegal architecture "..m)
132 return
133 else
134 if self.arch ~= m then return end
135 line = _sub(line, #m + 2)
138 line = _gsub(line, "%?(%b())", filter)
139 if (_sub(line,1,2) == "??") then return end
140 if self.tgt == "nasm" then
141 line = _gsub(line, "%b{}", "")
142 line = _gsub(line, "[<>]", "")
144 if self.tgt == "jitcs" then
145 line = _gsub(line, "%b<>", "")
146 line = _gsub(line, "[{}]", "")
149 self:write(line)
151 function ENV.handleExpr(self, line, lineno)
152 local function replacer(expr)
153 local repfnc = loadstring("return "..expr)
154 if not repfnc then
155 errors = true
156 print(lineno .. ": illegal expression "..expr)
157 return "ERROR"
158 else
159 _setfenv(repfnc, self)
160 return repfnc() or ""
163 line = _gsub(line, "$(%b())", replacer)
164 return line
166 function ENV.write(self, line)
167 if self.tgt == "jitcs" and self.lst and _sub(line,1,1) ~= ":" and not _match(line,"^%s*$") then
168 self.lstpos = self.lstpos + 1
169 line = line .. " ==> " .. (self.lst[self.lstpos] or "")
171 if self.file then
172 self.file:write(line)
173 self.file:write("\n")
174 else
175 print(line)
178 function ENV.X86(Y)
179 return tonumber(Y) == 64 and "64:" or ""
181 function ENV.MSZ(Y)
182 if Y == "DEF" then return "" end
183 return Y
185 function ENV.MVSZ(M)
186 if M == "S" then return "32" end
187 if M == "D" then return "64" end
188 return ""
190 function ENV.MVHSZ(Y, D)
191 if tonumber(Y) == 128 or tonumber(Y) == 256 or tonumber(Y) == 512 then
192 return tostring(tonumber(Y) / (D and tonumber(D) or 2))
194 print("VSZ error", Y)
195 return "ERROR"
197 function ENV.RSZ(Y)
198 if Y == "DEF" then return "R" end
199 if tonumber(Y) == 8 then return "B" end
200 if tonumber(Y) == 16 then return "H" end
201 if tonumber(Y) == 32 then return "W" end
202 if tonumber(Y) == 64 then return "D" end
203 print("RSZ error", Y)
204 return "ERROR"
206 function ENV.VSZ(Y)
207 if tonumber(Y) == 128 then return "X" end
208 if tonumber(Y) == 256 then return "Y" end
209 if tonumber(Y) == 512 then return "Z" end
210 print("VSZ error", Y)
211 return "ERROR"
213 function ENV.VHSZ(Y)
214 if tonumber(Y) == 128 then return "X" end
215 if tonumber(Y) == 256 then return "X" end
216 if tonumber(Y) == 512 then return "Y" end
217 print("VHSZ error", Y)
218 return "ERROR"
220 function ENV.VOSZ(Y,N)
221 if tonumber(Y) == tonumber(N) then return "" end
222 return tostring(N)
224 function ENV.RSZ2(Y)
225 -- if Y == "DEF" then return "ERROR" end
226 if tonumber(Y) == 8 then return "B" end
227 if tonumber(Y) == 16 then return "W" end
228 if tonumber(Y) == 32 then return "D" end
229 if tonumber(Y) == 64 then return "Q" end
230 return "ERROR"
232 function ENV.NASMSZ(Y)
233 if Y == "DEF" then Y = ENV.arch end
234 if tonumber(Y) == 8 then return "byte" end
235 if tonumber(Y) == 16 then return "word" end
236 if tonumber(Y) == 32 then return "dword" end
237 if tonumber(Y) == 64 then return "qword" end
238 if tonumber(Y) == 128 then return "oword" end
239 if tonumber(Y) == 256 then return "yword" end
240 return "ERROR"
242 function ENV.MAX(A,B)
243 if A == "DEF" then A = ENV.arch end
244 if B == "DEF" then B = ENV.arch end
245 return tonumber(A) > tonumber(B) and A or B
247 ENV.RNAME_Table_R2R = {ECX = "RCX", EAX = "RAX", EBX = "RBX", EDX = "RDX",
248 YMM0 = "XMM0", YMM1 = "XMM1", YMM2 = "XMM2", YMM3 = "XMM3"}
249 ENV.RNAME_Table_R2N = {
250 RAX = {["8"] = "AL", ["16"] = "AX", ["32"] = "EAX", ["64"]= "RAX"},
251 RBX = {["8"] = "BL", ["16"] = "BX", ["32"] = "EBX", ["64"]= "RBX"},
252 RCX = {["8"] = "CL", ["16"] = "CX", ["32"] = "ECX", ["64"]= "RCX"},
253 RDX = {["8"] = "DL", ["16"] = "DX", ["32"] = "EDX", ["64"]= "RDX"},
255 function ENV.RCONST(I, Y)
256 if Y == "DEF" then Y = ENV.arch end
257 return math.mod(I, math.pow(2,math.min(tonumber(Y),32)))
259 function ENV.RNAME(R, SZ)
260 if SZ == "DEF" then SZ = ENV.arch end
261 R = ENV.RNAME_Table_R2R[R] or R
262 return ENV.RNAME_Table_R2N[R][tostring(SZ)] or "ERROR"
264 function ENV.RNAMEDEF(R, SZ)
265 if SZ == "DEF" then SZ = 64 end
266 R = ENV.RNAME_Table_R2R[R] or R
267 return ENV.RNAME_Table_R2N[R][tostring(SZ)] or "ERROR"
269 ENV.VNAME_Table_R2N = {
270 XMM0 = {["64"] = "XMM0", ["128"] = "XMM0", ["256"] = "YMM0", ["512"] = "ZMM0"},
271 XMM1 = {["64"] = "XMM1", ["128"] = "XMM1", ["256"] = "YMM1", ["512"] = "ZMM1"},
272 XMM2 = {["64"] = "XMM2", ["128"] = "XMM2", ["256"] = "YMM2", ["512"] = "ZMM2"},
273 XMM3 = {["64"] = "XMM3", ["128"] = "XMM3", ["256"] = "YMM3", ["512"] = "ZMM3"},
274 XMM4 = {["64"] = "XMM4", ["128"] = "XMM4", ["256"] = "YMM4", ["512"] = "ZMM4"},
276 function ENV.VNAME(R, SZ)
277 if SZ == "DEF" then SZ = ENV.arch end
278 R = ENV.RNAME_Table_R2R[R] or R
279 return ENV.VNAME_Table_R2N[R][tostring(SZ)] or "ERROR"
281 function ENV.VHNAME(R, SZ)
282 if SZ == "DEF" then SZ = ENV.arch end
283 R = ENV.RNAME_Table_R2R[R] or R
284 return ENV.VNAME_Table_R2N[R][tostring(tonumber(SZ)/2)] or "ERROR"
287 local function readnasmlist(v)
288 local result = {}
289 for l in _gmatch(readfile(v), "([^\r\n]*)[\r\n]") do
290 local line, addr, opcodes, cmd = _match(l,
291 "^([ %d][ %d][ %d][ %d][ %d][ %d])"
292 .. " ([ %x][ %x][ %x][ %x][ %x][ %x][ %x][ %x])"
293 .. " (%x*)"
294 .. "%s*(.-)%s*$")
295 if opcodes and #opcodes > 0 then result[#result + 1] = opcodes end
297 return result
300 ENV.arch = tostring(N)
301 ENV.ipairs = _ipairs
302 ENV.ENV = ENV
303 _setfenv(progcode, ENV)
304 if ALG == "ins2nasm" then
305 ENV.file = _open(nasmfile, "w")
306 ENV.tgt = "nasm"
307 ENV:write(" bits " .. ENV.arch)
308 if N == 32 then
309 ENV:write("%define RAX EAX")
310 ENV:write("%define RBX EBX")
311 ENV:write("%define RCX ECX")
312 ENV:write("%define RDX EDX")
314 progcode()
315 ENV:write(" ret")
316 ENV.file:close()
317 elseif ALG == "nasm2as" then
318 local lst = readnasmlist(nasmlstfile)
320 ENV.file = _open(asfile, "w")
321 ENV.tgt = "jitcs"
322 ENV:write("<== test")
323 ENV:write("@fun: void -> void")
324 ENV:write("@strategy: direct")
325 ENV:write(":entry")
326 ENV.lst = lst
327 ENV.lstpos = 0
328 progcode()
329 ENV:write(" ret |")
330 if ENV.lstpos ~= #ENV.lst then
331 print("length difference between nasm and jitcs versions ("..N.."bit)")
333 ENV.lst = nil
334 ENV.file:close()