# Copyright (C) 2014 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 triplet 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. The third value is only here to make the
|
function prototype compatible with `SplitStream` and is always set to
|
`None` here.
|
"""
|
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], None)
|
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, None)
|
else:
|
return (line, None, 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, 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, None)
|
elif line == "begin_compilation":
|
state.currentState = C1ParserState.InsideCompilationBlock
|
return (None, 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, testArch in \
|
SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
|
C1visualizerPass(c1File, passName, passLines, startLineNo + 1)
|
return c1File
|