add pass 4, 5, 6 and let it can print basic assembly code
This commit is contained in:
parent
1afc0dd8e1
commit
eea281bc38
6 changed files with 253 additions and 22 deletions
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# TComp
|
||||||
|
A practice of Essential of Complication in Julia
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- julia
|
||||||
|
- [Match.jl](github.com/JuliaServices/Match.jl)
|
||||||
|
|
||||||
|
## instruction
|
||||||
|
`./src/TComp.jl [.tc file]`
|
||||||
|
|
||||||
|
the output assembly code is `./a.c` in AT&T assembly langauge.
|
||||||
|
|
||||||
|
to make it executable, please use `gcc`: `gcc ./a.c -o output.out`
|
||||||
|
|
||||||
|
the example `.tc` file is in `./test`
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
- parser for a + b + c .. and a * b * c
|
59
misc/vertexcoloring.jl
Normal file
59
misc/vertexcoloring.jl
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
graph = [['a', 'b'], ['b', 'c'], ['e', 'd'], ['e', 'a'], ['a', 'c'], ['b','e'], ['e','c']]
|
||||||
|
|
||||||
|
|
||||||
|
function vertexColoring(graph)
|
||||||
|
notDefined = -1
|
||||||
|
|
||||||
|
function getColor(v, color)
|
||||||
|
if !(v in keys(color))
|
||||||
|
return -1
|
||||||
|
else
|
||||||
|
return color[v]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vertices = Set(vcat(graph...))
|
||||||
|
verticesList = collect(vertices)
|
||||||
|
|
||||||
|
verticesMapping = map(x -> [x, Set()], verticesList)
|
||||||
|
|
||||||
|
adjacentNodes = Dict(verticesMapping)
|
||||||
|
|
||||||
|
for link in graph
|
||||||
|
a = link[1]
|
||||||
|
b = link[2]
|
||||||
|
push!(adjacentNodes[a], b)
|
||||||
|
push!(adjacentNodes[b], a)
|
||||||
|
end
|
||||||
|
|
||||||
|
sort!(verticesList, by=x -> length(adjacentNodes[x]), rev=true)
|
||||||
|
|
||||||
|
color = Dict()
|
||||||
|
|
||||||
|
println(verticesList)
|
||||||
|
|
||||||
|
|
||||||
|
for i in verticesList
|
||||||
|
i_adjacents = adjacentNodes[i]
|
||||||
|
println(i_adjacents)
|
||||||
|
i_adjacents_color_set = Set(map(x -> getColor(x, color), collect(i_adjacents)))
|
||||||
|
i_adjacents_color_list = sort(collect(i_adjacents_color_set))
|
||||||
|
|
||||||
|
if i_adjacents_color_list == [notDefined]
|
||||||
|
color[i] = 0
|
||||||
|
else
|
||||||
|
tmpId = 0
|
||||||
|
for i in i_adjacents_color_list
|
||||||
|
if tmpId == i
|
||||||
|
tmpId += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
color[i] = tmpId
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return color
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
println(vertexColoring(graph))
|
|
@ -7,7 +7,10 @@ to hold the results of complex subexpressions.
|
||||||
3. **OK** explicate_control makes the execution order of the program explicit. It converts
|
3. **OK** explicate_control makes the execution order of the program explicit. It converts
|
||||||
the abstract syntax tree representation into a graph in which each node is a
|
the abstract syntax tree representation into a graph in which each node is a
|
||||||
labeled sequence of statements and the edges are goto statements.
|
labeled sequence of statements and the edges are goto statements.
|
||||||
4. select_instructions handles the difference between LVar operations and x86
|
4. **OK** select_instructions handles the difference between LVar operations and x86
|
||||||
instructions. This pass converts each LVar operation to a short sequence of
|
instructions. This pass converts each LVar operation to a short sequence of
|
||||||
instructions that accomplishes the same task.
|
instructions that accomplishes the same task.
|
||||||
assign_homes
|
assign_homes
|
||||||
|
5. **OK**assign homes (register allocation)
|
||||||
|
6. **OK**patch instructions
|
||||||
|
7. **OK**prelude & conclusion
|
||||||
|
|
180
src/TComp.jl
180
src/TComp.jl
|
@ -13,9 +13,9 @@ inp = ARGS
|
||||||
f = open(ARGS[1], "r")
|
f = open(ARGS[1], "r")
|
||||||
prog = read(f, String)
|
prog = read(f, String)
|
||||||
|
|
||||||
print(prog)
|
#(prog)
|
||||||
parsed = Parser.totalParse(prog)
|
parsed = Parser.totalParse(prog)
|
||||||
print(parsed)
|
#print(parsed)
|
||||||
tmp_var_no = 0
|
tmp_var_no = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +93,6 @@ function explicitControlRemoveComplex(prog)
|
||||||
varNo = res[2]
|
varNo = res[2]
|
||||||
newBind = res[1].binds
|
newBind = res[1].binds
|
||||||
if newBind != []
|
if newBind != []
|
||||||
println("NEW_BIND:", newBind)
|
|
||||||
newResList = vcat(newResList, newBind)
|
newResList = vcat(newResList, newBind)
|
||||||
push!(new_exp_args, last(newBind)[2][2])
|
push!(new_exp_args, last(newBind)[2][2])
|
||||||
else
|
else
|
||||||
|
@ -103,7 +102,6 @@ function explicitControlRemoveComplex(prog)
|
||||||
end
|
end
|
||||||
push!(new_exp_body, new_exp_args)
|
push!(new_exp_body, new_exp_args)
|
||||||
|
|
||||||
println(newResList)
|
|
||||||
newBindVar = [("int", "id"), ("tmp" * string(varNo) , "id")]
|
newBindVar = [("int", "id"), ("tmp" * string(varNo) , "id")]
|
||||||
varNo += 1
|
varNo += 1
|
||||||
newBind = [("%let", "id"), newBindVar, new_exp_body]
|
newBind = [("%let", "id"), newBindVar, new_exp_body]
|
||||||
|
@ -118,10 +116,17 @@ function explicitControlRemoveComplex(prog)
|
||||||
end
|
end
|
||||||
|
|
||||||
function splitLet(binds, exp, varNo)
|
function splitLet(binds, exp, varNo)
|
||||||
|
|
||||||
if exp[1] == ("%let", "id")
|
if exp[1] == ("%let", "id")
|
||||||
res = rmComplexAux1(exp[3], varNo)
|
res = rmComplexAux1(exp[3], varNo)
|
||||||
|
|
||||||
binds = vcat(binds, res[1].binds)
|
binds = vcat(binds, res[1].binds)
|
||||||
new_exp = res[1].body
|
new_exp = res[1].body
|
||||||
|
|
||||||
|
#fix bug[("int", "id"), ("tmp1", "id")] => ("tmp1", "id")
|
||||||
|
if new_exp[1] == ("int", "id")
|
||||||
|
new_exp = new_exp[2]
|
||||||
|
end
|
||||||
new_bind = [("%let", "id"), exp[2], new_exp]
|
new_bind = [("%let", "id"), exp[2], new_exp]
|
||||||
push!(binds, new_bind)
|
push!(binds, new_bind)
|
||||||
|
|
||||||
|
@ -135,7 +140,17 @@ function explicitControlRemoveComplex(prog)
|
||||||
|
|
||||||
|
|
||||||
raw_res = rmComplex(prog)[1]
|
raw_res = rmComplex(prog)[1]
|
||||||
res = push!(raw_res.binds, raw_res.body)
|
raw_res_body = raw_res.body
|
||||||
|
#fix bug[("int", "id"), ("tmp1", "id")] => ("tmp1", "id")
|
||||||
|
if raw_res_body[1] == ("int", "id")
|
||||||
|
raw_res_body = [("%return", "id"), raw_res_body[2]]
|
||||||
|
end
|
||||||
|
|
||||||
|
if raw_res_body[2] == "int" # ("$8", "int")
|
||||||
|
raw_res_body = [("%return", "id"), raw_res_body]
|
||||||
|
end
|
||||||
|
|
||||||
|
res = push!(raw_res.binds, raw_res_body)
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -143,17 +158,30 @@ end
|
||||||
function assignInstruction(inp)
|
function assignInstruction(inp)
|
||||||
resList = []
|
resList = []
|
||||||
for i in inp
|
for i in inp
|
||||||
println(i)
|
|
||||||
@match i begin
|
@match i begin
|
||||||
|
[("%return", "id"), (val, t_val)] => begin
|
||||||
|
if t_val == "int"
|
||||||
|
val = "\$" * val
|
||||||
|
end
|
||||||
|
push!(resList, ["movq", val, "%rax"])
|
||||||
|
end
|
||||||
[("%let", "id"), [_ty, (id, "id")],
|
[("%let", "id"), [_ty, (id, "id")],
|
||||||
[("%prime", "id"), (op, _), [(rhs, _), (lhs, _)]]] =>
|
[("%prime", "id"), (op, _), [(lhs, lhs_t), (rhs, rhs_t)]]] =>
|
||||||
begin
|
begin
|
||||||
instr = ""
|
instr = ""
|
||||||
ops = ["+", "-", "*", "/"]
|
ops = ["+", "-", "*", "/"]
|
||||||
instrs = ["addq", "subq", "mulq", "divq"]
|
instrs = ["addq", "subq", "imulq", "divq"]
|
||||||
opIndex = findfirst(x -> x == op, ops)
|
opIndex = findfirst(x -> x == op, ops)
|
||||||
instr = instrs[opIndex]
|
instr = instrs[opIndex]
|
||||||
|
|
||||||
|
if lhs_t == "int"
|
||||||
|
lhs = "\$" * lhs
|
||||||
|
end
|
||||||
|
|
||||||
|
if rhs_t == "int"
|
||||||
|
rhs = "\$" * rhs
|
||||||
|
end
|
||||||
|
|
||||||
if rhs == id
|
if rhs == id
|
||||||
line1 = [instr, lhs, id]
|
line1 = [instr, lhs, id]
|
||||||
push!(resList, line1)
|
push!(resList, line1)
|
||||||
|
@ -169,13 +197,19 @@ function assignInstruction(inp)
|
||||||
#TODO [("%call", "id"), (op, _), args] => ...
|
#TODO [("%call", "id"), (op, _), args] => ...
|
||||||
end
|
end
|
||||||
|
|
||||||
[("%let", "id"), [_ty, (id, "id")], (val, _)] =>
|
[("%let", "id"), [_ty, (id, "id")], (val, t_val)] =>
|
||||||
begin
|
begin
|
||||||
|
if t_val == "int"
|
||||||
|
val = "\$" * val
|
||||||
|
end
|
||||||
line = ["movq", val, id]
|
line = ["movq", val, id]
|
||||||
push!(resList, line)
|
push!(resList, line)
|
||||||
end
|
end
|
||||||
|
|
||||||
(c, "int") => push!(resList, [c])
|
(c, "int") => begin
|
||||||
|
c_modified = "\$" * c
|
||||||
|
push!(resList, [c_modified])
|
||||||
|
end
|
||||||
|
|
||||||
(v, "id") => push!(resList, [v])
|
(v, "id") => push!(resList, [v])
|
||||||
_ => println("Error")
|
_ => println("Error")
|
||||||
|
@ -189,16 +223,134 @@ end
|
||||||
|
|
||||||
emptyEnv = []
|
emptyEnv = []
|
||||||
res = uniquifyVar(parsed, emptyEnv)
|
res = uniquifyVar(parsed, emptyEnv)
|
||||||
println("PASS1", res)
|
#println("PASS1", res)
|
||||||
res2 = explicitControlRemoveComplex(res)
|
res2 = explicitControlRemoveComplex(res)
|
||||||
|
|
||||||
println("PASS2", Parser.prettyStringLisp(res2))
|
#println("PASS2", Parser.prettyStringLisp(res2))
|
||||||
res3 = assignInstruction(res2)
|
res3 = assignInstruction(res2)
|
||||||
println("PASS3", res3)
|
#println("PASS3", res3)
|
||||||
|
|
||||||
|
|
||||||
|
# PASS4 assign home
|
||||||
|
function assignHomes(inp)
|
||||||
|
varRegex = r"(^[^\$%].*)"
|
||||||
|
res = []
|
||||||
|
vars = []
|
||||||
|
for i in inp
|
||||||
|
orig = i[2]
|
||||||
|
dest = i[3]
|
||||||
|
if match(varRegex, orig) != nothing # i.e. orig is a var and not a reg.
|
||||||
|
if !(orig in vars)
|
||||||
|
push!(vars, orig)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if match(varRegex, dest) != nothing # i.e. dest is a var and not a reg.
|
||||||
|
if !(dest in vars)
|
||||||
|
push!(vars, dest)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
#println("ALL_VAR", vars)
|
||||||
|
|
||||||
|
|
||||||
|
varsLength = length(vars)
|
||||||
|
for i in inp
|
||||||
|
instr = i[1]
|
||||||
|
orig = i[2]
|
||||||
|
dest = i[3]
|
||||||
|
|
||||||
|
origIdx = findfirst(x -> x == orig,vars)
|
||||||
|
if origIdx != nothing
|
||||||
|
realAddressIdx = varsLength - origIdx + 1
|
||||||
|
realAddress = "-$(realAddressIdx * 8)(%rbp)"
|
||||||
|
orig = realAddress
|
||||||
|
end
|
||||||
|
|
||||||
|
destIdx = findfirst(x -> x == dest,vars)
|
||||||
|
if destIdx != nothing
|
||||||
|
realAddressIdx = varsLength - destIdx + 1
|
||||||
|
realAddress = "-$(realAddressIdx * 8)(%rbp)"
|
||||||
|
dest = realAddress
|
||||||
|
end
|
||||||
|
|
||||||
|
push!(res, [instr, orig, dest])
|
||||||
|
end
|
||||||
|
return (res, varsLength)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# PASS5 patch instruction (ensure "instr x(rbp) y(rbp)" not happened)
|
||||||
|
function patchInstruction(inp)
|
||||||
|
memoryRegex = r".+[(]%rbp[)]$"
|
||||||
|
res = []
|
||||||
|
|
||||||
|
for i in inp
|
||||||
|
inst = i[1]
|
||||||
|
orig = i[2]
|
||||||
|
dest = i[3]
|
||||||
|
if (match(memoryRegex, orig) != nothing) & (match(memoryRegex, dest) != nothing)
|
||||||
|
cmd1 = ["movq", orig, "%rax"]
|
||||||
|
push!(res, cmd1)
|
||||||
|
|
||||||
|
cmd2 = [inst, "%rax", dest]
|
||||||
|
push!(res, cmd2)
|
||||||
|
elseif (inst == "imulq") & (match(r"^%.+", dest) == nothing)
|
||||||
|
cmd1 = ["movq", dest, "%rax"]
|
||||||
|
cmd2 = ["imulq", orig, "%rax"]
|
||||||
|
cmd3 = ["movq", "%rax", dest]
|
||||||
|
push!(res, cmd1)
|
||||||
|
push!(res, cmd2)
|
||||||
|
push!(res, cmd3)
|
||||||
|
|
||||||
|
else
|
||||||
|
push!(res, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
res4 = assignHomes(res3)
|
||||||
|
res4_prog = res4[1]
|
||||||
|
varNumber = res4[2]
|
||||||
|
res5 = patchInstruction(res4_prog)
|
||||||
|
#println("PASS5",res5)
|
||||||
|
|
||||||
|
|
||||||
|
## PASS6 add prelude and conclude
|
||||||
|
function preludeConclude(prog, varNumber)
|
||||||
|
rspSubqMax = varNumber * 8
|
||||||
|
|
||||||
|
body = "start:\n"
|
||||||
|
|
||||||
|
for i in prog
|
||||||
|
ln_cmd = ""
|
||||||
|
if length(i) == 3
|
||||||
|
ln_cmd = "\t$(i[1])\t$(i[2]), $(i[3])\n"
|
||||||
|
body = body * ln_cmd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
body *= "\tjmp\tconclusion\n\n\n"
|
||||||
|
|
||||||
|
prelude = """
|
||||||
|
.globl main
|
||||||
|
main:
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp, %rbp\n""" * "\tsubq \$$rspSubqMax, %rsp\n\tjmp start\n\n"
|
||||||
|
|
||||||
|
conclude = """\nconclusion:\n""" * "\taddq \$$rspSubqMax, %rsp\n\tpopq %rbp\n\tretq"
|
||||||
|
|
||||||
|
assemblyProg = prelude * body * conclude
|
||||||
|
return assemblyProg
|
||||||
|
end
|
||||||
|
|
||||||
|
res6 = preludeConclude(res5, varNumber)
|
||||||
|
# println("PASS6",res6) # emit assembly code
|
||||||
|
f2 = open("./a.s", "w")
|
||||||
|
write(f2, res6) #write the assembly code
|
||||||
|
|
||||||
|
|
||||||
close(f)
|
close(f)
|
||||||
|
close(f2)
|
||||||
|
|
||||||
|
|
||||||
end # module
|
end # module
|
||||||
|
|
|
@ -436,12 +436,10 @@ function totalParse(prog)
|
||||||
matchedList = map((x)->x.match, collect(mI))
|
matchedList = map((x)->x.match, collect(mI))
|
||||||
groupNameList = map(processKeys, collect(mI))
|
groupNameList = map(processKeys, collect(mI))
|
||||||
zippedTokenList = collect(zip(matchedList, groupNameList))
|
zippedTokenList = collect(zip(matchedList, groupNameList))
|
||||||
print(zippedTokenList)
|
|
||||||
|
|
||||||
withoutSpaces = filter((x)-> x[2] != "sp", zippedTokenList)
|
withoutSpaces = filter((x)-> x[2] != "sp", zippedTokenList)
|
||||||
initWrapped = ParserResult([], withoutSpaces)
|
initWrapped = ParserResult([], withoutSpaces)
|
||||||
res = initWrapped >> body
|
res = initWrapped >> body
|
||||||
println(prettyStringLisp(res))
|
|
||||||
return res.matched
|
return res.matched
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
int a = 12;
|
int a = 10;
|
||||||
|
int a = 13;
|
||||||
int b = (12 + (0 - a));
|
int b = (12 + (0 - a));
|
||||||
int a = (15 + b);
|
int c = (14 + b);
|
||||||
int d = 20;
|
int d = 20;
|
||||||
a + d((0 - a), b)
|
a * 2 + ((b - c) - d)
|
Loading…
Reference in a new issue