def Canonicalize(ast: c_ast.FileAST, meta_info: meta.MetaInfo, skip_constant_casts): global_id_gen = common.UniqueId() for node in ast: if isinstance(node, c_ast.FuncDef): CanonicalizeFun(node, meta_info) meta_info.CheckConsistency(ast) transform_arrayref.ConvertConvertAddressTakenScalarsToArray(ast, meta_info) meta_info.CheckConsistency(ast) transform_arrayref.ConvertArrayIndexToPointerDereference(ast, meta_info) transform_arrayref.SimplifyAddressExpressions(ast, meta_info) meta_info.CheckConsistency(ast) ConvertCompoundAssignment(ast, meta_info, global_id_gen) # This should go last so that we do not have worry to mess this # up in other phases. AddExplicitCasts(ast, ast, meta_info, skip_constant_casts) transform_rename.LiftStaticAndExternToGlobalScope(ast, meta_info, global_id_gen) meta_info.CheckConsistency(ast) ConfirmAbsenceOfUnsupportedFeatures(ast, ast)
def ConvertConvertAddressTakenScalarsToArray(ast, meta_info: meta.MetaInfo): """ Rewrite address taken scalar vars as one element arrays After this transform we can keep all scalars in registers. """ def IsAddressTakenScalarOrGlobalScalar(node, parent): if isinstance(node, c_ast.Decl) and IsScalarType(node.type): # return isinstance(parent, c_ast.FileAST) return (isinstance(parent, c_ast.FileAST) or "static" in node.storage) if not isinstance(node, c_ast.UnaryOp): return False if node.op != "&": return False if not isinstance(node.expr, c_ast.ID): return False type = meta_info.type_links[node.expr] return IsScalarType(type) candidates = common.FindMatchingNodesPreOrder(ast, ast, IsAddressTakenScalarOrGlobalScalar) ids = set() for node, _ in candidates: if isinstance(node, c_ast.UnaryOp): ids.add(meta_info.sym_links[node.expr]) else: ids.add(node) one = c_ast.Constant("int", "1") meta_info.type_links[one] = meta.INT_IDENTIFIER_TYPE for node in ids: assert isinstance(node, c_ast.Decl) node.type = c_ast.ArrayDecl(node.type, one, []) if node.init: node.init = c_ast.InitList([node.init]) def IsAddressTakenScalarId(node, _): return isinstance(node, c_ast.ID) and meta_info.sym_links[node] in ids candidates = common.FindMatchingNodesPreOrder(ast, ast, IsAddressTakenScalarId) for node, parent in candidates: original_type = meta_info.type_links[node] meta_info.type_links[node] = meta.GetTypeForDecl(meta_info.sym_links[node].type) array_ref = c_ast.UnaryOp("*", node) meta_info.type_links[array_ref] = original_type common.ReplaceNode(parent, node, array_ref)
def ConvertCompoundAssignment(ast: c_ast.Node, meta_info: meta.MetaInfo, _id_gen): """This works best after ConvertArrayIndexToPointerDereference""" candidates = common.FindMatchingNodesPostOrder(ast, ast, lambda n, _: isinstance(n, c_ast.Assignment)) for assign, parent in candidates: if assign.op == "=": continue lvalue = assign.lvalue if isinstance(lvalue, c_ast.ID): node = c_ast.BinaryOp(assign.op[:-1], lvalue, assign.rvalue) meta_info.type_links[node] = meta_info.type_links[assign] assign.rvalue = node assign.op = "=" elif isinstance(lvalue, c_ast.UnaryOp) and lvalue.op == "*": # TODO pass
def CanonicalizeFun(ast: c_ast.FuncDef, meta_info: meta.MetaInfo): id_gen = common.UniqueId() ConvertPostToPreIncDec(ast) meta_info.CheckConsistency(ast) ConvertPreIncDecToCompoundAssignment(ast, meta_info) meta_info.CheckConsistency(ast) ConvertWhileLoop(ast, id_gen) ConvertForLoop(ast, id_gen) meta_info.CheckConsistency(ast) EliminateExpressionLists(ast) transform_if.IfTransform(ast, id_gen) transform_if.ShortCircuitIfTransform(ast, id_gen) meta_info.CheckConsistency(ast) transform_label.PruneUselessLabels(ast) transform_rename.UniquifyLocalVars(ast, meta_info, id_gen) FixNodeRequiringBoolInt(ast, meta_info) meta_info.CheckConsistency(ast) # if return type is void decl: c_ast.FuncDecl = ast.decl type_decl: c_ast.TypeDecl = decl.type.type if not isinstance(type_decl.type, c_ast.IdentifierType): return if "void" not in type_decl.type.names: return if ast.body.block_items is None: ast.body.block_items = [] stmts = ast.body.block_items if not stmts or not isinstance(stmts[-1], c_ast.Return): ret = c_ast.Return(None) meta_info.type_links[ret] = meta.GetTypeForDecl(ast.decl.type) stmts.append(ret)