blob: 3d195f0b31519267b5f72cfcc745b9f352ddb7c3 [file] [log] [blame] [edit]
/*
Copyright (c) 2009 Peter Andrew Jamieson (jamieson.peter@gmail.com)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "odin_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"
#include "ctype.h"
#include "vtr_util.h"
#include "vtr_memory.h"
#include <string>
#include <iostream>
#include <vector>
#include <stack>
#define read_node 1
#define write_node 2
#define e_data 1
#define e_operation 2
#define e_variable 3
#define N 64
#define Max_size 64
long count_id = 0;
long count_assign = 0;
long count;
long count_write;
enode *head, *p;
void remove_generate(ast_node_t *node)
{
for(int i=0; i<node->num_children; i++){
if(!node->children[i])
continue;
ast_node_t* candidate = node->children[i];
ast_node_t* body_parent = nullptr;
if(candidate->type == GENERATE){
for(int j = 0; j<candidate->num_children; j++){
ast_node_t* new_child = ast_node_deep_copy(candidate->children[j]);
body_parent = body_parent ? newList_entry(body_parent, new_child) : newList(BLOCK, new_child);
}
node->children[i] = body_parent;
free_whole_tree(candidate);
} else {
remove_generate(candidate);
}
}
}
int simplify_ast_module(ast_node_t **ast_module)
{
/* reduce parameters with their values if they have been set */
reduce_parameter(*ast_module);
/* simplify assignment expressions */
reduce_assignment_expression(*ast_module);
/* for loop support */
unroll_loops(ast_module);
/* remove unused node preventing module instantiation */
remove_generate(*ast_module);
/* find multiply or divide operation that can be replaced with shift operation */
shift_operation(*ast_module);
return 1;
}
/*---------------------------------------------------------------------------
* (function: reduce_assignment_expression)
* reduce the number nodes which can be calculated to optimize the AST
*-------------------------------------------------------------------------*/
void reduce_assignment_expression(ast_node_t *ast_module)
{
head = NULL;
p = NULL;
ast_node_t *T = NULL;
if (count_id < ast_module->unique_count)
count_id = ast_module->unique_count;
count_assign = 0;
std::vector<ast_node_t *> list_assign;
find_assign_node(ast_module, list_assign, ast_module->children[0]->types.identifier);
for (long j = 0; j < count_assign; j++)
{
if (check_tree_operation(list_assign[j]->children[1]) && (list_assign[j]->children[1]->num_children > 0))
{
store_exp_list(list_assign[j]->children[1]);
if (deal_with_bracket(list_assign[j]->children[1])) // there are multiple brackets multiplying -- ()*(), stop expanding brackets which may not simplify AST but make it mroe complex
return;
if (simplify_expression())
{
enode *tail = find_tail(head);
free_whole_tree(list_assign[j]->children[1]);
T = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
construct_new_tree(tail, T, list_assign[j]->line_number, list_assign[j]->file_number);
list_assign[j]->children[1] = T;
}
free_exp_list();
}
}
}
/*---------------------------------------------------------------------------
* (function: search_assign_node)
* find the top of the assignment expression
*-------------------------------------------------------------------------*/
void find_assign_node(ast_node_t *node, std::vector<ast_node_t *> list, char *module_name)
{
if (node && node->num_children > 0 && (node->type == BLOCKING_STATEMENT || node->type == NON_BLOCKING_STATEMENT))
{
list.push_back(node);
}
for (long i = 0; node && i < node->num_children; i++)
find_assign_node(node->children[i], list, module_name);
}
/*---------------------------------------------------------------------------
* (function: simplify_expression)
* simplify the expression stored in the linked_list
*-------------------------------------------------------------------------*/
bool simplify_expression()
{
bool build = adjoin_constant();
reduce_enode_list();
if(delete_continuous_multiply())
build = TRUE;
if(combine_constant())
build = TRUE;
reduce_enode_list();
return build;
}
/*---------------------------------------------------------------------------
* (function: find_tail)
*-------------------------------------------------------------------------*/
enode *find_tail(enode *node)
{
enode *temp;
enode *tail = NULL;
for (temp = node; temp != NULL; temp = temp->next)
if (temp->next == NULL)
tail = temp;
return tail;
}
/*---------------------------------------------------------------------------
* (function: reduce_enode_list)
*-------------------------------------------------------------------------*/
void reduce_enode_list()
{
enode *temp;
int a;
while(head != NULL && (head->type.data == 0) && (head->next->priority == 2) && (head->next->type.operation == '+')){
temp=head;
head = head->next->next;
head->pre = NULL;
vtr::free(temp->next);
vtr::free(temp);
}
if(head == NULL){
return;
}
temp = head->next;
while (temp != NULL)
{
if ((temp->flag == 1) && (temp->pre->priority == 2))
{
if (temp->type.data == 0)
{
if (temp->next == NULL)
temp->pre->pre->next = NULL;
else
{
temp->pre->pre->next = temp->next;
temp->next->pre = temp->pre->pre;
}
vtr::free(temp->pre);
enode *toBeDeleted = temp;
temp = temp->next;
vtr::free(toBeDeleted);
} else if (temp->type.data < 0)
{
if (temp->pre->type.operation == '+')
temp->pre->type.operation = '-';
else
temp->pre->type.operation = '+';
a = temp->type.data;
temp->type.data = -a;
temp = temp->next;
} else {
temp = temp->next;
}
} else {
temp = temp->next;
}
}
}
/*---------------------------------------------------------------------------
* (function: store_exp_list)
*-------------------------------------------------------------------------*/
void store_exp_list(ast_node_t *node)
{
enode *temp;
head = (enode*)vtr::malloc(sizeof(enode));
p = head;
record_tree_info(node);
temp = head;
head = head->next;
head->pre = NULL;
p->next = NULL;
vtr::free(temp);
}
/*---------------------------------------------------------------------------
* (function: record_tree_info)
*-------------------------------------------------------------------------*/
void record_tree_info(ast_node_t *node)
{
if (node){
if (node->num_children > 0)
{
record_tree_info(node->children[0]);
create_enode(node);
if (node->num_children > 1)
record_tree_info(node->children[1]);
}else{
create_enode(node);
}
}
}
/*---------------------------------------------------------------------------
* (function: create_enode)
* store elements of an expression in nodes consisting the linked_list
*-------------------------------------------------------------------------*/
void create_enode(ast_node_t *node)
{
enode *s;
s = (enode*)vtr::malloc(sizeof(enode));
s->flag = -1;
s->priority = -1;
s->id = node->unique_count;
switch (node->type)
{
case NUMBERS:
s->type.data = node->types.number.value;
s->flag = 1;
s->priority = 0;
break;
case IDENTIFIERS:
s->type.variable = node->types.identifier;
s->flag = 3;
s->priority = 0;
break;
case BINARY_OPERATION:
{
switch(node->types.operation.op)
{
case ADD:
s->type.operation = '+';
s->flag = 2;
s->priority = 2;
break;
case MINUS:
s->type.operation = '-';
s->flag =2;
s->priority = 2;
break;
case MULTIPLY:
s->type.operation = '*';
s->flag = 2;
s->priority = 1;
break;
case DIVIDE:
s->type.operation = '/';
s->flag = 2;
s->priority = 1;
break;
default:
break;
}
default:
break;
}
}
p->next = s;
s->pre = p;
p = s;
}
/*---------------------------------------------------------------------------
* (function: adjoin_constant)
* compute the constant numbers in the linked_list
*-------------------------------------------------------------------------*/
bool adjoin_constant()
{
bool build = FALSE;
enode *t, *replace;
int a, b, result = 0;
int mark;
for (t = head; t->next!= NULL; )
{
mark = 0;
if ((t->flag == 1) && (t->next->next != NULL) && (t->next->next->flag ==1))
{
switch (t->next->priority)
{
case 1:
a = t->type.data;
b = t->next->next->type.data;
if (t->next->type.operation == '*')
result = a * b;
else
result = a / b;
replace = replace_enode(result, t, 1);
build = TRUE;
mark = 1;
break;
case 2:
if (((t == head) || (t->pre->priority == 2)) && ((t->next->next->next == NULL) ||(t->next->next->next->priority ==2)))
{
a = t->type.data;
b = t->next->next->type.data;
if (t->pre->type.operation == '+')
{
if (t->next->type.operation == '+')
result = a + b;
else
result = a - b;
}
if (t->pre->type.operation == '-')
{
if (t->next->type.operation == '+')
result = a - b;
else
result = a + b;
}
replace = replace_enode(result, t, 1);
build = TRUE;
mark = 1;
}
break;
default:
//pass
break;
}
}
if (mark == 0)
t = t->next;
else
if (mark == 1)
t = replace;
}
return build;
}
/*---------------------------------------------------------------------------
* (function: replace_enode)
*-------------------------------------------------------------------------*/
enode *replace_enode(int data, enode *t, int mark)
{
enode *replace;
replace = (enode*)vtr::malloc(sizeof(enode));
replace->type.data = data;
replace->flag = 1;
replace->priority = 0;
if (t == head)
{
replace->pre = NULL;
head = replace;
}
else
{
replace->pre = t->pre;
t->pre->next = replace;
}
if (mark == 1)
{
replace->next = t->next->next->next;
if (t->next->next->next == NULL)
replace->next = NULL;
else
t->next->next->next->pre = replace;
vtr::free(t->next->next);
vtr::free(t->next);
}
else
{
replace->next = t->next;
t->next->pre = replace;
}
vtr::free(t);
return replace;
}
/*---------------------------------------------------------------------------
* (function: combine_constant)
*-------------------------------------------------------------------------*/
bool combine_constant()
{
enode *temp, *m, *s1, *s2, *replace;
int a, b, result;
int mark;
bool build = FALSE;
for (temp = head; temp != NULL; )
{
mark = 0;
if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 2))
{
if ((temp == head) || (temp->pre->priority == 2))
{
for (m = temp->next; m != NULL; m = m->next)
{
if((m->flag == 1) && (m->pre->priority == 2) && ((m->next == NULL) || (m->next->priority == 2)))
{
s1 = temp;
s2 = m;
a = s1->type.data;
b = s2->type.data;
if ((s1 == head) || (s1->pre->type.operation == '+'))
{
if (s2->pre->type.operation == '+')
result = a + b;
else
result = a - b;
}
else
{
if (s2->pre->type.operation == '+')
result = a - b;
else
result = a + b;
}
replace = replace_enode(result, s1, 2);
if (s2->next == NULL)
{
s2->pre->pre->next = NULL;
mark = 2;
}
else
{
s2->pre->pre->next = s2->next;
s2->next->pre = s2->pre->pre;
}
vtr::free(s2->pre);
vtr::free(s2);
if (replace == head)
{
temp = replace;
mark = 1;
}
else
temp = replace->pre;
build = TRUE;
break;
}
}
}
}
if (mark == 0)
temp = temp->next;
else
if (mark == 1)
continue;
else
break;
}
return build;
}
/*---------------------------------------------------------------------------
* (function: construct_new_tree)
*-------------------------------------------------------------------------*/
void construct_new_tree(enode *tail, ast_node_t *node, int line_num, int file_num)
{
enode *temp, *tail1 = NULL, *tail2 = NULL;
int prio = 0;
if (tail == NULL)
return;
prio = check_exp_list(tail);
if (prio == 1)
{
for (temp = tail; temp != NULL; temp = temp->pre)
if ((temp->flag == 2) && (temp->priority == 2))
{
create_ast_node(temp, node, line_num, file_num);
tail1 = temp->pre;
tail2 = find_tail(temp->next);
tail1->next = NULL;
temp->next->pre = NULL;
break;
}
}
else
if(prio == 2)
{
for (temp = tail; temp != NULL; temp = temp->pre)
if ((temp->flag ==2) && (temp->priority == 1))
{
create_ast_node(temp, node, line_num, file_num);
tail1 = temp->pre;
tail2 = temp->next;
tail2->pre = NULL;
tail2->next = NULL;
break;
}
}
else
if (prio == 3)
create_ast_node(tail, node, line_num, file_num);
if (prio == 1 || prio == 2)
{
node->children = (ast_node_t**)vtr::malloc(2*sizeof(ast_node_t*));
node->children[0] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
node->children[1] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
construct_new_tree(tail1, node->children[0], line_num, file_num);
construct_new_tree(tail2, node->children[1], line_num, file_num);
}
return;
}
/*---------------------------------------------------------------------------
* (function: check_exp_list)
*-------------------------------------------------------------------------*/
int check_exp_list(enode *tail)
{
enode *temp;
for (temp = tail; temp != NULL; temp = temp->pre)
if ((temp->flag == 2) && (temp->priority == 2))
return 1;
for (temp = tail; temp != NULL; temp = temp->pre)
if ((temp->flag == 2) && (temp->priority ==1))
return 2;
return 3;
}
/*---------------------------------------------------------------------------
* (function: delete_continuous_multiply)
*-------------------------------------------------------------------------*/
bool delete_continuous_multiply()
{
enode *temp, *t, *m, *replace;
bool build = FALSE;
int a, b, result;
int mark;
for (temp = head; temp != NULL; )
{
mark = 0;
if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 1))
{
for (t = temp->next; t != NULL; t = t->next)
{
if ((t->flag == 1) && (t->pre->priority ==1))
{
for (m = temp->next; m != t; m = m->next)
{
if ((m->flag == 2) && (m->priority != 1))
{
mark = 1;
break;
}
}
if (mark == 0)
{
a = temp->type.data;
b = t->type.data;
if (t->pre->type.operation == '*')
result = a * b;
else
result = a / b;
replace = replace_enode(result, temp, 3);
if (t->next == NULL)
t->pre->pre->next = NULL;
else
{
t->pre->pre->next = t->next;
t->next->pre = t->pre->pre;
}
mark = 2;
build = TRUE;
vtr::free(t->pre);
vtr::free(t);
break;
}
break;
}
}
}
if ((mark == 0) || (mark == 1))
temp = temp->next;
else
if (mark == 2)
temp = replace;
}
return build;
}
/*---------------------------------------------------------------------------
* (function: create_ast_node)
*-------------------------------------------------------------------------*/
void create_ast_node(enode *temp, ast_node_t *node, int line_num, int file_num)
{
switch(temp->flag)
{
case 1:
initial_node(node, NUMBERS, line_num, file_num, ++count_id);
change_to_number_node(node, temp->type.data);
break;
case 2:
create_op_node(node, temp, line_num, file_num);
break;
case 3:
initial_node(node, IDENTIFIERS, line_num, file_num, ++count_id);
node->types.identifier = vtr::strdup(temp->type.variable.c_str());
break;
default:
break;
}
}
/*---------------------------------------------------------------------------
* (function: create_op_node)
*-------------------------------------------------------------------------*/
void create_op_node(ast_node_t *node, enode *temp, int line_num, int file_num)
{
initial_node(node, BINARY_OPERATION, line_num, file_num, ++count_id);
node->num_children = 2;
switch(temp->type.operation)
{
case '+':
node->types.operation.op = ADD;
break;
case '-':
node->types.operation.op = MINUS;
break;
case '*':
node->types.operation.op = MULTIPLY;
break;
case '/':
node->types.operation.op = DIVIDE;
break;
default:
oassert(FALSE);
break;
}
}
/*---------------------------------------------------------------------------
* (function: free_exp_list)
*-------------------------------------------------------------------------*/
void free_exp_list()
{
enode *next, *temp;
for (temp = head; temp != NULL; temp = next)
{
next = temp->next;
vtr::free(temp);
}
}
/*---------------------------------------------------------------------------
* (function: deal_with_bracket)
*-------------------------------------------------------------------------*/
bool deal_with_bracket(ast_node_t *node)
{
std::vector<int> list_bracket;
recursive_tree(node, list_bracket);
if (!check_mult_bracket(list_bracket)) //if there are brackets multiplying continuously ()*(), stop expanding brackets which may not simplify AST but make it mroe complex
{
for (int i = list_bracket.size()-2; i >= 0; i = i - 2)
delete_bracket(list_bracket[i], list_bracket[i+1]);
return TRUE;
}
return FALSE;
}
/*---------------------------------------------------------------------------
* (function: check_mult_bracket)
* check if the brackets are continuously multiplying
*-------------------------------------------------------------------------*/
bool check_mult_bracket(std::vector<int> list)
{
for (long i = 1; i < list.size() - 2; i = i + 2)
{
enode *node = head;
while (node != NULL && node->next != NULL && node->next->next != NULL)
{
if (node->id == list[i] && node->next->next->id == list[i+1] &&
node->next->flag == 2 &&
(node->next->type.operation == '*' || node->next->type.operation == '/'))
return TRUE;
node = node->next;
}
}
return FALSE;
}
/*---------------------------------------------------------------------------
* (function: recursive_tree)
* search the AST recursively to find brackets
*-------------------------------------------------------------------------*/
void recursive_tree(ast_node_t *node, std::vector<int> list_bracket)
{
if (node && (node->type == BINARY_OPERATION) && (node->types.operation.op == MULTIPLY))
{
for (long i = 0; i < node->num_children; i++)
{
if ((node->children[i]->type == BINARY_OPERATION) && (node->children[i]->types.operation.op == ADD || node->children[i]->types.operation.op == MINUS))
{
find_leaf_node(node->children[i], list_bracket, 0);
find_leaf_node(node->children[i], list_bracket, 1);
}
}
}
for (long i = 0; node && i < node->num_children; i++)
recursive_tree(node->children[i], list_bracket);
}
/*---------------------------------------------------------------------------
* (function: find_lead_node)
*-------------------------------------------------------------------------*/
void find_leaf_node(ast_node_t *node, std::vector<int> list_bracket, int ids2)
{
if (node){
if (node->num_children > 0){
find_leaf_node(node->children[ids2], list_bracket, ids2);
}else{
list_bracket.push_back(node->unique_count);
}
}
}
/*---------------------------------------------------------------------------
* (function: delete_bracket)
*-------------------------------------------------------------------------*/
void delete_bracket(int begin, int end)
{
enode *s1 = NULL, *s2 = NULL, *temp, *p2;
int mark = 0;
for (temp = head; temp != NULL; temp = temp->next)
{
if (temp->id == begin)
{
s1 = temp;
for (p2 = temp; p2 != NULL; p2 = p2->next)
if (p2->id == end)
{
s2 = p2;
mark = 1;
break;
}
}
if (mark == 1)
break;
}
if (s1 == head)
delete_bracket_head(s1, s2);
else
if (s2->next == NULL)
delete_bracket_tail(s1, s2);
else
delete_bracket_body(s1, s2);
if (s1 != head)
check_operation(s1, s2);
}
/*---------------------------------------------------------------------------
* (function: delete_bracket_head)
*-------------------------------------------------------------------------*/
void delete_bracket_head(enode *begin, enode *end)
{
enode *temp;
enode *s = NULL;
for (temp = end; temp != NULL; temp = temp->next)
{
if ((temp->flag == 2) && (temp->priority == 2))
{
s = temp->pre;
break;
}
if (temp->next == NULL)
s = temp;
}
change_exp_list(begin, end, s, 1);
}
/*---------------------------------------------------------------------------
* (function: change_exp_list)
*-------------------------------------------------------------------------*/
void change_exp_list(enode *begin, enode *end, enode *s, int flag)
{
enode *temp, *new_head, *tail, *p2, *partial = NULL, *start = NULL;
int mark;
switch (flag)
{
case 1:
{
for (temp = begin; temp != end; temp = p2->next)
{
mark = 0;
for (p2 = temp; p2 != end->next; p2 = p2->next)
{
if (p2 == end)
{
mark = 2;
break;
}
if ((p2->flag == 2) && (p2->priority == 2))
{
partial = p2->pre;
mark = 1;
break;
}
}
if (mark == 1)
{
new_head = (enode*)vtr::malloc(sizeof(enode));
tail = copy_enode_list(new_head, end->next, s);
tail = tail->pre;
vtr::free(tail->next);
partial->next = new_head;
new_head->pre = partial;
tail->next = p2;
p2->pre = tail;
}
if (mark == 2)
break;
}
break;
}
case 2:
{
for (temp = begin; temp != end->next; temp = temp->next)
if ((temp->flag == 2) && (temp->priority == 2))
{
start = temp;
break;
}
for (temp = start; temp != end->next; temp = partial->next)
{
mark = 0;
for (p2 = temp; p2 != end->next; p2 = p2->next)
{
if (p2 == end)
{
mark = 2;
break;
}
if ((p2->flag == 2) && (p2->priority == 2))
{
partial = p2->next;
mark = 1;
break;
}
}
if (mark == 1)
{
new_head = (enode*)vtr::malloc(sizeof(enode));
tail = copy_enode_list(new_head, s, begin->pre);
tail = tail->pre;
vtr::free(tail->next);
p2->next = new_head;
new_head->pre = p2;
tail->next = partial;
partial->pre = tail;
}
if (mark == 2)
break;
}
break;
}
default:
break;
}
}
/*---------------------------------------------------------------------------
* (function: copy_enode_list)
*-------------------------------------------------------------------------*/
enode *copy_enode_list(enode *new_head, enode *begin, enode *end)
{
enode *temp, *new_enode, *next_enode;
new_enode = new_head;
for (temp = begin; temp != end->next; temp = temp->next)
{
copy_enode(temp, new_enode);
next_enode = (enode*)vtr::malloc(sizeof(enode));
new_enode->next = next_enode;
next_enode->pre = new_enode;
new_enode = next_enode;
}
return new_enode;
}
/*---------------------------------------------------------------------------
* (function: copy_enode)
*-------------------------------------------------------------------------*/
void copy_enode(enode *node, enode *new_node)
{
new_node->type = node->type;
new_node->flag = node->flag;
new_node->priority = node->priority;
new_node->id = -1;
}
/*---------------------------------------------------------------------------
* (function: deleted_bracket_tail)
*-------------------------------------------------------------------------*/
void delete_bracket_tail(enode *begin, enode *end)
{
enode *temp, *s = NULL;
for (temp = begin; temp != NULL; temp = temp->pre)
if ((temp->flag == 2) && (temp->priority == 2)) // '+' or '-'
{
s = temp->next;
break;
}
change_exp_list(begin, end, s, 2);
}
/*---------------------------------------------------------------------------
* (function: delete_bracket_body)
*-------------------------------------------------------------------------*/
void delete_bracket_body(enode *begin, enode *end)
{
enode *temp;
if ((begin->pre->priority == 1) && (end->next->priority == 2))
delete_bracket_tail(begin, end);
if ((begin->pre->priority == 2) && (end->next->priority == 1))
delete_bracket_head(begin, end);
if ((begin->pre->priority == 1) && (end->next->priority == 1))
{
delete_bracket_tail(begin, end);
for (temp = begin; temp != NULL; temp = temp->pre)
if ((temp->flag == 2) && (temp->priority == 2))
{
begin = temp->next;
break;
}
delete_bracket_head(begin, end);
}
}
/*---------------------------------------------------------------------------
* (function: check_tree_operation)
*-------------------------------------------------------------------------*/
bool check_tree_operation(ast_node_t *node)
{
if (node && (node->type == BINARY_OPERATION) && ((node->types.operation.op == ADD ) || (node->types.operation.op == MINUS) || (node->types.operation.op == MULTIPLY)))
return TRUE;
for (long i = 0; node && i < node->num_children; i++)
if(check_tree_operation(node->children[i]))
return TRUE;
return FALSE;
}
/*---------------------------------------------------------------------------
* (function: check_operation)
*-------------------------------------------------------------------------*/
void check_operation(enode *begin, enode *end)
{
enode *temp, *op;
for (temp = begin; temp != head; temp = temp->pre)
{
if (temp->flag == 2 && temp->priority == 2 && temp->type.operation == '-')
{
for (op = begin; op != end; op = op->next)
{
if (op->flag == 2 && op->priority == 2)
{
if (op->type.operation == '+')
op->type.operation = '-';
else
op->type.operation = '+';
}
}
}
}
}
/*---------------------------------------------------------------------------
* (function: reduce_parameter)
* replace parameters with their values in the AST
*-------------------------------------------------------------------------*/
void reduce_parameter(ast_node_t *ast_module)
{
std::vector<ast_node_t *>para;
find_parameter(ast_module, para);
if (ast_module->types.module.is_instantiated == 0 && !para.empty())
remove_para_node(ast_module, para);
}
/*---------------------------------------------------------------------------
* (function: find_parameter)
*-------------------------------------------------------------------------*/
void find_parameter(ast_node_t *node, std::vector<ast_node_t *>para)
{
for (long i = 0; node && i < node->num_children; i++)
{
if (node->children[i] && node->children[i]->type == VAR_DECLARE && node->children[i]->types.variable.is_parameter == 1)
para.push_back(node->children[i]);
find_parameter(node->children[i], para);
}
}
/*---------------------------------------------------------------------------
* (function: remove_para_node)
*-------------------------------------------------------------------------*/
void remove_para_node(ast_node_t *top, std::vector<ast_node_t *> para)
{
std::vector<ast_node_t *> list;
count_assign = 0;
find_assign_node(top, list, top->children[0]->types.identifier);
if (count_assign!= 0){
for (long i = 0; i < para.size(); i++)
{
std::string name;
long value = 0;
if (para[i] && para[i]->children[0])
name = para[i]->children[0]->types.identifier;
if (node_is_constant(para[i]->children[5]))
value = para[i]->children[5]->types.number.value;
for (long j = 0; j < count_assign; j++){
change_para_node(list[j], name, value);
}
}
}
}
/*---------------------------------------------------------------------------
* (function: change_para_node)
*-------------------------------------------------------------------------*/
void change_para_node(ast_node_t *node, std::string name, long value)
{
if (node && node->type == IDENTIFIERS && name == (std::string) node->types.identifier)
change_to_number_node(node, value);
for (long i = 0; node && i < node->num_children; i++)
change_para_node(node->children[i], name, value);
}
/*---------------------------------------------------------------------------
* (function: copy_tree)
* find multiply or divide operation that can be replaced with shift operation
*-------------------------------------------------------------------------*/
void shift_operation(ast_node_t *ast_module)
{
if(ast_module){
search_certain_operation(ast_module);
}
}
/*---------------------------------------------------------------------------
* (function: change_ast_node)
* search all AST to find multiply or divide operations
*-------------------------------------------------------------------------*/
void search_certain_operation(ast_node_t *node)
{
for (long i = 0; node && i < node->num_children; i++){
check_binary_operation(node->children[i]);
search_certain_operation(node->children[i]);
}
}
/*---------------------------------------------------------------------------
* (function: change_ast_node)
* check the children nodes of an operation node
*-------------------------------------------------------------------------*/
void check_binary_operation(ast_node_t *node)
{
if(node && node->type == BINARY_OPERATION){
switch(node->types.operation.op){
case MULTIPLY:
if (node->children[0]->type == IDENTIFIERS && node->children[1]->type == NUMBERS)
check_node_number(node, node->children[1], 1); // 1 means multiply and don't need to move children nodes
if (node->children[0]->type == NUMBERS && node->children[1]->type == IDENTIFIERS)
check_node_number(node, node->children[0], 2); // 2 means multiply and needs to move children nodes
break;
case DIVIDE:
if (node->children[0]->type == IDENTIFIERS && node->children[1]->type == NUMBERS)
check_node_number(node, node->children[1], 3); // 3 means divide
break;
default:
break;
}
}
}
/*---------------------------------------------------------------------------
* (function: change_ast_node)
* check if the number is the power of 2
*-------------------------------------------------------------------------*/
void check_node_number(ast_node_t *parent, ast_node_t *child, int flag)
{
long power = 0;
long number = child->types.number.value;
if (number <= 1)
return;
while (((number % 2) == 0) && number > 1) // While number is even and > 1
{
number >>= 1;
power++;
}
if (number == 1) // the previous number is a power of 2
{
change_to_number_node(child, power);
if (flag == 1) // multiply
parent->types.operation.op = SL;
else if (flag == 2) // multiply and needs to move children nodes
{
parent->types.operation.op = SL;
parent->children[0] = parent->children[1];
parent->children[1] = child;
}
else if (flag == 3) // divide
parent->types.operation.op = SR;
}
}
/*---------------------------------------------------------------------------
* (function: check_intermediate_variable)
* check if there are intermediate variables
*-------------------------------------------------------------------------*/
short has_intermediate_variable(ast_node_t *node){
if (node && (node->is_read_write == 1 || node->is_read_write == 2))
return TRUE;
for (long i = 0; node && i < node->num_children; i++){
if(has_intermediate_variable(node->children[i]))
return TRUE;
}
return FALSE;
}