blob: f34161b297d6d56782726def42daa0a95e26cc1a [file] [log] [blame]
# Copyright (C) 2015 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 SplitStream
from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
import re
class C1ParserState:
OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
def __init__(self):
self.currentState = C1ParserState.OutsideBlock
self.lastMethodName = None
def __parseC1Line(line, lineNo, state, fileName):
""" This function is invoked on each line of the output file and returns
a pair 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.
"""
if state.currentState == C1ParserState.StartingCfgBlock:
# 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("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.currentState = C1ParserState.InsideCfgBlock
return (None, state.lastMethodName + " " + line.split("\"")[1])
else:
Logger.fail("Expected output group name", fileName, lineNo)
elif state.currentState == C1ParserState.InsideCfgBlock:
if line == "end_cfg":
state.currentState = C1ParserState.OutsideBlock
return (None, None)
else:
return (line, None)
elif state.currentState == C1ParserState.InsideCompilationBlock:
# Search for the method's name. Format: method "<name>"
if re.match("method\s+\"[^\"]*\"", line):
methodName = line.split("\"")[1].strip()
if not methodName:
Logger.fail("Empty method name in output", fileName, lineNo)
state.lastMethodName = methodName
elif line == "end_compilation":
state.currentState = C1ParserState.OutsideBlock
return (None, None)
else:
assert state.currentState == C1ParserState.OutsideBlock
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.lastMethodName is None:
Logger.fail("Expected method header", fileName, lineNo)
state.currentState = C1ParserState.StartingCfgBlock
return (None, None)
elif line == "begin_compilation":
state.currentState = C1ParserState.InsideCompilationBlock
return (None, None)
else:
Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
def ParseC1visualizerStream(fileName, stream):
c1File = C1visualizerFile(fileName)
state = C1ParserState()
fnProcessLine = lambda line, lineNo: __parseC1Line(line, lineNo, state, fileName)
fnLineOutsideChunk = lambda line, lineNo: \
Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
for passName, passLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
C1visualizerPass(c1File, passName, passLines, startLineNo + 1)
return c1File