blob: 55efbd74eaa120abba9b5057b234adb7c6c22cb5 [file] [log] [blame]
David Brazdil2c27f2c2015-05-12 18:06:38 +01001# 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
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000015from common.logger import Logger
16from file_format.common import split_stream
David Brazdil2c27f2c2015-05-12 18:06:38 +010017from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
18
19import re
20
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000021
David Brazdil2c27f2c2015-05-12 18:06:38 +010022class C1ParserState:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000023 OUTSIDE_BLOCK, INSIDE_COMPILATION_BLOCK, STARTING_CFG_BLOCK, INSIDE_CFG_BLOCK = range(4)
David Brazdil2c27f2c2015-05-12 18:06:38 +010024
25 def __init__(self):
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000026 self.current_state = C1ParserState.OUTSIDE_BLOCK
27 self.last_method_name = None
David Brazdil2c27f2c2015-05-12 18:06:38 +010028
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000029
30def _parse_c1_line(c1_file, line, line_no, state, filename):
David Brazdil2c27f2c2015-05-12 18:06:38 +010031 """ This function is invoked on each line of the output file and returns
Alexandre Rames5e2c8d32015-08-06 14:49:28 +010032 a triplet which instructs the parser how the line should be handled. If the
David Brazdil2c27f2c2015-05-12 18:06:38 +010033 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
Alexandre Rames5e2c8d32015-08-06 14:49:28 +010035 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.
David Brazdil2c27f2c2015-05-12 18:06:38 +010038 """
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000039 if state.current_state == C1ParserState.STARTING_CFG_BLOCK:
David Brazdil2c27f2c2015-05-12 18:06:38 +010040 # 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).
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000042 if re.match(r'name\s+"[^"]+"', line):
David Brazdil2c27f2c2015-05-12 18:06:38 +010043 # Extract the pass name, prepend it with the name of the method and
44 # return as the beginning of a new group.
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000045 state.current_state = C1ParserState.INSIDE_CFG_BLOCK
46 return None, state.last_method_name + " " + line.split('"')[1], None
David Brazdil2c27f2c2015-05-12 18:06:38 +010047 else:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000048 Logger.fail("Expected output group name", filename, line_no)
David Brazdil2c27f2c2015-05-12 18:06:38 +010049
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000050 elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK:
David Brazdil2c27f2c2015-05-12 18:06:38 +010051 if line == "end_cfg":
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000052 state.current_state = C1ParserState.OUTSIDE_BLOCK
53 return None, None, None
David Brazdil2c27f2c2015-05-12 18:06:38 +010054 else:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000055 return line, None, None
David Brazdil2c27f2c2015-05-12 18:06:38 +010056
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000057 elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK:
David Brazdil2c27f2c2015-05-12 18:06:38 +010058 # Search for the method's name. Format: method "<name>"
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000059 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)
Fabio Rinaldi40b06142020-02-12 16:18:50 +000063
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000064 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}.
Fabio Rinaldi40b06142020-02-12 16:18:50 +000068 features = {}
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000069 for rf in raw_features:
70 feature_name = rf
71 is_enabled = True
Fabio Rinaldi40b06142020-02-12 16:18:50 +000072 # A '-' in front of the feature name indicates that the feature wasn't enabled at compile
73 # time.
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000074 if rf[0] == "-":
75 feature_name = rf[1:]
76 is_enabled = False
77 features[feature_name] = is_enabled
Fabio Rinaldi40b06142020-02-12 16:18:50 +000078
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000079 c1_file.set_isa_features(features)
Fabio Rinaldi40b06142020-02-12 16:18:50 +000080 else:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000081 state.last_method_name = method_name
David Brazdil2c27f2c2015-05-12 18:06:38 +010082 elif line == "end_compilation":
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000083 state.current_state = C1ParserState.OUTSIDE_BLOCK
84 return None, None, None
David Brazdil2c27f2c2015-05-12 18:06:38 +010085
86 else:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000087 assert state.current_state == C1ParserState.OUTSIDE_BLOCK
David Brazdil2c27f2c2015-05-12 18:06:38 +010088 if line == "begin_cfg":
89 # The line starts a new group but we'll wait until the next line from
90 # which we can extract the name of the pass.
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000091 if state.last_method_name is None:
92 Logger.fail("Expected method header", filename, line_no)
93 state.current_state = C1ParserState.STARTING_CFG_BLOCK
94 return None, None, None
David Brazdil2c27f2c2015-05-12 18:06:38 +010095 elif line == "begin_compilation":
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000096 state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK
97 return None, None, None
David Brazdil2c27f2c2015-05-12 18:06:38 +010098 else:
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +000099 Logger.fail("C1visualizer line not inside a group", filename, line_no)
David Brazdil2c27f2c2015-05-12 18:06:38 +0100100
Daniil Riazanovskiybfe8fc82020-10-05 15:07:15 +0000101
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +0000102def parse_c1_visualizer_stream(filename, stream):
103 c1_file = C1visualizerFile(filename)
David Brazdil2c27f2c2015-05-12 18:06:38 +0100104 state = C1ParserState()
Daniil Riazanovskiybfe8fc82020-10-05 15:07:15 +0000105
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +0000106 def fn_process_line(line, line_no):
107 return _parse_c1_line(c1_file, line, line_no, state, c1_file.base_file_name)
Daniil Riazanovskiybfe8fc82020-10-05 15:07:15 +0000108
Daniil Riazanovskiy4a128a12020-10-15 00:46:06 +0000109 def fn_line_outside_chunk(line, line_no):
110 Logger.fail("C1visualizer line not inside a group", c1_file.base_file_name, line_no)
111
112 for pass_name, pass_lines, start_line_no, test_arch in split_stream(stream, fn_process_line,
113 fn_line_outside_chunk):
114 C1visualizerPass(c1_file, pass_name, pass_lines, start_line_no + 1)
115 return c1_file