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 SplitStream 17from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass 18 19import re 20 21class C1ParserState: 22 OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4) 23 24 def __init__(self): 25 self.currentState = C1ParserState.OutsideBlock 26 self.lastMethodName = None 27 28def __parseC1Line(c1File, line, lineNo, state, fileName): 29 """ This function is invoked on each line of the output file and returns 30 a triplet 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. The third value is only here to make the 34 function prototype compatible with `SplitStream` and is always set to 35 `None` here. 36 """ 37 if state.currentState == C1ParserState.StartingCfgBlock: 38 # Previous line started a new 'cfg' block which means that this one must 39 # contain the name of the pass (this is enforced by C1visualizer). 40 if re.match("name\s+\"[^\"]+\"", line): 41 # Extract the pass name, prepend it with the name of the method and 42 # return as the beginning of a new group. 43 state.currentState = C1ParserState.InsideCfgBlock 44 return (None, state.lastMethodName + " " + line.split("\"")[1], None) 45 else: 46 Logger.fail("Expected output group name", fileName, lineNo) 47 48 elif state.currentState == C1ParserState.InsideCfgBlock: 49 if line == "end_cfg": 50 state.currentState = C1ParserState.OutsideBlock 51 return (None, None, None) 52 else: 53 return (line, None, None) 54 55 elif state.currentState == C1ParserState.InsideCompilationBlock: 56 # Search for the method's name. Format: method "<name>" 57 if re.match("method\s+\"[^\"]*\"", line): 58 methodName = line.split("\"")[1].strip() 59 if not methodName: 60 Logger.fail("Empty method name in output", fileName, lineNo) 61 62 m = re.search("isa_features:([\w,-]+)", methodName) 63 if (m): 64 rawFeatures = m.group(1).split(",") 65 # Create a map of features in the form {featureName: isEnabled}. 66 features = {} 67 for rf in rawFeatures: 68 featureName = rf 69 isEnabled = True 70 # A '-' in front of the feature name indicates that the feature wasn't enabled at compile 71 # time. 72 if rf[0] == '-': 73 featureName = rf[1:] 74 isEnabled = False 75 features[featureName] = isEnabled 76 77 c1File.setISAFeatures(features) 78 else: 79 state.lastMethodName = methodName 80 elif line == "end_compilation": 81 state.currentState = C1ParserState.OutsideBlock 82 return (None, None, None) 83 84 else: 85 assert state.currentState == C1ParserState.OutsideBlock 86 if line == "begin_cfg": 87 # The line starts a new group but we'll wait until the next line from 88 # which we can extract the name of the pass. 89 if state.lastMethodName is None: 90 Logger.fail("Expected method header", fileName, lineNo) 91 state.currentState = C1ParserState.StartingCfgBlock 92 return (None, None, None) 93 elif line == "begin_compilation": 94 state.currentState = C1ParserState.InsideCompilationBlock 95 return (None, None, None) 96 else: 97 Logger.fail("C1visualizer line not inside a group", fileName, lineNo) 98 99def ParseC1visualizerStream(fileName, stream): 100 c1File = C1visualizerFile(fileName) 101 state = C1ParserState() 102 fnProcessLine = lambda line, lineNo: __parseC1Line(c1File, line, lineNo, state, fileName) 103 fnLineOutsideChunk = lambda line, lineNo: \ 104 Logger.fail("C1visualizer line not inside a group", fileName, lineNo) 105 for passName, passLines, startLineNo, testArch in \ 106 SplitStream(stream, fnProcessLine, fnLineOutsideChunk): 107 C1visualizerPass(c1File, passName, passLines, startLineNo + 1) 108 return c1File 109