Skip to content

Added support for >>> operator and simple for loops #416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ODIN_II/SRC/ast_elaborate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include "types.h"
#include "ast_util.h"
#include "ast_elaborate.h"
#include "ast_loop_unroll.h"
#include "parse_making_ast.h"
#include "verilog_bison.h"
#include "netlist_create_from_ast.h"
Expand Down Expand Up @@ -59,7 +60,7 @@ enode *head, *p;
int simplify_ast()
{
/* for loop support */
optimize_for_tree();
unroll_loops();
/* reduce parameters with their values if they have been set */
reduce_parameter();
/* simplify assignment expressions */
Expand Down
284 changes: 284 additions & 0 deletions ODIN_II/SRC/ast_loop_unroll.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/* Standard libraries */
#include <stdlib.h>
#include <string.h>

/* Odin_II libraries */
#include "globals.h"
#include "types.h"
#include "ast_util.h"
#include "parse_making_ast.h"
#include "odin_util.h"

/* This files header */
#include "ast_loop_unroll.h"

/*
* (function: unroll_loops)
*/
void unroll_loops()
{
/* preprocess each module */
size_t i;
for (i = 0; i < num_modules; i++)
{
ast_node_t* module = for_preprocessor(ast_modules[i]);
if(module != ast_modules[i])
free_whole_tree(ast_modules[i]);
ast_modules[i] = module;
}
}

/*
* (function: for_preprocessor)
*/
ast_node_t* for_preprocessor(ast_node_t* node)
{
if(!node)
return nullptr;
/* If this is a for node, something has gone wrong */
oassert(!is_for_node(node))

/* If this node has for loops as children, replace them */
bool for_loops = false;
for(int i=0; i<node->num_children && !for_loops; i++){
for_loops = is_for_node(node->children[i]);
}
ast_node_t* new_node = for_loops ? replace_fors(node) : node;

/* Run this function recursively on the children */
for(int i=0; i<new_node->num_children; i++){
ast_node_t* new_child = for_preprocessor(new_node->children[i]);

/* Cleanup replaced child */
if(new_node->children[i] != new_child){
free_whole_tree(new_node->children[i]);
new_node->children[i] = new_child;
}
}
return new_node;
}

/*
* (function: replace_fors)
*/
ast_node_t* replace_fors(ast_node_t* node)
{
oassert(!is_for_node(node));
oassert(node != nullptr);

ast_node_t* new_node = ast_node_deep_copy(node);
if(!new_node)
return nullptr;

/* process children one at a time */
for(int i=0; i<new_node->num_children; i++){
/* unroll `for` children */
if(is_for_node(new_node->children[i])){
ast_node_t* unrolled_for = resolve_for(new_node->children[i]);
oassert(unrolled_for != nullptr);
free_whole_tree(new_node->children[i]);
new_node->children[i] = unrolled_for;
}
}
return new_node;
}

/*
* (function: resolve_for)
*/
ast_node_t* resolve_for(ast_node_t* node)
{
oassert(is_for_node(node));
oassert(node != nullptr);
ast_node_t* body_parent = nullptr;

ast_node_t* pre = node->children[0];
ast_node_t* cond = node->children[1];
ast_node_t* post = node->children[2];
ast_node_t* body = node->children[3];

ast_node_t* value = 0;
if(resolve_pre_condition(pre, &value))
{
error_message(PARSE_ERROR, pre->line_number, pre->file_number, "Unsupported pre-condition node in for loop");
}

int error_code = 0;
condition_function cond_func = resolve_condition(cond, pre->children[0], &error_code);
if(error_code)
{
error_message(PARSE_ERROR, cond->line_number, cond->file_number, "Unsupported condition node in for loop");
}

post_condition_function post_func = resolve_post_condition(post, pre->children[0], &error_code);
if(error_code)
{
error_message(PARSE_ERROR, post->line_number, post->file_number, "Unsupported post-condition node in for loop");
}

while(cond_func(value->types.number.value))
{
ast_node_t* new_body = dup_and_fill_body(body, pre->children[0], &value, &error_code);
if(error_code)
{
error_message(PARSE_ERROR, pre->line_number, pre->file_number, "Unsupported pre-condition node in for loop");
}
value->types.number.value = post_func(value->types.number.value);
body_parent = body_parent ? newList_entry(body_parent, new_body) : newList(BLOCK, new_body);
}

return body_parent;
}

/*
* (function: resolve_pre_condition)
* return 0 if the first value of the variable set
* in the pre condition of a `for` node has been put in location
* pointed to by the number pointer.
*
* return a non-zero number on failure.
* define failure constants in header.
*/
int resolve_pre_condition(ast_node_t* node, ast_node_t** number_node)
{
/* Add new for loop support here. Keep current work in the TODO
* Currently supporting:
* TODO:
* for(VAR = NUM; VAR {<, >, ==, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
*/
if( node == nullptr ||
node->type != BLOCKING_STATEMENT ||
node->num_children != 2 ||
node->children[1] == nullptr ||
node->children[1]->type != NUMBERS)
{
return UNSUPPORTED_PRE_CONDITION_NODE;
}
*number_node = ast_node_deep_copy(node->children[1]);
return 0;
}

/*
* (function: resolve_condition)
* return a lambda which tests the loop condition for a given value
*/
condition_function resolve_condition(ast_node_t* node, ast_node_t* symbol, int* error_code)
{
/* Add new for loop support here. Keep current work in the TODO
* Currently supporting:
* TODO:
* for(VAR = NUM; VAR {<, >, ==, !=, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
*/
if( node->type != BINARY_OPERATION ||
!( node->types.operation.op == LT ||
node->types.operation.op == GT ||
node->types.operation.op == LOGICAL_EQUAL ||
node->types.operation.op == NOT_EQUAL ||
node->types.operation.op == LTE ||
node->types.operation.op == GTE ) ||
node->num_children != 2 ||
node->children[1] == nullptr ||
node->children[1]->type != NUMBERS ||
node->children[0] == nullptr ||
node->children[0]->type != IDENTIFIERS ||
strcmp(node->children[0]->types.identifier, symbol->types.identifier))
{
*error_code = UNSUPPORTED_CONDITION_NODE;
return nullptr;
}
*error_code = 0;
return [=](long long value) {
switch(node->types.operation.op){
case LT:
return value < node->children[1]->types.number.value;
case GT:
return value > node->children[1]->types.number.value;
case NOT_EQUAL:
return value != node->children[1]->types.number.value;
case LOGICAL_EQUAL:
return value == node->children[1]->types.number.value;
case LTE:
return value <= node->children[1]->types.number.value;
case GTE:
return value >= node->children[1]->types.number.value;
default:
return false;
}
};
}

/*
* (function: resolve_post_condition)
* return a lambda which gives the next value
* of the loop variable given the current value
* of the loop variable
*/
post_condition_function resolve_post_condition(ast_node_t* assignment, ast_node_t* symbol, int* error_code)
{
/* Add new for loop support here. Keep current work in the TODO
* Currently supporting:
* TODO:
* for(VAR = NUM; VAR {<, >, ==, <=, >=} NUM; VAR = VAR {+, -, *, /} NUM) STATEMENT
*/
ast_node_t* node = nullptr;
if( assignment != nullptr &&
assignment->type == BLOCKING_STATEMENT &&
assignment->num_children == 2 &&
assignment->children[0] != nullptr &&
assignment->children[1] != nullptr)
{
node = assignment->children[1];
}
if( node == nullptr ||
node->type != BINARY_OPERATION ||
!( node->types.operation.op == ADD ||
node->types.operation.op == MINUS ||
node->types.operation.op == MULTIPLY ||
node->types.operation.op == DIVIDE) ||
node->num_children != 2 ||
node->children[1] == nullptr ||
node->children[1]->type != NUMBERS ||
node->children[0] == nullptr ||
node->children[0]->type != IDENTIFIERS ||
strcmp(node->children[0]->types.identifier, symbol->types.identifier))
{
*error_code = UNSUPPORTED_POST_CONDITION_NODE;
return nullptr;
}
*error_code = 0;
return [=](long long value) {
switch(node->types.operation.op){
case ADD:
return value + node->children[1]->types.number.value;
case MINUS:
return value - node->children[1]->types.number.value;
case MULTIPLY:
return value * node->children[1]->types.number.value;
case DIVIDE:
return value / node->children[1]->types.number.value;
default:
return 0ll;
}
};
}

ast_node_t* dup_and_fill_body(ast_node_t* body, ast_node_t* symbol, ast_node_t** value, int* error_code)
{
ast_node_t* copy = ast_node_deep_copy(body);
for(int i = 0; i<copy->num_children; i++){
ast_node_t* child = copy->children[i];
oassert(child);
if(child->type == IDENTIFIERS){
if(!strcmp(child->types.identifier, symbol->types.identifier)){
ast_node_t* new_num = ast_node_deep_copy(*value);
free_whole_tree(child);
copy->children[i] = new_num;
}
} else if(child->num_children > 0){
copy->children[i] = dup_and_fill_body(child, symbol, value, error_code);
oassert(copy->children[i]);
free_whole_tree(child);
}
}
return copy;
}
18 changes: 17 additions & 1 deletion ODIN_II/SRC/ast_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,9 +1026,12 @@ ast_node_t *ast_node_deep_copy(ast_node_t *node){
node_copy->types.number.number = vtr::strdup(node->types.number.number);
node_copy->types.number.binary_string = vtr::strdup(node->types.number.binary_string);

//Create a new child list
node_copy->children = (ast_node_t**)vtr::malloc(sizeof(ast_node_t*)*node_copy->num_children);

//Recursively copy its children
for(i = 0; i < node->num_children; i++){
node_copy->children[i] = ast_node_deep_copy(node_copy->children[i]);
node_copy->children[i] = ast_node_deep_copy(node->children[i]);
}

return node_copy;
Expand Down Expand Up @@ -1134,6 +1137,7 @@ ast_node_t * fold_binary(ast_node_t *child_0 ,ast_node_t *child_1, operation_lis
long long operand_0 = child_0->types.number.value;
long long operand_1 = child_1->types.number.value;
long long result = 0;
long long mask = 0ll;
short success = FALSE;

int length =0;
Expand Down Expand Up @@ -1205,6 +1209,18 @@ ast_node_t * fold_binary(ast_node_t *child_0 ,ast_node_t *child_1, operation_lis
success = TRUE;
break;

case ASR:
result = operand_0 >> operand_1;
if(operand_0 < 0)
{
for(long long shift = 0; shift<operand_1; shift++){
mask |= 1 << ((sizeof(long long)*8) - (shift+1));
}
}
result |= mask;
success = TRUE;
break;

case LOGICAL_AND:
result = operand_0 && operand_1;
success = TRUE;
Expand Down
33 changes: 33 additions & 0 deletions ODIN_II/SRC/include/ast_loop_unroll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef LOOP_UNROLL_AST_H
#define LOOP_UNROLL_AST_H

#include "globals.h"
#include "types.h"
#include <stdlib.h>
#include <functional>

/* resolve_pre_condition error codes */
#define UNSUPPORTED_PRE_CONDITION_NODE 1
#define UNSUPPORTED_CONDITION_NODE 2
#define UNSUPPORTED_POST_CONDITION_NODE 3

/* Function Pointer Types */
typedef std::function<bool(long long)> condition_function;
typedef std::function<long long(long long)> post_condition_function;

void unroll_loops();

inline bool is_for_node(ast_node_t* node)
{
return node && node->type == FOR;
}

ast_node_t* for_preprocessor(ast_node_t* node);
ast_node_t* replace_fors(ast_node_t* node);
ast_node_t* resolve_for(ast_node_t* node);
int resolve_pre_condition(ast_node_t* node, ast_node_t** number);
condition_function resolve_condition(ast_node_t* node, ast_node_t* symbol, int* error_code);
post_condition_function resolve_post_condition(ast_node_t* assignment, ast_node_t* symbol, int* error_code);
ast_node_t* dup_and_fill_body(ast_node_t* body, ast_node_t* symbol, ast_node_t** value, int* error_code);

#endif
2 changes: 2 additions & 0 deletions ODIN_II/SRC/include/netlist_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ void join_nets(nnet_t *net, nnet_t* input_net);

void remap_pin_to_new_net(npin_t *pin, nnet_t *new_net);
void remap_pin_to_new_node(npin_t *pin, nnode_t *new_node, int pin_idx);
void remap_pin_to_new_node_range(npin_t *pin, nnode_t *new_node, int pin_range_start, int pin_range_end);


signal_list_t *init_signal_list();
void add_pin_to_signal_list(signal_list_t *list, npin_t* pin);
Expand Down
1 change: 1 addition & 0 deletions ODIN_II/SRC/include/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ typedef enum
LTE, // <=
GTE, // >=
SR, // >>
ASR, // >>>
SL, // <<
CASE_EQUAL, // ===
CASE_NOT_EQUAL, // !==
Expand Down
Loading