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 | |
| 15 | from common.logger import Logger |
| 16 | from file_format.common import SplitStream |
| 17 | from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass |
| 18 | |
| 19 | import re |
| 20 | |
| 21 | class C1ParserState: |
| 22 | OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4) |
| 23 | |
| 24 | def __init__(self): |
| 25 | self.currentState = C1ParserState.OutsideBlock |
| 26 | self.lastMethodName = None |
| 27 | |
| 28 | def __parseC1Line(line, lineNo, state, fileName): |
| 29 | """ This function is invoked on each line of the output file and returns |
| 30 | a pair which instructs the parser how the line should be handled. If the |
| 31 | line is to be included in the current group, it is returned in the first |
| 32 | value. If the line starts a new output group, the name of the group is |
| 33 | returned in the second value. |
| 34 | """ |
| 35 | if state.currentState == C1ParserState.StartingCfgBlock: |
| 36 | # Previous line started a new 'cfg' block which means that this one must |
| 37 | # contain the name of the pass (this is enforced by C1visualizer). |
| 38 | if re.match("name\s+\"[^\"]+\"", line): |
| 39 | # Extract the pass name, prepend it with the name of the method and |
| 40 | # return as the beginning of a new group. |
| 41 | state.currentState = C1ParserState.InsideCfgBlock |
| 42 | return (None, state.lastMethodName + " " + line.split("\"")[1]) |
| 43 | else: |
| 44 | Logger.fail("Expected output group name", fileName, lineNo) |
| 45 | |
| 46 | elif state.currentState == C1ParserState.InsideCfgBlock: |
| 47 | if line == "end_cfg": |
| 48 | state.currentState = C1ParserState.OutsideBlock |
| 49 | return (None, None) |
| 50 | else: |
| 51 | return (line, None) |
| 52 | |
| 53 | elif state.currentState == C1ParserState.InsideCompilationBlock: |
| 54 | # Search for the method's name. Format: method "<name>" |
| 55 | if re.match("method\s+\"[^\"]*\"", line): |
| 56 | methodName = line.split("\"")[1].strip() |
| 57 | if not methodName: |
| 58 | Logger.fail("Empty method name in output", fileName, lineNo) |
| 59 | state.lastMethodName = methodName |
| 60 | elif line == "end_compilation": |
| 61 | state.currentState = C1ParserState.OutsideBlock |
| 62 | return (None, None) |
| 63 | |
| 64 | else: |
| 65 | assert state.currentState == C1ParserState.OutsideBlock |
| 66 | if line == "begin_cfg": |
| 67 | # The line starts a new group but we'll wait until the next line from |
| 68 | # which we can extract the name of the pass. |
| 69 | if state.lastMethodName is None: |
| 70 | Logger.fail("Expected method header", fileName, lineNo) |
| 71 | state.currentState = C1ParserState.StartingCfgBlock |
| 72 | return (None, None) |
| 73 | elif line == "begin_compilation": |
| 74 | state.currentState = C1ParserState.InsideCompilationBlock |
| 75 | return (None, None) |
| 76 | else: |
| 77 | Logger.fail("C1visualizer line not inside a group", fileName, lineNo) |
| 78 | |
| 79 | def ParseC1visualizerStream(fileName, stream): |
| 80 | c1File = C1visualizerFile(fileName) |
| 81 | state = C1ParserState() |
| 82 | fnProcessLine = lambda line, lineNo: __parseC1Line(line, lineNo, state, fileName) |
| 83 | fnLineOutsideChunk = lambda line, lineNo: \ |
| 84 | Logger.fail("C1visualizer line not inside a group", fileName, lineNo) |
| 85 | for passName, passLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk): |
| 86 | C1visualizerPass(c1File, passName, passLines, startLineNo + 1) |
| 87 | return c1File |