def __init__(self, field: Decl, ast, tag, annotation_types): self.field = field self.field_name = field.name field_type = type(field.type) if field_type == TypeDecl: decl_type = type(field.type.type) if decl_type == IdentifierType: self.c_type = field.type.type.names[0] self.type = FieldType.NORMAL elif decl_type == Struct: self.type = FieldType.STRUCT self.c_type = field.type.type.name self.struct = struct_by_name(ast, self.c_type) self.fields_and_annotations = walk_struct(ast, tag, self.struct, annotation_types) elif decl_type == CEnum: self.type = FieldType.ENUM self.c_type = field.type.type.name self.enum = enum_by_name(ast, self.c_type) else: field.show() assert False, ("TypeDecl type %s not handled" % decl_type) elif field_type == PtrDecl: self.c_type = field.type.type.type.names[0] self.type = FieldType.POINTER else: assert False, ("field type %s not handled" % (type(field.type)))
def translate_Decl(c_ast): pat = Decl(Var("name"), [], [], [], Var("type"), Var("init", True), None) subst = unify(pat, c_ast) if subst is None: pat.show() c_ast.show() name = subst.lookup("name") raw_typ = subst.lookup("type") raw_init = subst.lookup("init") typ = translate_typ(raw_typ) if raw_init is not None: init = translate_exp(raw_init) else: init = None return (name, typ, init)
def gen_memo_flag_node(self,self_touch): val = 'true' if self_touch else 'false' type_ = TypeDecl(declname = self.memo_flag_name, quals=[], type=IdentifierType(names=['bool'])) return Decl(name=self.entity, quals=[], storage=[], funcspec=[], type= type_, init=ID(name=val), bitsize=None)
def anonymize_param(param: ca.Decl) -> ca.Typename: param = copy.deepcopy(param) param.name = None set_decl_name(param) return ca.Typename(name=None, quals=param.quals, type=param.type, align=[])
def touch_definition_node(self): type_ = FuncDecl(args=None, type=TypeDecl(declname=self.c_touch_name, quals=[], type=IdentifierType(names=['void']))) return FuncDef(decl=Decl(name=self.c_touch_name, quals=[], storage=[], funcspec=[], type=type_, init=None, bitsize=None), param_decls=None, body=Compound(block_items=[]))
def void_ptr_ptr(cls, ident: str): """ Special method for generating a void** (corner case)""" obj = cls(ident, MVoid, True) obj.ptr_decl = PtrDecl(quals=[], type=obj.ptr_decl) obj.decl = Decl(name=obj.ident, quals=obj.quals, storage=obj.storage, funcspec=[], type=obj.ptr_decl, init=obj.init, bitsize=None) return obj
def __init__(self, struct_name: str, members: OrderedDict = None, storage: list = None): """ Initializes a new struct type. :param str struct_name: Type name of the struct. :param OrderedDict members: _MyriadBase-derived members of the struct :param list storage: List of C AST storage qualifiers (e.g. "const") :raises AssertionError: if members are not _MyriadBase subclassed """ # Make sure we got the right parameter types assert_list_type(list(members.values()), _MyriadBase) #: Struct type identifier, i.e. the name after 'struct' in C. self.struct_name = struct_name #: Ordered members of the struct, derived from _MyriadBase. self.members = OrderedDict() members = OrderedDict() if members is None else members # Store member type information for introspection. Non-ordered. self.member_type_info = {} for scalar in members.values(): self.member_type_info[scalar.ident] = scalar # Set struct members using ordered dict: order matters for memory! sorted_members = [members[idx].decl for idx in members.keys()] members = {v.ident: v.decl for v in members.values()} for member_ident, member in members.items(): self.members[member_ident] = member #: pycparser C AST struct node. self.struct_c_ast = Struct(self.struct_name, sorted_members) #: Programmatically-generated base type for run-time checking. self.base_type = type(self.struct_name, (MyriadCType, ), {'mtype': Struct(self.struct_name, None)})() # Manually build declaration to pass to super constructor _tmp_decl = Decl(name=None, quals=[], storage=[], funcspec=[], type=self.struct_c_ast, init=None, bitsize=None) super().__init__(None, _tmp_decl, storage=storage)
def make_decl(name, offset, type_name): nonlocal decls, pad_count, parser, prev_end if isinstance(offset, str): assert offset[:2] == '0x' offset = int(offset, 16) if prev_end < offset: pad_str = f"char _padding{pad_count}[{offset - prev_end}];" decls.append(parser.parse(pad_str).ext[0]) pad_count += 1 type_decl = TypeDecl(name.replace(".", "__"), None, IdentifierType([mangle_name(type_name)])) decls.append(Decl(None, None, None, None, type_decl, None, None)) req_graph.setdefault(type_name, set()).add(parent_name) if offset != -1: size = pointer_size if type_name.endswith('*') else int( types[type_name]['size'], 16) prev_end = offset + size
def __init__(self, ident: str, args_list: OrderedDict = None, ret_var: MyriadScalar = None, storage: list = None, fun_def=None): """ Initializes a new MyriadFunction. :param str ident: Name of the function to be created. :param args_list: Ordered dict of identifiers:_MyriadBase fxn args :type args_list: OrderedDict or None :param ret_var: Return value as a MyriadScalar :type ret_var: MyriadScalar or None :param storage: C AST storage qualifiers (e.g. "const") :type storage: list or None :param fun_def: Function definition in form of a string or template :raise AssertionError: if args_list has non-_MyriadBase members """ # Always call super first super().__init__(ident) # -------------------------------------------- # Set return value; none is given, assume void # -------------------------------------------- if ret_var is None: ret_var = MyriadScalar(self.ident, MVoid) #: Return value for the function as a MyriadScalar, default MVoid. self.ret_var = ret_var # -------------------------------------------- # Create internal representation of args list # -------------------------------------------- # Make sure we got the right parameter types if args_list is not None and len(args_list) > 0: assert_list_type(list(args_list.values()), _MyriadBase) #: Stores the MyriadScalars as ordered parameters. self.args_list = OrderedDict() if args_list is None else args_list #: Stores the scalar's declarations in a C AST object. self.param_list = ParamList([v.decl for v in self.args_list.values()]) # ------------------------------------------ # Create internal c_ast function declaration # ------------------------------------------ _tmp_decl = copy.deepcopy(self.ret_var.decl.type) # Make sure we override the identifier in our copy if isinstance(_tmp_decl, PtrDecl): _tmp_decl.type.declname = self.ident else: _tmp_decl.declname = self.ident #: C AST function declaration with parameter list and return type. self.func_decl = FuncDecl(self.param_list, _tmp_decl) self.decl = Decl(name=self.ident, quals=[], storage=storage, funcspec=[], type=self.func_decl, init=None, bitsize=None) #: C AST typedef, must be generated using gen_typedef. self.fun_typedef = None #: Typedef name defaults to ident + "_t" self.typedef_name = self.ident + "_t" #: Underlying MyriadCType for this function (based on typedef). self.base_type = None # Automaticall generate typedef depending on function type self.gen_typedef() #: Function definition represented as a string. self.fun_def = fun_def
def __init__(self, ident: str, base_type: MyriadCType, ptr: bool = False, quals: list = None, storage: list = None, arr_id: str = None, init=None): """ Initializes a scalar variable, i.e. a base type, a pointer type, or an array type containing the base scalar type (variable/fixed length). :param str ident: Name of the scalar variable to be created. :param MyriadCType base_type: Underlying C AST base type (e.g. MInt). :param bool ptr: Indicates whether this is a pointer. :param list quals: C AST scope qualifiers (e.g. "static") :param list storage: C AST storage qualifiers (e.g. "const") :param str arr_id: Array length ID specifier (None if this isn't one) :param init: Initial value given to this scalar # TODO: NOT IMPLEMENTED """ # Always call super first super().__init__(ident, quals=quals, storage=storage) #: Represents the underlying C type via a MyriadCType subclass. self.base_type = base_type #: Indicates if this is a pointer (or an array of pointers). self.ptr = ptr #: Indicates whether this is actually an array of this scalar type self.arr_id = arr_id #: Underlying C AST type declaration, used for C generation. self.type_decl = TypeDecl(declname=self.ident, quals=self.quals, type=self.base_type.mtype) #: Optional pointer declaration, used for scalar pointers. self.ptr_decl = PtrDecl(quals=[], type=self.type_decl) #: Optional array declaration, used for scalar arrays self.arr_decl = None if self.arr_id is not None: # Array of scalars or array of pointers (first arg is base type) self.arr_decl = ArrayDecl(self.ptr_decl if ptr else self.type_decl, dim=ID(name=self.arr_id), dim_quals=[]) # TODO: Process init in some way #: Initial value of this scalar at the C level. self.init = init if init is not None: warn("Setting init is deprecated", DeprecationWarning) # Override superclass and re-initialize internal top-level declaration # Order of choosing declaration: # 1. If it's an array declaration (aka arr_id isn't None), use that # 2. Otherwise: # a) If ptr is true, use the ptr declaration # b) Otherwise, use the regular type declaration if self.arr_id is None: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.ptr_decl if ptr else self.type_decl, init=self.init, bitsize=None) else: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.arr_decl, init=None, bitsize=None)
def visit_Decl(self, node: c_ast.Decl): logger.debug(f'Line {str(node.coord.line)}: {generate(node)}') # ignore the FuncDecl node since it's already preprocessed if isinstance(node.type, c_ast.FuncDecl): return # TODO - Enhancement: Array Declaration support elif not isinstance(node.type, c_ast.TypeDecl): raise NotImplementedError( f'Declaration type {node.type} currently not supported for statement: {generate(node)}' ) # if declarations are in function body, store distance into type system assert isinstance(node.type, c_ast.TypeDecl) # if no initial value is given, default to (0, 0) if not node.init: self._type_system.update_distance(node.name, '0', '0') # else update the distance to the distance of initial value (T-Asgn) elif isinstance( node.init, (c_ast.Constant, c_ast.BinaryOp, c_ast.BinaryOp, c_ast.UnaryOp)): self._assign(c_ast.ID(name=node.name), node.init, node) # if it is random variable declaration (T-Laplace) elif isinstance(node.init, c_ast.FuncCall): if self._enable_shadow and self._pc: raise ValueError( 'Cannot have random variable assignment in shadow-diverging branches' ) self._random_variables.add(node.name) logger.debug(f'Random variables: {self._random_variables}') # set the random variable distance self._type_system.update_distance(node.name, '*', '0') if self._enable_shadow: # since we have to dynamically switch (the aligned distances) to shadow version, we have to guard the # switch with the selector shadow_type_system = deepcopy(self._type_system) for name, _, shadow_distance, _, _ in shadow_type_system.variables( ): # skip the distance of custom holes if constants.HOLE in name: continue shadow_type_system.update_distance(name, shadow_distance, shadow_distance) self._type_system.merge(shadow_type_system) if self._loop_level == 0: to_inserts = [] if self._enable_shadow: # insert distance updates for normal variables distance_update_statements = [] for name, align, shadow, _, _ in self._type_system.variables( ): if align == '*' and name not in self._parameters and name != node.name: shadow_distance = f'{constants.SHADOW_DISTANCE}_{name}' if shadow == '*' else shadow distance_update_statements.append( parse( f'{constants.ALIGNED_DISTANCE}_{name} = {shadow_distance};' )) distance_update = c_ast.If(cond=parse( f'{constants.SELECTOR}_{node.name} == {constants.SELECT_SHADOW}' ), iftrue=c_ast.Compound( block_items= distance_update_statements), iffalse=None) to_inserts.append(distance_update) # insert distance template for the variable distance = parse( f'{constants.ALIGNED_DISTANCE}_{node.name} = {constants.RANDOM_DISTANCE}_{node.name}' ) to_inserts.append(distance) # insert cost variable update statement scale = generate(node.init.args.exprs[0]) cost = expr_simplify( f'(Abs({constants.ALIGNED_DISTANCE}_{node.name}) * (1 / ({scale})))' ) # calculate v_epsilon by combining normal cost and sampling cost if self._enable_shadow: previous_cost = \ f'(({constants.SELECTOR}_{node.name} == {constants.SELECT_ALIGNED}) ? {constants.V_EPSILON} : 0)' else: previous_cost = constants.V_EPSILON v_epsilon = parse( f'{constants.V_EPSILON} = {previous_cost} + {cost}') to_inserts.append(v_epsilon) # transform sampling command to havoc command node.init = parse( f'{constants.SAMPLE_ARRAY}[{constants.SAMPLE_INDEX}]') to_inserts.append( parse( f'{constants.SAMPLE_INDEX} = {constants.SAMPLE_INDEX} + 1;' )) self._insert_at(node, to_inserts) else: raise NotImplementedError( f'Initial value currently not supported: {node.init}') logger.debug(f'types: {self._type_system}')
def identify_nested(ast_tree): ast = ast_tree old_stdout = sys.stdout sys.stdout = mystdout = StringIO() aux_ast = duplicate_element(ast) list = [] extern_while = get_extern_while_body(aux_ast) identify_nested_algorithms_bodies(extern_while, list) labelname_inner = config.variables_2['round'] rounds_list_inner = config.rounds_list_2 delete_round_phase_inner = config.delete_round_phase message_inner = config.msg_structure_fields_2 variables_inner = config.variables_2 if list: list.reverse() labels = config.rounds_list_2 labels.append('ERR_ROUND') code = None cop = duplicate_element(ast) if len(list) >= config.number_of_nested_algorithms: extern = get_extern_while_body(cop) if isinstance(extern.block_items[0], If): myif = extern.block_items[0] list1 = [] list2 = [] aux1 = [] aux2 = [] identify_nested_algorithms_bodies(extern.block_items[0].iftrue, list1) if list1: sys.stdout = old_stdout for elem in list1: conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) aux1 = elem.stmt parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) identify_nested_algorithms_bodies( extern.block_items[0].iffalse, list2) if list2: for elem in list2: conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) aux2 = elem.stmt parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) if aux1 and aux2: myif.iftrue = None myif.iffalse = None myif.iftrue = aux1 myif.iffalse = aux2 trees_dict, trees_paths_dict, is_job = get_paths_trees( cop, labels, labels, config.variables_2['round']) print_rounds(labels, trees_dict, trees_paths_dict, config.variables_2['round'], is_job, delete_round_phase_inner, message_inner, variables_inner, rounds_list_inner[0]) code = mystdout.getvalue() sys.stdout = old_stdout return ast, code else: for elem in list: # print generator.visit(elem), "AAAAAAAAAAA" conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) # print generator.visit(elem) trees_dict, trees_paths_dict, is_job = get_paths_trees( elem.stmt, labels, labels, config.variables_2['round']) # print_code(trees_dict, trees_paths_dict, labels) print_rounds(labels, trees_dict, trees_paths_dict, config.variables_2['round'], is_job, delete_round_phase_inner, message_inner, variables_inner, rounds_list_inner[0]) parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) # print generator.visit(parent.block_items[index]) # print generator.visit(ast) # print generator.visit(func) funcdecl = FuncDecl( None, TypeDecl('inner_algorithm', None, IdentifierType(['int']))) decl = Decl('inner_algorithm', None, None, None, funcdecl, None, None) funcdef = FuncDef(decl, None, None) code = mystdout.getvalue() funcdef.body = Compound([code]) # print generator.visit(ast) sys.stdout = old_stdout return ast, code else: sys.stdout = old_stdout print "pe else" return ast_tree