1b1994897Sopenharmony_ci#!/usr/bin/env python3 2b1994897Sopenharmony_ci# -- coding: utf-8 -- 3b1994897Sopenharmony_ci# Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. 4b1994897Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 5b1994897Sopenharmony_ci# you may not use this file except in compliance with the License. 6b1994897Sopenharmony_ci# You may obtain a copy of the License at 7b1994897Sopenharmony_ci# 8b1994897Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 9b1994897Sopenharmony_ci# 10b1994897Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 11b1994897Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 12b1994897Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b1994897Sopenharmony_ci# See the License for the specific language governing permissions and 14b1994897Sopenharmony_ci# limitations under the License. 15b1994897Sopenharmony_ci# 16b1994897Sopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd. 17b1994897Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 18b1994897Sopenharmony_ci# you may not use this file except in compliance with the License. 19b1994897Sopenharmony_ci# You may obtain a copy of the License at 20b1994897Sopenharmony_ci# 21b1994897Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 22b1994897Sopenharmony_ci# 23b1994897Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 24b1994897Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 25b1994897Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26b1994897Sopenharmony_ci# See the License for the specific language governing permissions and 27b1994897Sopenharmony_ci# limitations under the License. 28b1994897Sopenharmony_ci 29b1994897Sopenharmony_cifrom typing import List 30b1994897Sopenharmony_ciimport graphviz as gv 31b1994897Sopenharmony_ciimport sys 32b1994897Sopenharmony_ciimport os 33b1994897Sopenharmony_ciimport argparse 34b1994897Sopenharmony_ci 35b1994897Sopenharmony_ci 36b1994897Sopenharmony_ciclass BasicBlock: 37b1994897Sopenharmony_ci def __init__(self, ident: int) -> None: 38b1994897Sopenharmony_ci self.id = ident 39b1994897Sopenharmony_ci self.insts = [] 40b1994897Sopenharmony_ci self.preds = [] 41b1994897Sopenharmony_ci self.succs = [] 42b1994897Sopenharmony_ci self.props = [] 43b1994897Sopenharmony_ci 44b1994897Sopenharmony_ci def text(self, no_insts=False) -> str: 45b1994897Sopenharmony_ci s = 'BB ' + str(self.id) + '\n' 46b1994897Sopenharmony_ci s += 'props: ' 47b1994897Sopenharmony_ci for i, prop in enumerate(self.props): 48b1994897Sopenharmony_ci if i > 0: 49b1994897Sopenharmony_ci s += ', ' 50b1994897Sopenharmony_ci s += prop 51b1994897Sopenharmony_ci s += '\n' 52b1994897Sopenharmony_ci 53b1994897Sopenharmony_ci if not no_insts: 54b1994897Sopenharmony_ci for inst in self.insts: 55b1994897Sopenharmony_ci s += inst + '\n' 56b1994897Sopenharmony_ci return s 57b1994897Sopenharmony_ci 58b1994897Sopenharmony_ci 59b1994897Sopenharmony_ciclass Function: 60b1994897Sopenharmony_ci def __init__(self, method: str, blocks: List[BasicBlock]) -> None: 61b1994897Sopenharmony_ci self.method = method 62b1994897Sopenharmony_ci self.blocks = blocks 63b1994897Sopenharmony_ci 64b1994897Sopenharmony_ci 65b1994897Sopenharmony_ciclass GraphDumpParser: 66b1994897Sopenharmony_ci def __init__(self) -> None: 67b1994897Sopenharmony_ci self.method = None 68b1994897Sopenharmony_ci self.block = None 69b1994897Sopenharmony_ci self.blocks = [] 70b1994897Sopenharmony_ci self.functions = [] 71b1994897Sopenharmony_ci 72b1994897Sopenharmony_ci def finish_block(self): 73b1994897Sopenharmony_ci if self.block: 74b1994897Sopenharmony_ci self.blocks.append(self.block) 75b1994897Sopenharmony_ci self.block = None 76b1994897Sopenharmony_ci 77b1994897Sopenharmony_ci def finish_function(self): 78b1994897Sopenharmony_ci self.finish_block() 79b1994897Sopenharmony_ci if self.method: 80b1994897Sopenharmony_ci self.functions.append(Function(self.method, self.blocks)) 81b1994897Sopenharmony_ci self.blocks = [] 82b1994897Sopenharmony_ci 83b1994897Sopenharmony_ci def begin_block(self, line: str): 84b1994897Sopenharmony_ci self.finish_block() 85b1994897Sopenharmony_ci 86b1994897Sopenharmony_ci preds_start = line.find('preds:') 87b1994897Sopenharmony_ci block_id = int(line[len('BB'):preds_start].strip()) 88b1994897Sopenharmony_ci self.block = BasicBlock(block_id) 89b1994897Sopenharmony_ci if preds_start != -1: 90b1994897Sopenharmony_ci self.parse_block_preds(line, preds_start) 91b1994897Sopenharmony_ci 92b1994897Sopenharmony_ci def begin_function(self, line: str): 93b1994897Sopenharmony_ci self.finish_function() 94b1994897Sopenharmony_ci self.method = line[len('method:'):].strip() 95b1994897Sopenharmony_ci 96b1994897Sopenharmony_ci def parse_block_preds(self, line: str, preds_start: int): 97b1994897Sopenharmony_ci preds = line[preds_start+len('preds:'):].strip().strip('[]') 98b1994897Sopenharmony_ci for pred in preds.split(','): 99b1994897Sopenharmony_ci pred = pred.strip() 100b1994897Sopenharmony_ci self.block.preds.append(int(pred[len('bb'):].strip())) 101b1994897Sopenharmony_ci 102b1994897Sopenharmony_ci def parse_block_props(self, line: str): 103b1994897Sopenharmony_ci for s in line[len('prop:'):].strip().split(','): 104b1994897Sopenharmony_ci s = s.strip() 105b1994897Sopenharmony_ci if not s.startswith('bc'): 106b1994897Sopenharmony_ci self.block.props.append(s) 107b1994897Sopenharmony_ci 108b1994897Sopenharmony_ci def parse_block_succs(self, line: str): 109b1994897Sopenharmony_ci succs = line[len('succs:'):].strip().strip('[]') 110b1994897Sopenharmony_ci for succ in succs.split(','): 111b1994897Sopenharmony_ci succ = succ.strip() 112b1994897Sopenharmony_ci self.block.succs.append(int(succ[len('bb'):].strip())) 113b1994897Sopenharmony_ci self.finish_block() 114b1994897Sopenharmony_ci 115b1994897Sopenharmony_ci def parse(self, lines: List[str]) -> List[Function]: 116b1994897Sopenharmony_ci for line in lines: 117b1994897Sopenharmony_ci if line.startswith('Method:'): 118b1994897Sopenharmony_ci self.begin_function(line) 119b1994897Sopenharmony_ci elif line.startswith('BB'): 120b1994897Sopenharmony_ci self.begin_block(line) 121b1994897Sopenharmony_ci elif self.block: 122b1994897Sopenharmony_ci if line.startswith('prop:'): 123b1994897Sopenharmony_ci self.parse_block_props(line) 124b1994897Sopenharmony_ci elif line.startswith('succs:'): 125b1994897Sopenharmony_ci self.parse_block_succs(line) 126b1994897Sopenharmony_ci else: 127b1994897Sopenharmony_ci self.block.insts.append(line) 128b1994897Sopenharmony_ci self.finish_function() 129b1994897Sopenharmony_ci return self.functions 130b1994897Sopenharmony_ci 131b1994897Sopenharmony_ci 132b1994897Sopenharmony_cidef draw_function(function: Function, out_dir=None, no_insts=False): 133b1994897Sopenharmony_ci dot = gv.Digraph(format='png') 134b1994897Sopenharmony_ci for block in function.blocks: 135b1994897Sopenharmony_ci dot.node(str(block.id), block.text(no_insts), shape='box') 136b1994897Sopenharmony_ci for block in function.blocks: 137b1994897Sopenharmony_ci for succ in block.succs: 138b1994897Sopenharmony_ci dot.edge(str(block.id), str(succ)) 139b1994897Sopenharmony_ci basename = 'cfg_' + function.method 140b1994897Sopenharmony_ci dotfile_path = os.path.join(out_dir, basename) 141b1994897Sopenharmony_ci dot.render(basename, out_dir, format="png") 142b1994897Sopenharmony_ci os.rename(dotfile_path, dotfile_path + '.dot') 143b1994897Sopenharmony_ci 144b1994897Sopenharmony_ci 145b1994897Sopenharmony_cidef main(): 146b1994897Sopenharmony_ci parser = argparse.ArgumentParser(description="A tool for drawing CFGs by reading ir dump from stdin") 147b1994897Sopenharmony_ci parser.add_argument("--no-insts", action="store_true", help="drawing without ir instructions") 148b1994897Sopenharmony_ci parser.add_argument("--out", type=str, default="./out", help="output directory, default to './out'") 149b1994897Sopenharmony_ci args = parser.parse_args() 150b1994897Sopenharmony_ci 151b1994897Sopenharmony_ci functions = GraphDumpParser().parse(sys.stdin.readlines()) 152b1994897Sopenharmony_ci for function in functions: 153b1994897Sopenharmony_ci draw_function(function, args.out, no_insts=args.no_insts) 154b1994897Sopenharmony_ci 155b1994897Sopenharmony_ci 156b1994897Sopenharmony_ciif __name__ == "__main__": 157b1994897Sopenharmony_ci main() 158