#!/usr/bin/env python # viewcfg - A script for viewing the CFG of SIL and LLVM IR -*- python -*- # # This source file is part of the Swift.org open source project # # Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors # # ---------------------------------------------------------------------------- # # For vim users: use the following lines in .vimrc... # # com! -nargs=? Funccfg silent ?{$?,/^}/w !viewcfg # com! -range -nargs=? Viewcfg silent ,w !viewcfg # # ...to add these commands: # # :Funccfg displays the CFG of the current SIL/LLVM function. # :Viewcfg displays the sub-CFG of the selected range. # # Note: viewcfg should be in the $PATH and .dot files should be associated # with the Graphviz app. # # ---------------------------------------------------------------------------- from __future__ import print_function import re import subprocess import sys import tempfile def help(): print("""\ Usage: viewcfg [output-suffix] < file By default all CFGs are opened in the same window. Use the a unique output-suffix to open a CFG in a new window. """) class Block(object): current_index = 0 def __init__(self, name, preds): self.name = name self.content = None self.last_line_content = None self.preds = [] self.succs = None self.last_line = None self.index = Block.current_index Block.current_index += 1 if preds is not None: for pred in re.split("[, %]", preds): can_pred = pred.strip() if can_pred: self.preds.append(can_pred) def add_line(self, text): if self.content is None: self.content = "" escaped_text = re.sub(r'([\\<>{}"|])', r'\\\1', text[0:80]).rstrip() self.content += escaped_text + '\\l' self.last_line = text def get_succs(self): if self.succs is None: self.succs = [] if self.last_line is not None: for match in re.finditer(r'\bbb[0-9]+\b', self.last_line): self.succs.append(match.group()) for match in re.finditer(r'\blabel %(\S+)\b', self.last_line): self.succs.append(match.group(1)) return self.succs def main(): suffix = "" if len(sys.argv) >= 2: if sys.argv[1].startswith('-'): help() return suffix = sys.argv[1] blocks = {} cur_block = None sil_block_pattern = re.compile(r'^(\S+)(\(.*\))?: *(\/\/ *Preds:(.*))?$') llvm_block_pattern1 = re.compile(r'^(\S+): *; *preds =(.*)?$') llvm_block_pattern2 = re.compile(r'^;