1# Copyright (C) 2014 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from common.logger import Logger 16from file_format.common import split_stream 17from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass 18 19import re 20 21 22class C1ParserState: 23 OUTSIDE_BLOCK, INSIDE_COMPILATION_BLOCK, STARTING_CFG_BLOCK, INSIDE_CFG_BLOCK = range(4) 24 25 def __init__(self): 26 self.current_state = C1ParserState.OUTSIDE_BLOCK 27 self.last_method_name = None 28 29 30def _parse_c1_line(c1_file, line, line_no, state, filename): 31 """ This function is invoked on each line of the output file and returns 32 a triplet which instructs the parser how the line should be handled. If the 33 line is to be included in the current group, it is returned in the first 34 value. If the line starts a new output group, the name of the group is 35 returned in the second value. The third value is only here to make the 36 function prototype compatible with `SplitStream` and is always set to 37 `None` here. 38 """ 39 if state.current_state == C1ParserState.STARTING_CFG_BLOCK: 40 # Previous line started a new 'cfg' block which means that this one must 41 # contain the name of the pass (this is enforced by C1visualizer). 42 if re.match(r'name\s+"[^"]+"', line): 43 # Extract the pass name, prepend it with the name of the method and 44 # return as the beginning of a new group. 45 state.current_state = C1ParserState.INSIDE_CFG_BLOCK 46 return None, state.last_method_name + " " + line.split('"')[1], None 47 else: 48 Logger.fail("Expected output group name", filename, line_no) 49 50 elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK: 51 if line == "end_cfg": 52 state.current_state = C1ParserState.OUTSIDE_BLOCK 53 return None, None, None 54 else: 55 return line, None, None 56 57 elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK: 58 # Search for the method's name. Format: method "<name>" 59 if re.match(r'method\s+"[^"]*"', line): 60 method_name = line.split('"')[1].strip() 61 if not method_name: 62 Logger.fail("Empty method name in output", filename, line_no) 63 64 match = re.search(r"isa_features:([\w,-]+)", method_name) 65 if match: 66 raw_features = match.group(1).split(",") 67 # Create a map of features in the form {feature_name: is_enabled}. 68 features = {} 69 for rf in raw_features: 70 feature_name = rf 71 is_enabled = True 72 # A '-' in front of the feature name indicates that the feature wasn't enabled at compile 73 # time. 74 if rf[0] == "-": 75 feature_name = rf[1:] 76 is_enabled = False 77 features[feature_name] = is_enabled 78 79 c1_file.set_isa_features(features) 80 81 # Check what type of read barrier is used 82 match = re.search(r"read_barrier_type:(\w+)", method_name) 83 if match: 84 c1_file.set_read_barrier_type(match.group(1)) 85 86 else: 87 state.last_method_name = method_name 88 elif line == "end_compilation": 89 state.current_state = C1ParserState.OUTSIDE_BLOCK 90 return None, None, None 91 92 else: 93 assert state.current_state == C1ParserState.OUTSIDE_BLOCK 94 if line == "begin_cfg": 95 # The line starts a new group but we'll wait until the next line from 96 # which we can extract the name of the pass. 97 if state.last_method_name is None: 98 Logger.fail("Expected method header", filename, line_no) 99 state.current_state = C1ParserState.STARTING_CFG_BLOCK 100 return None, None, None 101 elif line == "begin_compilation": 102 state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK 103 return None, None, None 104 else: 105 Logger.fail("C1visualizer line not inside a group", filename, line_no) 106 107 108def parse_c1_visualizer_stream(filename, stream): 109 c1_file = C1visualizerFile(filename) 110 state = C1ParserState() 111 112 def fn_process_line(line, line_no): 113 return _parse_c1_line(c1_file, line, line_no, state, c1_file.base_file_name) 114 115 def fn_line_outside_chunk(line, line_no): 116 Logger.fail("C1visualizer line not inside a group", c1_file.base_file_name, line_no) 117 118 for pass_name, pass_lines, start_line_no, test_arch in split_stream(stream, fn_process_line, 119 fn_line_outside_chunk): 120 C1visualizerPass(c1_file, pass_name, pass_lines, start_line_no + 1) 121 return c1_file 122