forked from djsutton/Compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instruction_selection1.py
89 lines (71 loc) · 2.82 KB
/
instruction_selection1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
###############################################################################
# Instruction Selection
# This is a very naive version (easy to implement)
# Input: an AST for P_1
# Output: an AST for IR_x86
from ir_x86 import *
from vis import Visitor
def make_arith(klass, lhs, rhs):
if isinstance(lhs, Name) and isinstance(rhs, Name):
return [IntMoveInstr(Register('eax'), [rhs]),
klass(lhs, [Register('eax')])]
else:
return [klass(lhs, [rhs])]
def name_or_reg(n):
return isinstance(n, Name) or isinstance(n, Register)
class InstrSelVisitor(Visitor):
def __init__(self):
Visitor.__init__(self)
def visitModule(self, n):
ss = self.dispatch(n.node)
return Module(n.doc, ss)
def visitStmt(self, n):
sss = [self.dispatch(s) for s in n.nodes]
return Stmt(reduce(lambda a,b: a + b, sss, []))
def visitAdd(self, n, lhs):
left = n.left
right = n.right
if name_or_reg(left) and left.name == lhs:
return make_arith(IntAddInstr, Name(lhs), right)
elif name_or_reg(right) and right.name == lhs:
return make_arith(IntAddInstr, Name(lhs), left)
else:
return [IntMoveInstr(Register('eax'), [left]),
IntAddInstr(Register('eax'), [right]),
IntMoveInstr(Name(lhs), [Register('eax')])]
def visitUnarySub(self, n, lhs):
return [IntMoveInstr(Register('eax'), [n.expr]),
IntNegInstr(Register('eax'), []),
IntMoveInstr(Name(lhs), [Register('eax')])]
def visitName(self, n, lhs):
if lhs == n.name:
return []
else:
return make_arith(IntMoveInstr, Name(lhs), n)
def visitConst(self, n, lhs):
return [IntMoveInstr(Name(lhs), [n])]
def visitCallFunc(self, n, lhs):
push_args = [Push(a) for a in reversed(n.args)]
# Align stack to 16-bytes for MacOS X
align = 4 * (4 - len(n.args) % 4)
pop_amount = (4 * len(n.args)) + align
if align != 0:
push_args = [IntSubInstr(Register('esp'), [Const(align)])] + push_args
if 0 < pop_amount:
pop = [Pop(pop_amount)]
else:
pop = []
return push_args + [CallX86(n.node.name)] + pop \
+ [IntMoveInstr(Name(lhs), [Register('eax')])]
def visitAssign(self, n):
lhs = n.nodes[0].name
return self.dispatch(n.expr, lhs)
def visitPrintnl(self, n):
push_args = [Push(n.nodes[0])]
# Align stack to 16-bytes for MacOS X
if len(push_args) % 4 != 0:
n = 4 - (len(push_args) % 4)
for i in range(0,n):
push_args = [Push(Const(0))] + push_args
pop = [Pop(4 * len(push_args))]
return push_args + [CallX86('print_int_nl')] + pop