# Copyright (C) 2014 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from common.logger import Logger from file_format.common import split_stream from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass import re class C1ParserState: OUTSIDE_BLOCK, INSIDE_COMPILATION_BLOCK, STARTING_CFG_BLOCK, INSIDE_CFG_BLOCK = range(4) def __init__(self): self.current_state = C1ParserState.OUTSIDE_BLOCK self.last_method_name = None def _parse_c1_line(c1_file, line, line_no, state, filename): """ This function is invoked on each line of the output file and returns a triplet which instructs the parser how the line should be handled. If the line is to be included in the current group, it is returned in the first value. If the line starts a new output group, the name of the group is returned in the second value. The third value is only here to make the function prototype compatible with `SplitStream` and is always set to `None` here. """ if state.current_state == C1ParserState.STARTING_CFG_BLOCK: # Previous line started a new 'cfg' block which means that this one must # contain the name of the pass (this is enforced by C1visualizer). if re.match(r'name\s+"[^"]+"', line): # Extract the pass name, prepend it with the name of the method and # return as the beginning of a new group. state.current_state = C1ParserState.INSIDE_CFG_BLOCK return None, state.last_method_name + " " + line.split('"')[1], None else: Logger.fail("Expected output group name", filename, line_no) elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK: if line == "end_cfg": state.current_state = C1ParserState.OUTSIDE_BLOCK return None, None, None else: return line, None, None elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK: # Search for the method's name. Format: method "" if re.match(r'method\s+"[^"]*"', line): method_name = line.split('"')[1].strip() if not method_name: Logger.fail("Empty method name in output", filename, line_no) match = re.search(r"isa_features:([\w,-]+)", method_name) if match: raw_features = match.group(1).split(",") # Create a map of features in the form {feature_name: is_enabled}. features = {} for rf in raw_features: feature_name = rf is_enabled = True # A '-' in front of the feature name indicates that the feature wasn't enabled at compile # time. if rf[0] == "-": feature_name = rf[1:] is_enabled = False features[feature_name] = is_enabled c1_file.set_isa_features(features) # Check what type of read barrier is used match = re.search(r"read_barrier_type:(\w+)", method_name) if match: c1_file.set_read_barrier_type(match.group(1)) else: state.last_method_name = method_name elif line == "end_compilation": state.current_state = C1ParserState.OUTSIDE_BLOCK return None, None, None else: assert state.current_state == C1ParserState.OUTSIDE_BLOCK if line == "begin_cfg": # The line starts a new group but we'll wait until the next line from # which we can extract the name of the pass. if state.last_method_name is None: Logger.fail("Expected method header", filename, line_no) state.current_state = C1ParserState.STARTING_CFG_BLOCK return None, None, None elif line == "begin_compilation": state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK return None, None, None else: Logger.fail("C1visualizer line not inside a group", filename, line_no) def parse_c1_visualizer_stream(filename, stream): c1_file = C1visualizerFile(filename) state = C1ParserState() def fn_process_line(line, line_no): return _parse_c1_line(c1_file, line, line_no, state, c1_file.base_file_name) def fn_line_outside_chunk(line, line_no): Logger.fail("C1visualizer line not inside a group", c1_file.base_file_name, line_no) for pass_name, pass_lines, start_line_no, test_arch in split_stream(stream, fn_process_line, fn_line_outside_chunk): C1visualizerPass(c1_file, pass_name, pass_lines, start_line_no + 1) return c1_file