Skip to content

Commit c642003

Browse files
authored
Merge pull request #416 from Scott-Young-6746/pr_branch
Added support for >>> operator and simple for loops
2 parents e783661 + 17f7a91 commit c642003

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+272272
-9
lines changed

ODIN_II/SRC/ast_elaborate.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
2929
#include "types.h"
3030
#include "ast_util.h"
3131
#include "ast_elaborate.h"
32+
#include "ast_loop_unroll.h"
3233
#include "parse_making_ast.h"
3334
#include "verilog_bison.h"
3435
#include "netlist_create_from_ast.h"
@@ -59,7 +60,7 @@ enode *head, *p;
5960
int simplify_ast()
6061
{
6162
/* for loop support */
62-
optimize_for_tree();
63+
unroll_loops();
6364
/* reduce parameters with their values if they have been set */
6465
reduce_parameter();
6566
/* simplify assignment expressions */

ODIN_II/SRC/ast_loop_unroll.cpp

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/* Standard libraries */
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
/* Odin_II libraries */
6+
#include "globals.h"
7+
#include "types.h"
8+
#include "ast_util.h"
9+
#include "parse_making_ast.h"
10+
#include "odin_util.h"
11+
12+
/* This files header */
13+
#include "ast_loop_unroll.h"
14+
15+
/*
16+
* (function: unroll_loops)
17+
*/
18+
void unroll_loops()
19+
{
20+
/* preprocess each module */
21+
size_t i;
22+
for (i = 0; i < num_modules; i++)
23+
{
24+
ast_node_t* module = for_preprocessor(ast_modules[i]);
25+
if(module != ast_modules[i])
26+
free_whole_tree(ast_modules[i]);
27+
ast_modules[i] = module;
28+
}
29+
}
30+
31+
/*
32+
* (function: for_preprocessor)
33+
*/
34+
ast_node_t* for_preprocessor(ast_node_t* node)
35+
{
36+
if(!node)
37+
return nullptr;
38+
/* If this is a for node, something has gone wrong */
39+
oassert(!is_for_node(node))
40+
41+
/* If this node has for loops as children, replace them */
42+
bool for_loops = false;
43+
for(int i=0; i<node->num_children && !for_loops; i++){
44+
for_loops = is_for_node(node->children[i]);
45+
}
46+
ast_node_t* new_node = for_loops ? replace_fors(node) : node;
47+
48+
/* Run this function recursively on the children */
49+
for(int i=0; i<new_node->num_children; i++){
50+
ast_node_t* new_child = for_preprocessor(new_node->children[i]);
51+
52+
/* Cleanup replaced child */
53+
if(new_node->children[i] != new_child){
54+
free_whole_tree(new_node->children[i]);
55+
new_node->children[i] = new_child;
56+
}
57+
}
58+
return new_node;
59+
}
60+
61+
/*
62+
* (function: replace_fors)
63+
*/
64+
ast_node_t* replace_fors(ast_node_t* node)
65+
{
66+
oassert(!is_for_node(node));
67+
oassert(node != nullptr);
68+
69+
ast_node_t* new_node = ast_node_deep_copy(node);
70+
if(!new_node)
71+
return nullptr;
72+
73+
/* process children one at a time */
74+
for(int i=0; i<new_node->num_children; i++){
75+
/* unroll `for` children */
76+
if(is_for_node(new_node->children[i])){
77+
ast_node_t* unrolled_for = resolve_for(new_node->children[i]);
78+
oassert(unrolled_for != nullptr);
79+
free_whole_tree(new_node->children[i]);
80+
new_node->children[i] = unrolled_for;
81+
}
82+
}
83+
return new_node;
84+
}
85+
86+
/*
87+
* (function: resolve_for)
88+
*/
89+
ast_node_t* resolve_for(ast_node_t* node)
90+
{
91+
oassert(is_for_node(node));
92+
oassert(node != nullptr);
93+
ast_node_t* body_parent = nullptr;
94+
95+
ast_node_t* pre = node->children[0];
96+
ast_node_t* cond = node->children[1];
97+
ast_node_t* post = node->children[2];
98+
ast_node_t* body = node->children[3];
99+
100+
ast_node_t* value = 0;
101+
if(resolve_pre_condition(pre, &value))
102+
{
103+
error_message(PARSE_ERROR, pre->line_number, pre->file_number, "Unsupported pre-condition node in for loop");
104+
}
105+
106+
int error_code = 0;
107+
condition_function cond_func = resolve_condition(cond, pre->children[0], &error_code);
108+
if(error_code)
109+
{
110+
error_message(PARSE_ERROR, cond->line_number, cond->file_number, "Unsupported condition node in for loop");
111+
}
112+
113+
post_condition_function post_func = resolve_post_condition(post, pre->children[0], &error_code);
114+
if(error_code)
115+
{
116+
error_message(PARSE_ERROR, post->line_number, post->file_number, "Unsupported post-condition node in for loop");
117+
}
118+
119+
while(cond_func(value->types.number.value))
120+
{
121+
ast_node_t* new_body = dup_and_fill_body(body, pre->children[0], &value, &error_code);
122+
if(error_code)
123+
{
124+
error_message(PARSE_ERROR, pre->line_number, pre->file_number, "Unsupported pre-condition node in for loop");
125+
}
126+
value->types.number.value = post_func(value->types.number.value);
127+
body_parent = body_parent ? newList_entry(body_parent, new_body) : newList(BLOCK, new_body);
128+
}
129+
130+
return body_parent;
131+
}
132+
133+
/*
134+
* (function: resolve_pre_condition)
135+
* return 0 if the first value of the variable set
136+
* in the pre condition of a `for` node has been put in location
137+
* pointed to by the number pointer.
138+
*
139+
* return a non-zero number on failure.
140+
* define failure constants in header.
141+
*/
142+
int resolve_pre_condition(ast_node_t* node, ast_node_t** number_node)
143+
{
144+
/* Add new for loop support here. Keep current work in the TODO
145+
* Currently supporting:
146+
* TODO:
147+
* for(VAR = NUM; VAR {<, >, ==, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
148+
*/
149+
if( node == nullptr ||
150+
node->type != BLOCKING_STATEMENT ||
151+
node->num_children != 2 ||
152+
node->children[1] == nullptr ||
153+
node->children[1]->type != NUMBERS)
154+
{
155+
return UNSUPPORTED_PRE_CONDITION_NODE;
156+
}
157+
*number_node = ast_node_deep_copy(node->children[1]);
158+
return 0;
159+
}
160+
161+
/*
162+
* (function: resolve_condition)
163+
* return a lambda which tests the loop condition for a given value
164+
*/
165+
condition_function resolve_condition(ast_node_t* node, ast_node_t* symbol, int* error_code)
166+
{
167+
/* Add new for loop support here. Keep current work in the TODO
168+
* Currently supporting:
169+
* TODO:
170+
* for(VAR = NUM; VAR {<, >, ==, !=, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
171+
*/
172+
if( node->type != BINARY_OPERATION ||
173+
!( node->types.operation.op == LT ||
174+
node->types.operation.op == GT ||
175+
node->types.operation.op == LOGICAL_EQUAL ||
176+
node->types.operation.op == NOT_EQUAL ||
177+
node->types.operation.op == LTE ||
178+
node->types.operation.op == GTE ) ||
179+
node->num_children != 2 ||
180+
node->children[1] == nullptr ||
181+
node->children[1]->type != NUMBERS ||
182+
node->children[0] == nullptr ||
183+
node->children[0]->type != IDENTIFIERS ||
184+
strcmp(node->children[0]->types.identifier, symbol->types.identifier))
185+
{
186+
*error_code = UNSUPPORTED_CONDITION_NODE;
187+
return nullptr;
188+
}
189+
*error_code = 0;
190+
return [=](long long value) {
191+
switch(node->types.operation.op){
192+
case LT:
193+
return value < node->children[1]->types.number.value;
194+
case GT:
195+
return value > node->children[1]->types.number.value;
196+
case NOT_EQUAL:
197+
return value != node->children[1]->types.number.value;
198+
case LOGICAL_EQUAL:
199+
return value == node->children[1]->types.number.value;
200+
case LTE:
201+
return value <= node->children[1]->types.number.value;
202+
case GTE:
203+
return value >= node->children[1]->types.number.value;
204+
default:
205+
return false;
206+
}
207+
};
208+
}
209+
210+
/*
211+
* (function: resolve_post_condition)
212+
* return a lambda which gives the next value
213+
* of the loop variable given the current value
214+
* of the loop variable
215+
*/
216+
post_condition_function resolve_post_condition(ast_node_t* assignment, ast_node_t* symbol, int* error_code)
217+
{
218+
/* Add new for loop support here. Keep current work in the TODO
219+
* Currently supporting:
220+
* TODO:
221+
* for(VAR = NUM; VAR {<, >, ==, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
222+
*/
223+
ast_node_t* node = nullptr;
224+
if( assignment != nullptr &&
225+
assignment->type == BLOCKING_STATEMENT &&
226+
assignment->num_children == 2 &&
227+
assignment->children[0] != nullptr &&
228+
assignment->children[1] != nullptr)
229+
{
230+
node = assignment->children[1];
231+
}
232+
if( node == nullptr ||
233+
node->type != BINARY_OPERATION ||
234+
!( node->types.operation.op == ADD ||
235+
node->types.operation.op == MINUS ||
236+
node->types.operation.op == MULTIPLY ||
237+
node->types.operation.op == DIVIDE) ||
238+
node->num_children != 2 ||
239+
node->children[1] == nullptr ||
240+
node->children[1]->type != NUMBERS ||
241+
node->children[0] == nullptr ||
242+
node->children[0]->type != IDENTIFIERS ||
243+
strcmp(node->children[0]->types.identifier, symbol->types.identifier))
244+
{
245+
*error_code = UNSUPPORTED_POST_CONDITION_NODE;
246+
return nullptr;
247+
}
248+
*error_code = 0;
249+
return [=](long long value) {
250+
switch(node->types.operation.op){
251+
case ADD:
252+
return value + node->children[1]->types.number.value;
253+
case MINUS:
254+
return value - node->children[1]->types.number.value;
255+
case MULTIPLY:
256+
return value * node->children[1]->types.number.value;
257+
case DIVIDE:
258+
return value / node->children[1]->types.number.value;
259+
default:
260+
return 0ll;
261+
}
262+
};
263+
}
264+
265+
ast_node_t* dup_and_fill_body(ast_node_t* body, ast_node_t* symbol, ast_node_t** value, int* error_code)
266+
{
267+
ast_node_t* copy = ast_node_deep_copy(body);
268+
for(int i = 0; i<copy->num_children; i++){
269+
ast_node_t* child = copy->children[i];
270+
oassert(child);
271+
if(child->type == IDENTIFIERS){
272+
if(!strcmp(child->types.identifier, symbol->types.identifier)){
273+
ast_node_t* new_num = ast_node_deep_copy(*value);
274+
free_whole_tree(child);
275+
copy->children[i] = new_num;
276+
}
277+
} else if(child->num_children > 0){
278+
copy->children[i] = dup_and_fill_body(child, symbol, value, error_code);
279+
oassert(copy->children[i]);
280+
free_whole_tree(child);
281+
}
282+
}
283+
return copy;
284+
}

ODIN_II/SRC/ast_util.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,9 +1026,12 @@ ast_node_t *ast_node_deep_copy(ast_node_t *node){
10261026
node_copy->types.number.number = vtr::strdup(node->types.number.number);
10271027
node_copy->types.number.binary_string = vtr::strdup(node->types.number.binary_string);
10281028

1029+
//Create a new child list
1030+
node_copy->children = (ast_node_t**)vtr::malloc(sizeof(ast_node_t*)*node_copy->num_children);
1031+
10291032
//Recursively copy its children
10301033
for(i = 0; i < node->num_children; i++){
1031-
node_copy->children[i] = ast_node_deep_copy(node_copy->children[i]);
1034+
node_copy->children[i] = ast_node_deep_copy(node->children[i]);
10321035
}
10331036

10341037
return node_copy;
@@ -1134,6 +1137,7 @@ ast_node_t * fold_binary(ast_node_t *child_0 ,ast_node_t *child_1, operation_lis
11341137
long long operand_0 = child_0->types.number.value;
11351138
long long operand_1 = child_1->types.number.value;
11361139
long long result = 0;
1140+
long long mask = 0ll;
11371141
short success = FALSE;
11381142

11391143
int length =0;
@@ -1205,6 +1209,18 @@ ast_node_t * fold_binary(ast_node_t *child_0 ,ast_node_t *child_1, operation_lis
12051209
success = TRUE;
12061210
break;
12071211

1212+
case ASR:
1213+
result = operand_0 >> operand_1;
1214+
if(operand_0 < 0)
1215+
{
1216+
for(long long shift = 0; shift<operand_1; shift++){
1217+
mask |= 1 << ((sizeof(long long)*8) - (shift+1));
1218+
}
1219+
}
1220+
result |= mask;
1221+
success = TRUE;
1222+
break;
1223+
12081224
case LOGICAL_AND:
12091225
result = operand_0 && operand_1;
12101226
success = TRUE;

ODIN_II/SRC/include/ast_loop_unroll.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef LOOP_UNROLL_AST_H
2+
#define LOOP_UNROLL_AST_H
3+
4+
#include "globals.h"
5+
#include "types.h"
6+
#include <stdlib.h>
7+
#include <functional>
8+
9+
/* resolve_pre_condition error codes */
10+
#define UNSUPPORTED_PRE_CONDITION_NODE 1
11+
#define UNSUPPORTED_CONDITION_NODE 2
12+
#define UNSUPPORTED_POST_CONDITION_NODE 3
13+
14+
/* Function Pointer Types */
15+
typedef std::function<bool(long long)> condition_function;
16+
typedef std::function<long long(long long)> post_condition_function;
17+
18+
void unroll_loops();
19+
20+
inline bool is_for_node(ast_node_t* node)
21+
{
22+
return node && node->type == FOR;
23+
}
24+
25+
ast_node_t* for_preprocessor(ast_node_t* node);
26+
ast_node_t* replace_fors(ast_node_t* node);
27+
ast_node_t* resolve_for(ast_node_t* node);
28+
int resolve_pre_condition(ast_node_t* node, ast_node_t** number);
29+
condition_function resolve_condition(ast_node_t* node, ast_node_t* symbol, int* error_code);
30+
post_condition_function resolve_post_condition(ast_node_t* assignment, ast_node_t* symbol, int* error_code);
31+
ast_node_t* dup_and_fill_body(ast_node_t* body, ast_node_t* symbol, ast_node_t** value, int* error_code);
32+
33+
#endif

ODIN_II/SRC/include/netlist_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ void join_nets(nnet_t *net, nnet_t* input_net);
3737

3838
void remap_pin_to_new_net(npin_t *pin, nnet_t *new_net);
3939
void remap_pin_to_new_node(npin_t *pin, nnode_t *new_node, int pin_idx);
40+
void remap_pin_to_new_node_range(npin_t *pin, nnode_t *new_node, int pin_range_start, int pin_range_end);
41+
4042

4143
signal_list_t *init_signal_list();
4244
void add_pin_to_signal_list(signal_list_t *list, npin_t* pin);

ODIN_II/SRC/include/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ typedef enum
275275
LTE, // <=
276276
GTE, // >=
277277
SR, // >>
278+
ASR, // >>>
278279
SL, // <<
279280
CASE_EQUAL, // ===
280281
CASE_NOT_EQUAL, // !==

0 commit comments

Comments
 (0)