blob: dd0d4415f9fc186dde3c8718281e4fd58174c500 [file] [log] [blame]
# Copyright (c) 2021, Alliance for Open Media. All rights reserved
#
# This source code is subject to the terms of the BSD 2 Clause License and
# the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
# was not distributed with this source code in the LICENSE file, you can
# obtain it at www.aomedia.org/license/software. If the Alliance for Open
# Media Patent License 1.0 was not distributed with this source code in the
# PATENTS file, you can obtain it at www.aomedia.org/license/patent.
#
from __future__ import print_function
import sys
import os
import operator
from pycparser import c_parser, c_ast, parse_file
from math import *
from inspect import currentframe, getframeinfo
from collections import deque
def debug_print(frameinfo):
print('******** ERROR:', frameinfo.filename, frameinfo.lineno, '********')
class StructItem():
def __init__(self,
typedef_name=None,
struct_name=None,
struct_node=None,
is_union=False):
self.typedef_name = typedef_name
self.struct_name = struct_name
self.struct_node = struct_node
self.is_union = is_union
self.child_decl_map = None
def __str__(self):
return str(self.typedef_name) + ' ' + str(self.struct_name) + ' ' + str(
self.is_union)
def compute_child_decl_map(self, struct_info):
self.child_decl_map = {}
if self.struct_node != None and self.struct_node.decls != None:
for decl_node in self.struct_node.decls:
if decl_node.name == None:
for sub_decl_node in decl_node.type.decls:
sub_decl_status = parse_decl_node(struct_info, sub_decl_node)
self.child_decl_map[sub_decl_node.name] = sub_decl_status
else:
decl_status = parse_decl_node(struct_info, decl_node)
self.child_decl_map[decl_status.name] = decl_status
def get_child_decl_status(self, decl_name):
if self.child_decl_map == None:
debug_print(getframeinfo(currentframe()))
print('child_decl_map is None')
return None
if decl_name not in self.child_decl_map:
debug_print(getframeinfo(currentframe()))
print(decl_name, 'does not exist ')
return None
return self.child_decl_map[decl_name]
class StructInfo():
def __init__(self):
self.struct_name_dic = {}
self.typedef_name_dic = {}
self.enum_value_dic = {} # enum value -> enum_node
self.enum_name_dic = {} # enum name -> enum_node
self.struct_item_list = []
def get_struct_by_typedef_name(self, typedef_name):
if typedef_name in self.typedef_name_dic:
return self.typedef_name_dic[typedef_name]
else:
return None
def get_struct_by_struct_name(self, struct_name):
if struct_name in self.struct_name_dic:
return self.struct_name_dic[struct_name]
else:
debug_print(getframeinfo(currentframe()))
print('Cant find', struct_name)
return None
def update_struct_item_list(self):
# Collect all struct_items from struct_name_dic and typedef_name_dic
# Compute child_decl_map for each struct item.
for struct_name in self.struct_name_dic.keys():
struct_item = self.struct_name_dic[struct_name]
struct_item.compute_child_decl_map(self)
self.struct_item_list.append(struct_item)
for typedef_name in self.typedef_name_dic.keys():
struct_item = self.typedef_name_dic[typedef_name]
if struct_item.struct_name not in self.struct_name_dic:
struct_item.compute_child_decl_map(self)
self.struct_item_list.append(struct_item)
def update_enum(self, enum_node):
if enum_node.name != None:
self.enum_name_dic[enum_node.name] = enum_node
if enum_node.values != None:
enumerator_list = enum_node.values.enumerators
for enumerator in enumerator_list:
self.enum_value_dic[enumerator.name] = enum_node
def update(self,
typedef_name=None,
struct_name=None,
struct_node=None,
is_union=False):
"""T: typedef_name S: struct_name N: struct_node
T S N
case 1: o o o
typedef struct P {
int u;
} K;
T S N
case 2: o o x
typedef struct P K;
T S N
case 3: x o o
struct P {
int u;
};
T S N
case 4: o x o
typedef struct {
int u;
} K;
"""
struct_item = None
# Check whether struct_name or typedef_name is already in the dictionary
if struct_name in self.struct_name_dic:
struct_item = self.struct_name_dic[struct_name]
if typedef_name in self.typedef_name_dic:
struct_item = self.typedef_name_dic[typedef_name]
if struct_item == None:
struct_item = StructItem(typedef_name, struct_name, struct_node, is_union)
if struct_node.decls != None:
struct_item.struct_node = struct_node
if struct_name != None:
self.struct_name_dic[struct_name] = struct_item
if typedef_name != None:
self.typedef_name_dic[typedef_name] = struct_item
class StructDefVisitor(c_ast.NodeVisitor):
def __init__(self):
self.struct_info = StructInfo()
def visit_Struct(self, node):
if node.decls != None:
self.struct_info.update(None, node.name, node)
self.generic_visit(node)
def visit_Union(self, node):
if node.decls != None:
self.struct_info.update(None, node.name, node, True)
self.generic_visit(node)
def visit_Enum(self, node):
self.struct_info.update_enum(node)
self.generic_visit(node)
def visit_Typedef(self, node):
if node.type.__class__.__name__ == 'TypeDecl':
typedecl = node.type
if typedecl.type.__class__.__name__ == 'Struct':
struct_node = typedecl.type
typedef_name = node.name
struct_name = struct_node.name
self.struct_info.update(typedef_name, struct_name, struct_node)
elif typedecl.type.__class__.__name__ == 'Union':
union_node = typedecl.type
typedef_name = node.name
union_name = union_node.name
self.struct_info.update(typedef_name, union_name, union_node, True)
# TODO(angiebird): Do we need to deal with enum here?
self.generic_visit(node)
def build_struct_info(ast):
v = StructDefVisitor()
v.visit(ast)
struct_info = v.struct_info
struct_info.update_struct_item_list()
return v.struct_info
class DeclStatus():
def __init__(self, name, struct_item=None, is_ptr_decl=False):
self.name = name
self.struct_item = struct_item
self.is_ptr_decl = is_ptr_decl
def get_child_decl_status(self, decl_name):
if self.struct_item != None:
return self.struct_item.get_child_decl_status(decl_name)
else:
#TODO(angiebird): 2. Investigage the situation when a struct's definition can't be found.
return None
def __str__(self):
return str(self.struct_item) + ' ' + str(self.name) + ' ' + str(
self.is_ptr_decl)
def peel_ptr_decl(decl_type_node):
""" Remove PtrDecl and ArrayDecl layer """
is_ptr_decl = False
peeled_decl_type_node = decl_type_node
while peeled_decl_type_node.__class__.__name__ == 'PtrDecl' or peeled_decl_type_node.__class__.__name__ == 'ArrayDecl':
is_ptr_decl = True
peeled_decl_type_node = peeled_decl_type_node.type
return is_ptr_decl, peeled_decl_type_node
def parse_peeled_decl_type_node(struct_info, node):
struct_item = None
if node.__class__.__name__ == 'TypeDecl':
if node.type.__class__.__name__ == 'IdentifierType':
identifier_type_node = node.type
typedef_name = identifier_type_node.names[0]
struct_item = struct_info.get_struct_by_typedef_name(typedef_name)
elif node.type.__class__.__name__ == 'Struct':
struct_node = node.type
if struct_node.name != None:
struct_item = struct_info.get_struct_by_struct_name(struct_node.name)
else:
struct_item = StructItem(None, None, struct_node, False)
struct_item.compute_child_decl_map(struct_info)
elif node.type.__class__.__name__ == 'Union':
# TODO(angiebird): Special treatment for Union?
struct_node = node.type
if struct_node.name != None:
struct_item = struct_info.get_struct_by_struct_name(struct_node.name)
else:
struct_item = StructItem(None, None, struct_node, True)
struct_item.compute_child_decl_map(struct_info)
elif node.type.__class__.__name__ == 'Enum':
# TODO(angiebird): Special treatment for Union?
struct_node = node.type
struct_item = None
else:
print('Unrecognized peeled_decl_type_node.type',
node.type.__class__.__name__)
else:
# debug_print(getframeinfo(currentframe()))
# print(node.__class__.__name__)
#TODO(angiebird): Do we need to take care of this part?
pass
return struct_item
def parse_decl_node(struct_info, decl_node):
# struct_item is None if this decl_node is not a struct_item
decl_node_name = decl_node.name
decl_type_node = decl_node.type
is_ptr_decl, peeled_decl_type_node = peel_ptr_decl(decl_type_node)
struct_item = parse_peeled_decl_type_node(struct_info, peeled_decl_type_node)
return DeclStatus(decl_node_name, struct_item, is_ptr_decl)
def get_lvalue_lead(lvalue_node):
"""return '&' or '*' of lvalue if available"""
if lvalue_node.__class__.__name__ == 'UnaryOp' and lvalue_node.op == '&':
return '&'
elif lvalue_node.__class__.__name__ == 'UnaryOp' and lvalue_node.op == '*':
return '*'
return None
def parse_lvalue(lvalue_node):
"""get id_chain from lvalue"""
id_chain = parse_lvalue_recursive(lvalue_node, [])
return id_chain
def parse_lvalue_recursive(lvalue_node, id_chain):
"""cpi->rd->u -> (cpi->rd)->u"""
if lvalue_node.__class__.__name__ == 'ID':
id_chain.append(lvalue_node.name)
id_chain.reverse()
return id_chain
elif lvalue_node.__class__.__name__ == 'StructRef':
id_chain.append(lvalue_node.field.name)
return parse_lvalue_recursive(lvalue_node.name, id_chain)
elif lvalue_node.__class__.__name__ == 'ArrayRef':
return parse_lvalue_recursive(lvalue_node.name, id_chain)
elif lvalue_node.__class__.__name__ == 'UnaryOp' and lvalue_node.op == '&':
return parse_lvalue_recursive(lvalue_node.expr, id_chain)
elif lvalue_node.__class__.__name__ == 'UnaryOp' and lvalue_node.op == '*':
return parse_lvalue_recursive(lvalue_node.expr, id_chain)
else:
return None
class FuncDefVisitor(c_ast.NodeVisitor):
func_dictionary = {}
def visit_FuncDef(self, node):
func_name = node.decl.name
self.func_dictionary[func_name] = node
def build_func_dictionary(ast):
v = FuncDefVisitor()
v.visit(ast)
return v.func_dictionary
def get_func_start_coord(func_node):
return func_node.coord
def find_end_node(node):
node_list = []
for c in node:
node_list.append(c)
if len(node_list) == 0:
return node
else:
return find_end_node(node_list[-1])
def get_func_end_coord(func_node):
return find_end_node(func_node).coord
def get_func_size(func_node):
start_coord = get_func_start_coord(func_node)
end_coord = get_func_end_coord(func_node)
if start_coord.file == end_coord.file:
return end_coord.line - start_coord.line + 1
else:
return None
def save_object(obj, filename):
with open(filename, 'wb') as obj_fp:
pickle.dump(obj, obj_fp, protocol=-1)
def load_object(filename):
obj = None
with open(filename, 'rb') as obj_fp:
obj = pickle.load(obj_fp)
return obj
def get_av1_ast(gen_ast=False):
# TODO(angiebird): Generalize this path
c_filename = './av1_pp.c'
print('generate ast')
ast = parse_file(c_filename)
#save_object(ast, ast_file)
print('finished generate ast')
return ast
def get_func_param_id_map(func_def_node):
param_id_map = {}
func_decl = func_def_node.decl.type
param_list = func_decl.args.params
for decl in param_list:
param_id_map[decl.name] = decl
return param_id_map
class IDTreeStack():
def __init__(self, global_id_tree):
self.stack = deque()
self.global_id_tree = global_id_tree
def add_link_node(self, node, link_id_chain):
link_node = self.add_id_node(link_id_chain)
node.link_node = link_node
node.link_id_chain = link_id_chain
def push_id_tree(self, id_tree=None):
if id_tree == None:
id_tree = IDStatusNode()
self.stack.append(id_tree)
return id_tree
def pop_id_tree(self):
return self.stack.pop()
def add_id_seed_node(self, id_seed, decl_status):
return self.stack[-1].add_child(id_seed, decl_status)
def get_id_seed_node(self, id_seed):
idx = len(self.stack) - 1
while idx >= 0:
id_node = self.stack[idx].get_child(id_seed)
if id_node != None:
return id_node
idx -= 1
id_node = self.global_id_tree.get_child(id_seed)
if id_node != None:
return id_node
return None
def add_id_node(self, id_chain):
id_seed = id_chain[0]
id_seed_node = self.get_id_seed_node(id_seed)
if id_seed_node == None:
return None
if len(id_chain) == 1:
return id_seed_node
return id_seed_node.add_descendant(id_chain[1:])
def get_id_node(self, id_chain):
id_seed = id_chain[0]
id_seed_node = self.get_id_seed_node(id_seed)
if id_seed_node == None:
return None
if len(id_chain) == 1:
return id_seed_node
return id_seed_node.get_descendant(id_chain[1:])
def top(self):
return self.stack[-1]
class IDStatusNode():
def __init__(self, name=None, root=None):
if root is None:
self.root = self
else:
self.root = root
self.name = name
self.parent = None
self.children = {}
self.assign = False
self.last_assign_coord = None
self.refer = False
self.last_refer_coord = None
self.decl_status = None
self.link_id_chain = None
self.link_node = None
self.visit = False
def set_link_id_chain(self, link_id_chain):
self.set_assign(False)
self.link_id_chain = link_id_chain
self.link_node = self.root.get_descendant(link_id_chain)
def set_link_node(self, link_node):
self.set_assign(False)
self.link_id_chain = ['*']
self.link_node = link_node
def get_link_id_chain(self):
return self.link_id_chain
def get_concrete_node(self):
if self.visit == True:
# return None when there is a loop
return None
self.visit = True
if self.link_node == None:
self.visit = False
return self
else:
concrete_node = self.link_node.get_concrete_node()
self.visit = False
if concrete_node == None:
return self
return concrete_node
def set_assign(self, assign, coord=None):
concrete_node = self.get_concrete_node()
concrete_node.assign = assign
concrete_node.last_assign_coord = coord
def get_assign(self):
concrete_node = self.get_concrete_node()
return concrete_node.assign
def set_refer(self, refer, coord=None):
concrete_node = self.get_concrete_node()
concrete_node.refer = refer
concrete_node.last_refer_coord = coord
def get_refer(self):
concrete_node = self.get_concrete_node()
return concrete_node.refer
def set_parent(self, parent):
concrete_node = self.get_concrete_node()
concrete_node.parent = parent
def add_child(self, name, decl_status=None):
concrete_node = self.get_concrete_node()
if name not in concrete_node.children:
child_id_node = IDStatusNode(name, concrete_node.root)
concrete_node.children[name] = child_id_node
if decl_status == None:
# Check if the child decl_status can be inferred from its parent's
# decl_status
if self.decl_status != None:
decl_status = self.decl_status.get_child_decl_status(name)
child_id_node.set_decl_status(decl_status)
return concrete_node.children[name]
def get_child(self, name):
concrete_node = self.get_concrete_node()
if name in concrete_node.children:
return concrete_node.children[name]
else:
return None
def add_descendant(self, id_chain):
current_node = self.get_concrete_node()
for name in id_chain:
current_node.add_child(name)
parent_node = current_node
current_node = current_node.get_child(name)
current_node.set_parent(parent_node)
return current_node
def get_descendant(self, id_chain):
current_node = self.get_concrete_node()
for name in id_chain:
current_node = current_node.get_child(name)
if current_node == None:
return None
return current_node
def get_children(self):
current_node = self.get_concrete_node()
return current_node.children
def set_decl_status(self, decl_status):
current_node = self.get_concrete_node()
current_node.decl_status = decl_status
def get_decl_status(self):
current_node = self.get_concrete_node()
return current_node.decl_status
def __str__(self):
if self.link_id_chain is None:
return str(self.name) + ' a: ' + str(int(self.assign)) + ' r: ' + str(
int(self.refer))
else:
return str(self.name) + ' -> ' + ' '.join(self.link_id_chain)
def collect_assign_refer_status(self,
id_chain=None,
assign_ls=None,
refer_ls=None):
if id_chain == None:
id_chain = []
if assign_ls == None:
assign_ls = []
if refer_ls == None:
refer_ls = []
id_chain.append(self.name)
if self.assign:
info_str = ' '.join([
' '.join(id_chain[1:]), 'a:',
str(int(self.assign)), 'r:',
str(int(self.refer)),
str(self.last_assign_coord)
])
assign_ls.append(info_str)
if self.refer:
info_str = ' '.join([
' '.join(id_chain[1:]), 'a:',
str(int(self.assign)), 'r:',
str(int(self.refer)),
str(self.last_refer_coord)
])
refer_ls.append(info_str)
for c in self.children:
self.children[c].collect_assign_refer_status(id_chain, assign_ls,
refer_ls)
id_chain.pop()
return assign_ls, refer_ls
def show(self):
assign_ls, refer_ls = self.collect_assign_refer_status()
print('---- assign ----')
for item in assign_ls:
print(item)
print('---- refer ----')
for item in refer_ls:
print(item)
class FuncInOutVisitor(c_ast.NodeVisitor):
def __init__(self,
func_def_node,
struct_info,
func_dictionary,
keep_body_id_tree=True,
call_param_map=None,
global_id_tree=None,
func_history=None,
unknown=None):
self.func_dictionary = func_dictionary
self.struct_info = struct_info
self.param_id_map = get_func_param_id_map(func_def_node)
self.parent_node = None
self.global_id_tree = global_id_tree
self.body_id_tree = None
self.keep_body_id_tree = keep_body_id_tree
if func_history == None:
self.func_history = {}
else:
self.func_history = func_history
if unknown == None:
self.unknown = []
else:
self.unknown = unknown
self.id_tree_stack = IDTreeStack(global_id_tree)
self.id_tree_stack.push_id_tree()
#TODO move this part into a function
for param in self.param_id_map:
decl_node = self.param_id_map[param]
decl_status = parse_decl_node(self.struct_info, decl_node)
descendant = self.id_tree_stack.add_id_seed_node(decl_status.name,
decl_status)
if call_param_map is not None and param in call_param_map:
# This is a function call.
# Map the input parameter to the caller's nodes
# TODO(angiebird): Can we use add_link_node here?
descendant.set_link_node(call_param_map[param])
def get_id_tree_stack(self):
return self.id_tree_stack
def generic_visit(self, node):
prev_parent = self.parent_node
self.parent_node = node
for c in node:
self.visit(c)
self.parent_node = prev_parent
# TODO rename
def add_new_id_tree(self, node):
self.id_tree_stack.push_id_tree()
self.generic_visit(node)
id_tree = self.id_tree_stack.pop_id_tree()
if self.parent_node == None and self.keep_body_id_tree == True:
# this is function body
self.body_id_tree = id_tree
def visit_For(self, node):
self.add_new_id_tree(node)
def visit_Compound(self, node):
self.add_new_id_tree(node)
def visit_Decl(self, node):
if node.type.__class__.__name__ != 'FuncDecl':
decl_status = parse_decl_node(self.struct_info, node)
descendant = self.id_tree_stack.add_id_seed_node(decl_status.name,
decl_status)
if node.init is not None:
init_id_chain = self.process_lvalue(node.init)
if init_id_chain != None:
if decl_status.struct_item is None:
init_descendant = self.id_tree_stack.add_id_node(init_id_chain)
if init_descendant != None:
init_descendant.set_refer(True, node.coord)
else:
self.unknown.append(node)
descendant.set_assign(True, node.coord)
else:
self.id_tree_stack.add_link_node(descendant, init_id_chain)
else:
self.unknown.append(node)
else:
descendant.set_assign(True, node.coord)
self.generic_visit(node)
def is_lvalue(self, node):
if self.parent_node is None:
# TODO(angiebird): Do every lvalue has parent_node != None?
return False
if self.parent_node.__class__.__name__ == 'StructRef':
return False
if self.parent_node.__class__.__name__ == 'ArrayRef' and node == self.parent_node.name:
# if node == self.parent_node.subscript, the node could be lvalue
return False
if self.parent_node.__class__.__name__ == 'UnaryOp' and self.parent_node.op == '&':
return False
if self.parent_node.__class__.__name__ == 'UnaryOp' and self.parent_node.op == '*':
return False
return True
def process_lvalue(self, node):
id_chain = parse_lvalue(node)
if id_chain == None:
return id_chain
elif id_chain[0] in self.struct_info.enum_value_dic:
return None
else:
return id_chain
def process_possible_lvalue(self, node):
if self.is_lvalue(node):
id_chain = self.process_lvalue(node)
lead_char = get_lvalue_lead(node)
# make sure the id is not an enum value
if id_chain == None:
self.unknown.append(node)
return
descendant = self.id_tree_stack.add_id_node(id_chain)
if descendant == None:
self.unknown.append(node)
return
decl_status = descendant.get_decl_status()
if decl_status == None:
descendant.set_assign(True, node.coord)
descendant.set_refer(True, node.coord)
self.unknown.append(node)
return
if self.parent_node.__class__.__name__ == 'Assignment':
if node is self.parent_node.lvalue:
if decl_status.struct_item != None:
if len(id_chain) > 1:
descendant.set_assign(True, node.coord)
elif len(id_chain) == 1:
if lead_char == '*':
descendant.set_assign(True, node.coord)
else:
right_id_chain = self.process_lvalue(self.parent_node.rvalue)
if right_id_chain != None:
self.id_tree_stack.add_link_node(descendant, right_id_chain)
else:
#TODO(angiebird): 1.Find a better way to deal with this case.
descendant.set_assign(True, node.coord)
else:
debug_print(getframeinfo(currentframe()))
else:
descendant.set_assign(True, node.coord)
elif node is self.parent_node.rvalue:
if decl_status.struct_item is None:
descendant.set_refer(True, node.coord)
if lead_char == '&':
descendant.set_assign(True, node.coord)
else:
left_id_chain = self.process_lvalue(self.parent_node.lvalue)
left_lead_char = get_lvalue_lead(self.parent_node.lvalue)
if left_id_chain != None:
if len(left_id_chain) > 1:
descendant.set_refer(True, node.coord)
elif len(left_id_chain) == 1:
if left_lead_char == '*':
descendant.set_refer(True, node.coord)
else:
#TODO(angiebird): Check whether the other node is linked to this node.
pass
else:
self.unknown.append(self.parent_node.lvalue)
debug_print(getframeinfo(currentframe()))
else:
self.unknown.append(self.parent_node.lvalue)
debug_print(getframeinfo(currentframe()))
else:
debug_print(getframeinfo(currentframe()))
elif self.parent_node.__class__.__name__ == 'UnaryOp':
# TODO(angiebird): Consider +=, *=, -=, /= etc
if self.parent_node.op == '--' or self.parent_node.op == '++' or\
self.parent_node.op == 'p--' or self.parent_node.op == 'p++':
descendant.set_assign(True, node.coord)
descendant.set_refer(True, node.coord)
else:
descendant.set_refer(True, node.coord)
elif self.parent_node.__class__.__name__ == 'Decl':
#The logic is at visit_Decl
pass
elif self.parent_node.__class__.__name__ == 'ExprList':
#The logic is at visit_FuncCall
pass
else:
descendant.set_refer(True, node.coord)
def visit_ID(self, node):
# If the parent is a FuncCall, this ID is a function name.
if self.parent_node.__class__.__name__ != 'FuncCall':
self.process_possible_lvalue(node)
self.generic_visit(node)
def visit_StructRef(self, node):
self.process_possible_lvalue(node)
self.generic_visit(node)
def visit_ArrayRef(self, node):
self.process_possible_lvalue(node)
self.generic_visit(node)
def visit_UnaryOp(self, node):
if node.op == '&' or node.op == '*':
self.process_possible_lvalue(node)
self.generic_visit(node)
def visit_FuncCall(self, node):
if node.name.__class__.__name__ == 'ID':
if node.name.name in self.func_dictionary:
if node.name.name not in self.func_history:
self.func_history[node.name.name] = True
func_def_node = self.func_dictionary[node.name.name]
call_param_map = self.process_func_call(node, func_def_node)
visitor = FuncInOutVisitor(func_def_node, self.struct_info,
self.func_dictionary, False,
call_param_map, self.global_id_tree,
self.func_history, self.unknown)
visitor.visit(func_def_node.body)
else:
self.unknown.append(node)
self.generic_visit(node)
def process_func_call(self, func_call_node, func_def_node):
# set up a refer/assign for func parameters
# return call_param_map
call_param_ls = func_call_node.args.exprs
call_param_map = {}
func_decl = func_def_node.decl.type
decl_param_ls = func_decl.args.params
for param_node, decl_node in zip(call_param_ls, decl_param_ls):
id_chain = self.process_lvalue(param_node)
if id_chain != None:
descendant = self.id_tree_stack.add_id_node(id_chain)
if descendant == None:
self.unknown.append(param_node)
else:
decl_status = descendant.get_decl_status()
if decl_status != None:
if decl_status.struct_item == None:
if decl_status.is_ptr_decl == True:
descendant.set_assign(True, param_node.coord)
descendant.set_refer(True, param_node.coord)
else:
descendant.set_refer(True, param_node.coord)
else:
call_param_map[decl_node.name] = descendant
else:
self.unknown.append(param_node)
else:
self.unknown.append(param_node)
return call_param_map
def build_global_id_tree(ast, struct_info):
global_id_tree = IDStatusNode()
for node in ast.ext:
if node.__class__.__name__ == 'Decl':
# id tree is for tracking assign/refer status
# we don't care about function id because they can't be changed
if node.type.__class__.__name__ != 'FuncDecl':
decl_status = parse_decl_node(struct_info, node)
descendant = global_id_tree.add_child(decl_status.name, decl_status)
return global_id_tree
class FuncAnalyzer():
def __init__(self):
self.ast = get_av1_ast()
self.struct_info = build_struct_info(self.ast)
self.func_dictionary = build_func_dictionary(self.ast)
self.global_id_tree = build_global_id_tree(self.ast, self.struct_info)
def analyze(self, func_name):
if func_name in self.func_dictionary:
func_def_node = self.func_dictionary[func_name]
visitor = FuncInOutVisitor(func_def_node, self.struct_info,
self.func_dictionary, True, None,
self.global_id_tree)
visitor.visit(func_def_node.body)
root = visitor.get_id_tree_stack()
root.top().show()
else:
print(func_name, "doesn't exist")
if __name__ == '__main__':
fa = FuncAnalyzer()
fa.analyze('tpl_get_satd_cost')
pass