-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnotes.h
182 lines (148 loc) · 4.34 KB
/
notes.h
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//~ this design would allow for easier multithreaded IR generation
// since the IRGenerators have no dependency on the vm or each other
/*
IRGenerator gen;
...
IRModule m1 = gen.create_module();
gen.clear();
...
IRModule m2 = gen.create_module();
Arcvm vm;
vm.load_module(m1);
vm.load_module(m2);
// interpret
i32 ec = vm.run();
// create a binary file
vm.compile();
// jit compile and run
vm.jit();
*/
//~ currently there is no way to refer to basic blocks
// this is an issue because it makes generating control flow structures impossible
// for example statements like if-elseif-else-then, for, while, etc.
//
// maybe only let labels/basicblocks be created at function level
// then whatever code is calling a gen_inst will have to create explicity create a basic block
// this will then give them a way to reference the block
// problem solved
// then higher-level contructs can take basicblock pointers as arugments
// as long as the basicblocks are local to the current block there should be no issues
//
// this will also make phi nodes possible to implement
//
// something to think about:
// phi nodes can somewhat be "replaced" by pointers in some cases
// what do I want to do about this????
// obviously there will be a canonicalization pass
// however do I want to generate this instead of phi nodes by default?
// it could potentially make IR gen easier for the front end
// hmmm, actually a language without pointers may have a harder time trying to do this
// let's start with having users generate phi nodes
// it will allow for easier optimization in the backend and it's less to think about for the frontend
/*
// new function gen api
// this should handle label creation
create_basicblock()
// allow pushing/popping/reordering elements in the list???
get_basic_block_list()
// I don't see much of a reason to provide a public gen api for blocks
// at the moment it is purely used as a function body, so
// the function api can handle it
// new basic block api
basicblock->gen_inst(...);
// basicblock->gen_if(if, else, then);
basicblock->gen_if(BasicBlock, BasicBlock, BasicBlock);
// basicblock->gen_loop(header, body, then);
basicblock->gen_loop(BasicBlock, BasicBlock, BasicBlock);
*/
//~ an aritfact from the old design is the gen_function_def() function
// at this point it should just take a Block as a parameter
// at the moment it just handles the header stuff and let's
// the user generate the code directly
//~ Block::gen_if
/*
IRValue cond, BasicBlock* if_block, BasicBlock* else_block, BasicBlock* then_block
cond: codegen is inserted into the preceding BasicBlock
if_block: is jumped to when the cond is non-zero
else_block: is jumped to when cond is zero
then_block: is jumped to after if_block or else_block is executed
fn(...)
#fn
...
#bb1
...
+---+--brz cond, #if_block1, #else_block
| +->#if_block
| ...
| +---br #then_block1
+--+-->#else_block1
| ...
| +-br #then_block1
+-+>#then_block1
...
*/
//~
/*
need some way to change the "insertion point"
at the moment the way to generate an if expression would
be to make a bunch of free basic blocks then use gen_if to tie them together
this design is not good
instead providing an easy way to insert basic blocks in the middle of blocks would be better
*/
//~ optmization pipeline
/*
define function fact(i32 %0) -> i32 {
#fact
brnz %0, #0, #1
#0
%1 = alloc i32
store %1, 1
%2 = load %1
%3 = sub %0, %2
%4 = call @fact, %3, i32
%5 = mul %0, 4
ret %5
br #2
#1
br #2
#2
%6 = alloc i32
store %6, 1
%7 = load %6
ret %7
}
[entrypoint]
define function main() -> i32 {
#main
%0 = alloc i32
store %0, 5
%1 = load %0
%2 = call @fact, %1, i32
ret 2
}
The above IR generated by the front-end can be trivially transformed to the IR below
potential transformation pass names...
* merge basic blocks
* remove redundant control flow
// the below two might inhibit other optimizations or could be redundant once GVN is added etc.
// assure this isn't the case before implementing
* stack promotion
* immediate canonicalization
define function fact(i32 %0) -> i32 {
#fact
brnz %0, #0, #1
#0
%1 = sub %0, 1
%2 = call @fact, %1, i32
%3 = mul %0, %2
ret %3
#1
ret 1
}
[entrypoint]
define function main() -> i32 {
#main
%1 = call @fact, 5, i32
ret %1
}
*/