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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
import "ir.hff";
import "common.hff";
extern fn ir_genstatic(IR *IRCtx, decl *Decl) void {
}
struct InstStream {
IR *IRCtx,
head *IRInst,
tail *IRInst,
fn push(S *InstStream, inst *IRInst) void {
if S.tail {
S.tail.next = inst;
} else {
S.head = inst;
}
S.tail = inst;
}
}
fn mkinstr(S *InstStream, t IRInstT, args [#]IRArg) *IRInst {
let inst *IRInst = S.IR.alloc->alloc(sizeof IRInst + (args.#len * sizeof IRArg), alignof IRInst);
*inst = { .t: t };
for let i = 0; i < args.#len; ++i {
inst.args[i] = args[i];
}
return inst;
}
defmacro mkslice(Ty, ...args) [ (as([]Ty){args})[0::] ]
fn genblock(S *InstStream, block [#]Stmt) void;
fn genexpr(S *InstStream, ex *Expr) IRValue {
static tmpid int = 0;
// fold(ex);
defmacro genunop(u,t) [ {
let child = genexpr(S, (u).ex);
let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(child))));
return res;
} ]
defmacro genbinop(b,t) [ {
let lhs = genexpr(S, (b).lhs);
let rhs = genexpr(S, (b).rhs);
let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
S->push(mkinstr(S, (t), mkslice(IRArg, :Val(res), :Val(lhs), :Val(rhs))));
return res;
} ]
switch ex.u {
case IntLit i; return {ex.ty, :IImm(i.i)};
case FloLit f; return {ex.ty, :FImm(f)};
case StrLit s; return {ex.ty, :SImm(s)};
case BoolLit b; return {ex.ty, :BImm(b)};
case NullLit; return {ex.ty, :Null};
case UnOp u;
switch u.op {
case :neg; genunop(u, ex.ty->is(:Int) ? :neg : :fneg);
case :compl; genunop(u, :compl);
}
case BinOp b;
switch b.op {
case '+'; genbinop(b, ex.ty->is(:Int) ? :add : :fadd);
case '-'; genbinop(b, ex.ty->is(:Int) ? :sub : :fsub);
case '*'; genbinop(b, ex.ty->is(:Int) ? :mul : :fmul);
case '/'; genbinop(b, ex.ty->is(:Int) ? :div : :fdiv);
case '%'; genbinop(b, :mod);
case '&'; genbinop(b, :band);
case '|'; genbinop(b, :bor);
case '^'; genbinop(b, :xor);
case '<<'; genbinop(b, :lsl);
case '>>'; genbinop(b, ex.ty.u.Int.sgn ? :asr : :lsr);
}
case Call c;
let n = c.args.#len;
let args [#]IRArg = (as(*IRArg)malloc((n + 2) * sizeof IRArg))[0::n + 2];
defer free(args.#ptr);
let res = IRValue{ex.ty, .u: :Tmp(tmpid++)};
args[0] = :Val(res);
if c.lhs.u.#tag == :Symbol {
args[1] = :Fn(c.lhs.u.Symbol);
for let i = 0; i < n; ++i {
args[i + 2] = :Val(genexpr(S, &c.args[i]));
}
let inst = mkinstr(S, :call, args);
inst.call_nargs = n;
S->push(inst);
return res;
} else {
}
}
assert(#f, "NYI ex");
}
fn genstmt(S *InstStream, stmt *Stmt) void {
switch stmt.u {
case Expr *ex;
genexpr(S, ex);
case else
assert(#f, "NYI st");
}
}
fn genblock(S *InstStream, block [#]Stmt) void {
foreach_ptr(st, _, block) {
genstmt(S, st);
}
}
extern fn ir_genfn(IR *IRCtx, f *Fn) void {
let stream InstStream = {.IR: IR};
genblock(&stream, f.body.Some);
stream->push(mkinstr(&stream, :ret0, {}));
efmt("----------------------\n");
efmt("function %s.%d:\n", container_of(f, Decl, u.Fn).name, f.id);
irdump(stream.head);
}
|