| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 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 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 15 | from common.logger import Logger |
| 16 | from file_format.common import split_stream |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 17 | from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass |
| 18 | |
| 19 | import re |
| 20 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 21 | |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 22 | class C1ParserState: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 23 | OUTSIDE_BLOCK, INSIDE_COMPILATION_BLOCK, STARTING_CFG_BLOCK, INSIDE_CFG_BLOCK = range(4) |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 24 | |
| 25 | def __init__(self): |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 26 | self.current_state = C1ParserState.OUTSIDE_BLOCK |
| 27 | self.last_method_name = None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 28 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 29 | |
| 30 | def _parse_c1_line(c1_file, line, line_no, state, filename): |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 31 | """ This function is invoked on each line of the output file and returns |
| Alexandre Rames | 5e2c8d3 | 2015-08-06 14:49:28 +0100 | [diff] [blame] | 32 | a triplet which instructs the parser how the line should be handled. If the |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 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 |
| Alexandre Rames | 5e2c8d3 | 2015-08-06 14:49:28 +0100 | [diff] [blame] | 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. |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 38 | """ |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 39 | if state.current_state == C1ParserState.STARTING_CFG_BLOCK: |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 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). |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 42 | if re.match(r'name\s+"[^"]+"', line): |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 43 | # Extract the pass name, prepend it with the name of the method and |
| 44 | # return as the beginning of a new group. |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 45 | state.current_state = C1ParserState.INSIDE_CFG_BLOCK |
| 46 | return None, state.last_method_name + " " + line.split('"')[1], None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 47 | else: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 48 | Logger.fail("Expected output group name", filename, line_no) |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 49 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 50 | elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK: |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 51 | if line == "end_cfg": |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 52 | state.current_state = C1ParserState.OUTSIDE_BLOCK |
| 53 | return None, None, None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 54 | else: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 55 | return line, None, None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 56 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 57 | elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK: |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 58 | # Search for the method's name. Format: method "<name>" |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 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) |
| Fabio Rinaldi | 40b0614 | 2020-02-12 16:18:50 +0000 | [diff] [blame] | 63 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 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}. |
| Fabio Rinaldi | 40b0614 | 2020-02-12 16:18:50 +0000 | [diff] [blame] | 68 | features = {} |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 69 | for rf in raw_features: |
| 70 | feature_name = rf |
| 71 | is_enabled = True |
| Fabio Rinaldi | 40b0614 | 2020-02-12 16:18:50 +0000 | [diff] [blame] | 72 | # A '-' in front of the feature name indicates that the feature wasn't enabled at compile |
| 73 | # time. |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 74 | if rf[0] == "-": |
| 75 | feature_name = rf[1:] |
| 76 | is_enabled = False |
| 77 | features[feature_name] = is_enabled |
| Fabio Rinaldi | 40b0614 | 2020-02-12 16:18:50 +0000 | [diff] [blame] | 78 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 79 | c1_file.set_isa_features(features) |
| Fabio Rinaldi | 40b0614 | 2020-02-12 16:18:50 +0000 | [diff] [blame] | 80 | else: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 81 | state.last_method_name = method_name |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 82 | elif line == "end_compilation": |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 83 | state.current_state = C1ParserState.OUTSIDE_BLOCK |
| 84 | return None, None, None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 85 | |
| 86 | else: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 87 | assert state.current_state == C1ParserState.OUTSIDE_BLOCK |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 88 | 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 Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 91 | 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 Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 95 | elif line == "begin_compilation": |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 96 | state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK |
| 97 | return None, None, None |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 98 | else: |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 99 | Logger.fail("C1visualizer line not inside a group", filename, line_no) |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 100 | |
| Daniil Riazanovskiy | bfe8fc8 | 2020-10-05 15:07:15 +0000 | [diff] [blame] | 101 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 102 | def parse_c1_visualizer_stream(filename, stream): |
| 103 | c1_file = C1visualizerFile(filename) |
| David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 104 | state = C1ParserState() |
| Daniil Riazanovskiy | bfe8fc8 | 2020-10-05 15:07:15 +0000 | [diff] [blame] | 105 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 106 | def fn_process_line(line, line_no): |
| 107 | return _parse_c1_line(c1_file, line, line_no, state, c1_file.base_file_name) |
| Daniil Riazanovskiy | bfe8fc8 | 2020-10-05 15:07:15 +0000 | [diff] [blame] | 108 | |
| Daniil Riazanovskiy | 4a128a1 | 2020-10-15 00:46:06 +0000 | [diff] [blame] | 109 | 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 |