Beispiel #1
0
def MatchFiles(checkerFile, c1File, targetArch, debuggableMode):
    for testCase in checkerFile.testCases:
        if testCase.testArch not in [None, targetArch]:
            continue
        if testCase.forDebuggable != debuggableMode:
            continue

        # TODO: Currently does not handle multiple occurrences of the same group
        # name, e.g. when a pass is run multiple times. It will always try to
        # match a check group against the first output group of the same name.
        c1Pass = c1File.findPass(testCase.name)
        if c1Pass is None:
            Logger.fail(
                "Test case \"{}\" not found in the CFG file".format(
                    testCase.name), testCase.fileName, testCase.startLineNo)

        Logger.startTest(testCase.name)
        try:
            MatchTestCase(testCase, c1Pass)
            Logger.testPassed()
        except MatchFailedException as e:
            lineNo = c1Pass.startLineNo + e.lineNo
            if e.assertion.variant == TestAssertion.Variant.Not:
                Logger.testFailed(
                    "NOT assertion matched line {}".format(lineNo),
                    e.assertion.fileName, e.assertion.lineNo)
            else:
                Logger.testFailed(
                    "Assertion could not be matched starting from line {}".
                    format(lineNo), e.assertion.fileName, e.assertion.lineNo)
Beispiel #2
0
def MatchFiles(checkerFile, c1File, targetArch, debuggableMode):
  for testCase in checkerFile.testCases:
    if testCase.testArch not in [None, targetArch]:
      continue
    if testCase.forDebuggable != debuggableMode:
      continue

    # TODO: Currently does not handle multiple occurrences of the same group
    # name, e.g. when a pass is run multiple times. It will always try to
    # match a check group against the first output group of the same name.
    c1Pass = c1File.findPass(testCase.name)
    if c1Pass is None:
      with file(c1File.fileName) as cfgFile:
        Logger.log(''.join(cfgFile), Logger.Level.Error)
      Logger.fail("Test case not found in the CFG file",
                  testCase.fileName, testCase.startLineNo, testCase.name)

    Logger.startTest(testCase.name)
    try:
      MatchTestCase(testCase, c1Pass, c1File.instructionSetFeatures)
      Logger.testPassed()
    except MatchFailedException as e:
      lineNo = c1Pass.startLineNo + e.lineNo
      if e.statement.variant == TestStatement.Variant.Not:
        msg = "NOT statement matched line {}"
      else:
        msg = "Statement could not be matched starting from line {}"
      msg = msg.format(lineNo)
      with file(c1File.fileName) as cfgFile:
        Logger.log(''.join(cfgFile), Logger.Level.Error)
      Logger.testFailed(msg, e.statement, e.variables)
Beispiel #3
0
def match_files(checker_file, c1_file, target_arch, debuggable_mode,
                print_cfg):
    for test_case in checker_file.test_cases:
        if test_case.test_arch not in [None, target_arch]:
            continue
        if test_case.for_debuggable != debuggable_mode:
            continue

        # TODO: Currently does not handle multiple occurrences of the same group
        # name, e.g. when a pass is run multiple times. It will always try to
        # match a check group against the first output group of the same name.
        c1_pass = c1_file.find_pass(test_case.name)
        if c1_pass is None:
            with open(c1_file.full_file_name) as cfg_file:
                Logger.log("".join(cfg_file), Logger.Level.ERROR)
            Logger.fail("Test case not found in the CFG file",
                        c1_file.full_file_name, test_case.start_line_no,
                        test_case.name)

        Logger.start_test(test_case.name)
        try:
            match_test_case(test_case, c1_pass,
                            c1_file.instruction_set_features)
            Logger.test_passed()
        except MatchFailedException as e:
            line_no = c1_pass.start_line_no + e.line_no
            if e.statement.variant == TestStatement.Variant.NOT:
                msg = "NOT statement matched line {}"
            else:
                msg = "Statement could not be matched starting from line {}"
            msg = msg.format(line_no)
            if print_cfg:
                with open(c1_file.full_file_name) as cfg_file:
                    Logger.log("".join(cfg_file), Logger.Level.ERROR)
            Logger.test_failed(msg, e.statement, e.variables)
Beispiel #4
0
 def addExpression(self, new_expression):
     assert isinstance(new_expression, TestExpression)
     if self.variant == TestStatement.Variant.Not:
         if new_expression.variant == TestExpression.Variant.VarDef:
             Logger.fail("CHECK-NOT lines cannot define variables",
                         self.fileName, self.lineNo)
     self.expressions.append(new_expression)
Beispiel #5
0
def MatchFiles(checkerFile, c1File, targetArch, debuggableMode):
  for testCase in checkerFile.testCases:
    if testCase.testArch not in [None, targetArch]:
      continue
    if testCase.forDebuggable != debuggableMode:
      continue

    # TODO: Currently does not handle multiple occurrences of the same group
    # name, e.g. when a pass is run multiple times. It will always try to
    # match a check group against the first output group of the same name.
    c1Pass = c1File.findPass(testCase.name)
    if c1Pass is None:
      Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name),
                  testCase.fileName, testCase.startLineNo)

    Logger.startTest(testCase.name)
    try:
      MatchTestCase(testCase, c1Pass)
      Logger.testPassed()
    except MatchFailedException as e:
      lineNo = c1Pass.startLineNo + e.lineNo
      if e.assertion.variant == TestAssertion.Variant.Not:
        msg = "NOT assertion matched line {}"
      else:
        msg = "Assertion could not be matched starting from line {}"
      msg = msg.format(lineNo)
      Logger.testFailed(msg, e.assertion, e.variables)
Beispiel #6
0
 def addAssertion(self, new_assertion):
   if new_assertion.variant == TestAssertion.Variant.NextLine:
     if not self.assertions or \
        (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
         self.assertions[-1].variant != TestAssertion.Variant.NextLine):
       Logger.fail("A next-line assertion can only be placed after an "
                   "in-order assertion or another next-line assertion.",
                   new_assertion.fileName, new_assertion.lineNo)
   self.assertions.append(new_assertion)
Beispiel #7
0
 def addAssertion(self, new_assertion):
   if new_assertion.variant == TestAssertion.Variant.NextLine:
     if not self.assertions or \
        (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
         self.assertions[-1].variant != TestAssertion.Variant.NextLine):
       Logger.fail("A next-line assertion can only be placed after an "
                   "in-order assertion or another next-line assertion.",
                   new_assertion.fileName, new_assertion.lineNo)
   self.assertions.append(new_assertion)
Beispiel #8
0
 def addStatement(self, new_statement):
     if new_statement.variant == TestStatement.Variant.NextLine:
         if not self.statements or \
            (self.statements[-1].variant != TestStatement.Variant.InOrder and \
             self.statements[-1].variant != TestStatement.Variant.NextLine):
             Logger.fail(
                 "A next-line statement can only be placed after an "
                 "in-order statement or another next-line statement.",
                 new_statement.fileName, new_statement.lineNo)
     self.statements.append(new_statement)
Beispiel #9
0
    def __init__(self, parent, name, body, startLineNo):
        self.parent = parent
        self.name = name
        self.body = body
        self.startLineNo = startLineNo

        if not self.name:
            Logger.fail("C1visualizer pass does not have a name", self.fileName, self.startLineNo)
        if not self.body:
            Logger.fail("C1visualizer pass does not have a body", self.fileName, self.startLineNo)

        self.parent.addPass(self)
Beispiel #10
0
def DumpPass(outputFilename, passName):
  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
  compiler_pass = c1File.findPass(passName)
  if compiler_pass:
    maxLineNo = compiler_pass.startLineNo + len(compiler_pass.body)
    lenLineNo = len(str(maxLineNo)) + 2
    curLineNo = compiler_pass.startLineNo
    for line in compiler_pass.body:
      Logger.log((str(curLineNo) + ":").ljust(lenLineNo) + line)
      curLineNo += 1
  else:
    Logger.fail("Pass \"" + passName + "\" not found in the output")
Beispiel #11
0
  def __init__(self, parent, name, body, startLineNo):
    self.parent = parent
    self.name = name
    self.body = body
    self.startLineNo = startLineNo

    if not self.name:
      Logger.fail("C1visualizer pass does not have a name", self.fileName, self.startLineNo)
    if not self.body:
      Logger.fail("C1visualizer pass does not have a body", self.fileName, self.startLineNo)

    self.parent.addPass(self)
Beispiel #12
0
def DumpPass(outputFilename, passName):
  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
  compiler_pass = c1File.findPass(passName)
  if compiler_pass:
    maxLineNo = compiler_pass.startLineNo + len(compiler_pass.body)
    lenLineNo = len(str(maxLineNo)) + 2
    curLineNo = compiler_pass.startLineNo
    for line in compiler_pass.body:
      Logger.log((str(curLineNo) + ":").ljust(lenLineNo) + line)
      curLineNo += 1
  else:
    Logger.fail("Pass \"" + passName + "\" not found in the output")
Beispiel #13
0
  def __init__(self, parent, name, startLineNo, testArch = None):
    assert isinstance(parent, CheckerFile)

    self.parent = parent
    self.name = name
    self.assertions = []
    self.startLineNo = startLineNo
    self.testArch = testArch

    if not self.name:
      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)

    self.parent.addTestCase(self)
Beispiel #14
0
def dump_pass(output_filename, pass_name):
    c1_file = parse_c1_visualizer_stream(output_filename,
                                         open(output_filename, "r"))
    compiler_pass = c1_file.find_pass(pass_name)
    if compiler_pass:
        max_line_no = compiler_pass.start_line_no + len(compiler_pass.body)
        len_line_no = len(str(max_line_no)) + 2
        cur_line_no = compiler_pass.start_line_no
        for line in compiler_pass.body:
            Logger.log((str(cur_line_no) + ":").ljust(len_line_no) + line)
            cur_line_no += 1
    else:
        Logger.fail('Pass "{}" not found in the output'.format(pass_name))
Beispiel #15
0
  def __init__(self, parent, name, startLineNo, testArch = None, forDebuggable = False):
    assert isinstance(parent, CheckerFile)

    self.parent = parent
    self.name = name
    self.assertions = []
    self.startLineNo = startLineNo
    self.testArch = testArch
    self.forDebuggable = forDebuggable

    if not self.name:
      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)

    self.parent.addTestCase(self)
Beispiel #16
0
def __processLine(line, lineNo, prefix, fileName, targetArch):
    """ This function is invoked on each line of the check 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 check group, it is returned in the first
      value. If the line starts a new check group, the name of the group is
      returned in the second value. The third value indicates whether the line
      contained an architecture-specific suffix.
  """
    if not __isCheckerLine(line):
        return None, None, None

    # Lines beginning with 'CHECK-START' start a new test case.
    # We currently only consider the architecture suffix(es) in "CHECK-START" lines.
    for debuggable in [True, False]:
        sline = __preprocessLineForStart(prefix + "-START", line, targetArch)
        for arch in [None] + archs_list:
            startLine = __extractLine(prefix + "-START", sline, arch,
                                      debuggable)
            if startLine is not None:
                return None, startLine, (arch, debuggable)

    # Lines starting only with 'CHECK' are matched in order.
    plainLine = __extractLine(prefix, line)
    if plainLine is not None:
        return (plainLine, TestAssertion.Variant.InOrder, lineNo), None, None

    # 'CHECK-NEXT' lines are in-order but must match the very next line.
    nextLine = __extractLine(prefix + "-NEXT", line)
    if nextLine is not None:
        return (nextLine, TestAssertion.Variant.NextLine, lineNo), None, None

    # 'CHECK-DAG' lines are no-order assertions.
    dagLine = __extractLine(prefix + "-DAG", line)
    if dagLine is not None:
        return (dagLine, TestAssertion.Variant.DAG, lineNo), None, None

    # 'CHECK-NOT' lines are no-order negative assertions.
    notLine = __extractLine(prefix + "-NOT", line)
    if notLine is not None:
        return (notLine, TestAssertion.Variant.Not, lineNo), None, None

    # 'CHECK-EVAL' lines evaluate a Python expression.
    evalLine = __extractLine(prefix + "-EVAL", line)
    if evalLine is not None:
        return (evalLine, TestAssertion.Variant.Eval, lineNo), None, None

    Logger.fail("Checker assertion could not be parsed: '" + line + "'",
                fileName, lineNo)
Beispiel #17
0
def __processLine(line, lineNo, prefix, fileName):
  """ This function is invoked on each line of the check 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 check group, it is returned in the first
      value. If the line starts a new check group, the name of the group is
      returned in the second value. The third value indicates whether the line
      contained an architecture-specific suffix.
  """
  if not __isCheckerLine(line):
    return None, None, None

  # Lines beginning with 'CHECK-START' start a new test case.
  # We currently only consider the architecture suffix in "CHECK-START" lines.
  for debuggable in [True, False]:
    for arch in [None] + archs_list:
      startLine = __extractLine(prefix + "-START", line, arch, debuggable)
      if startLine is not None:
        return None, startLine, (arch, debuggable)

  # Lines starting only with 'CHECK' are matched in order.
  plainLine = __extractLine(prefix, line)
  if plainLine is not None:
    return (plainLine, TestAssertion.Variant.InOrder, lineNo), None, None

  # 'CHECK-NEXT' lines are in-order but must match the very next line.
  nextLine = __extractLine(prefix + "-NEXT", line)
  if nextLine is not None:
    return (nextLine, TestAssertion.Variant.NextLine, lineNo), None, None

  # 'CHECK-DAG' lines are no-order assertions.
  dagLine = __extractLine(prefix + "-DAG", line)
  if dagLine is not None:
    return (dagLine, TestAssertion.Variant.DAG, lineNo), None, None

  # 'CHECK-NOT' lines are no-order negative assertions.
  notLine = __extractLine(prefix + "-NOT", line)
  if notLine is not None:
    return (notLine, TestAssertion.Variant.Not, lineNo), None, None

  # 'CHECK-EVAL' lines evaluate a Python expression.
  evalLine = __extractLine(prefix + "-EVAL", line)
  if evalLine is not None:
    return (evalLine, TestAssertion.Variant.Eval, lineNo), None, None

  Logger.fail("Checker assertion could not be parsed: '" + line + "'", fileName, lineNo)
Beispiel #18
0
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)
Beispiel #19
0
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
Beispiel #20
0
def FindCheckerFiles(path):
  """ Returns a list of files to scan for check annotations in the given path.
      Path to a file is returned as a single-element list, directories are
      recursively traversed and all '.java' and '.smali' files returned.
  """
  if not path:
    Logger.fail("No source path provided")
  elif os.path.isfile(path):
    return [ path ]
  elif os.path.isdir(path):
    foundFiles = []
    for root, dirs, files in os.walk(path):
      for file in files:
        extension = os.path.splitext(file)[1]
        if extension in [".java", ".smali"]:
          foundFiles.append(os.path.join(root, file))
    return foundFiles
  else:
    Logger.fail("Source path \"" + path + "\" not found")
Beispiel #21
0
def find_checker_files(path):
    """ Returns a list of files to scan for check annotations in the given path.
      Path to a file is returned as a single-element list, directories are
      recursively traversed and all '.java', '.j', and '.smali' files returned.
  """
    if not path:
        Logger.fail("No source path provided")
    elif os.path.isfile(path):
        return [path]
    elif os.path.isdir(path):
        found_files = []
        for root, dirs, files in os.walk(path):
            for file in files:
                extension = os.path.splitext(file)[1]
                if extension in [".java", ".smali", ".j"]:
                    found_files.append(os.path.join(root, file))
        return found_files
    else:
        Logger.fail('Source path "{}" not found'.format(path))
Beispiel #22
0
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)
Beispiel #23
0
    def __init__(self,
                 parent,
                 name,
                 start_line_no,
                 test_arch=None,
                 for_debuggable=False):
        assert isinstance(parent, CheckerFile)

        self.parent = parent
        self.name = name
        self.statements = []
        self.start_line_no = start_line_no
        self.test_arch = test_arch
        self.for_debuggable = for_debuggable

        if not self.name:
            Logger.fail("Test case does not have a name", self.filename,
                        self.start_line_no)

        self.parent.add_test_case(self)
Beispiel #24
0
def ParseCheckerStream(fileName, prefix, stream):
  checkerFile = CheckerFile(fileName)
  fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName)
  fnLineOutsideChunk = lambda line, lineNo: \
      Logger.fail("Checker line not inside a group", fileName, lineNo)
  for caseName, caseLines, startLineNo, testArch in \
      SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
    testCase = TestCase(checkerFile, caseName, startLineNo, testArch)
    for caseLine in caseLines:
      ParseCheckerAssertion(testCase, caseLine[0], caseLine[1], caseLine[2])
  return checkerFile
Beispiel #25
0
def ParseC1visualizerStream(fileName, stream):
    c1File = C1visualizerFile(fileName)
    state = C1ParserState()
    fnProcessLine = lambda line, lineNo: __parseC1Line(c1File, 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
Beispiel #26
0
def ParseCheckerStream(fileName, prefix, stream):
    checkerFile = CheckerFile(fileName)
    fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix,
                                                       fileName)
    fnLineOutsideChunk = lambda line, lineNo: \
        Logger.fail("Checker line not inside a group", fileName, lineNo)
    for caseName, caseLines, startLineNo, testArch in \
        SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
        testCase = TestCase(checkerFile, caseName, startLineNo, testArch)
        for caseLine in caseLines:
            ParseCheckerAssertion(testCase, caseLine[0], caseLine[1],
                                  caseLine[2])
    return checkerFile
Beispiel #27
0
def ParseCheckerStream(fileName, prefix, stream, targetArch=None):
    checkerFile = CheckerFile(fileName)
    fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix,
                                                       fileName, targetArch)
    fnLineOutsideChunk = lambda line, lineNo: \
        Logger.fail("Checker line not inside a group", fileName, lineNo)
    for caseName, caseLines, startLineNo, testData in \
        SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
        testArch = testData[0]
        forDebuggable = testData[1]
        testCase = TestCase(checkerFile, caseName, startLineNo, testArch,
                            forDebuggable)
        for caseLine in caseLines:
            ParseCheckerStatement(testCase, caseLine[0], caseLine[1],
                                  caseLine[2])
    return checkerFile
Beispiel #28
0
def ParseCheckerStatement(parent, line, variant, lineNo):
    """ This method parses the content of a check line stripped of the initial
      comment symbol and the CHECK-* keyword.
  """
    statement = TestStatement(parent, variant, line, lineNo)

    if statement.isNoContentStatement() and line:
        Logger.fail("Expected empty statement: '" + line + "'",
                    statement.fileName, statement.lineNo)

    # Loop as long as there is something to parse.
    while line:
        # Search for the nearest occurrence of the special markers.
        if statement.isEvalContentStatement():
            # The following constructs are not supported in CHECK-EVAL, -IF and -ELIF lines
            matchWhitespace = None
            matchPattern = None
            matchVariableDefinition = None
        else:
            matchWhitespace = re.search(r"\s+", line)
            matchPattern = re.search(TestExpression.Regex.regexPattern, line)
            matchVariableDefinition = re.search(
                TestExpression.Regex.regexVariableDefinition, line)
        matchVariableReference = re.search(
            TestExpression.Regex.regexVariableReference, line)

        # If one of the above was identified at the current position, extract them
        # from the line, parse them and add to the list of line parts.
        if __isMatchAtStart(matchWhitespace):
            # A whitespace in the check line creates a new separator of line parts.
            # This allows for ignored output between the previous and next parts.
            line = line[matchWhitespace.end():]
            statement.addExpression(TestExpression.createSeparator())
        elif __isMatchAtStart(matchPattern):
            pattern = line[0:matchPattern.end()]
            pattern = pattern[2:-2]
            line = line[matchPattern.end():]
            statement.addExpression(TestExpression.createPattern(pattern))
        elif __isMatchAtStart(matchVariableReference):
            var = line[0:matchVariableReference.end()]
            line = line[matchVariableReference.end():]
            name = var[2:-2]
            statement.addExpression(
                TestExpression.createVariableReference(name))
        elif __isMatchAtStart(matchVariableDefinition):
            var = line[0:matchVariableDefinition.end()]
            line = line[matchVariableDefinition.end():]
            colonPos = var.find(":")
            name = var[2:colonPos]
            body = var[colonPos + 1:-2]
            statement.addExpression(
                TestExpression.createVariableDefinition(name, body))
        else:
            # If we're not currently looking at a special marker, this is a plain
            # text match all the way until the first special marker (or the end
            # of the line).
            firstMatch = __firstMatch([
                matchWhitespace, matchPattern, matchVariableReference,
                matchVariableDefinition
            ], line)
            text = line[0:firstMatch]
            line = line[firstMatch:]
            if statement.isEvalContentStatement():
                statement.addExpression(TestExpression.createPlainText(text))
            else:
                statement.addExpression(
                    TestExpression.createPatternFromPlainText(text))
    return statement
Beispiel #29
0
 def addExpression(self, new_expression):
     assert isinstance(new_expression, TestExpression)
     if self.variant == TestAssertion.Variant.Not:
         if new_expression.variant == TestExpression.Variant.VarDef:
             Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
     self.expressions.append(new_expression)
Beispiel #30
0
def _process_line(line, line_no, prefix, filename, target_arch):
    """ This function is invoked on each line of the check 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 check group, it is returned in the first
      value. If the line starts a new check group, the name of the group is
      returned in the second value. The third value indicates whether the line
      contained an architecture-specific suffix.
  """
    if not _is_checker_line(line):
        return None, None, None

    # Lines beginning with 'CHECK-START' start a new test case.
    # We currently only consider the architecture suffix(es) in "CHECK-START" lines.
    for debuggable in [True, False]:
        sline = _preprocess_line_for_start(prefix + "-START", line,
                                           target_arch)
        for arch in [None] + archs_list:
            start_line = _extract_line(prefix + "-START", sline, arch,
                                       debuggable)
            if start_line is not None:
                return None, start_line, (arch, debuggable)

    # Lines starting only with 'CHECK' are matched in order.
    plain_line = _extract_line(prefix, line)
    if plain_line is not None:
        return (plain_line, TestStatement.Variant.IN_ORDER,
                line_no), None, None

    # 'CHECK-NEXT' lines are in-order but must match the very next line.
    next_line = _extract_line(prefix + "-NEXT", line)
    if next_line is not None:
        return (next_line, TestStatement.Variant.NEXT_LINE,
                line_no), None, None

    # 'CHECK-DAG' lines are no-order statements.
    dag_line = _extract_line(prefix + "-DAG", line)
    if dag_line is not None:
        return (dag_line, TestStatement.Variant.DAG, line_no), None, None

    # 'CHECK-NOT' lines are no-order negative statements.
    not_line = _extract_line(prefix + "-NOT", line)
    if not_line is not None:
        return (not_line, TestStatement.Variant.NOT, line_no), None, None

    # 'CHECK-EVAL' lines evaluate a Python expression.
    eval_line = _extract_line(prefix + "-EVAL", line)
    if eval_line is not None:
        return (eval_line, TestStatement.Variant.EVAL, line_no), None, None

    # 'CHECK-IF' lines mark the beginning of a block that will be executed
    # only if the Python expression that follows evaluates to true.
    if_line = _extract_line(prefix + "-IF", line)
    if if_line is not None:
        return (if_line, TestStatement.Variant.IF, line_no), None, None

    # 'CHECK-ELIF' lines mark the beginning of an `else if` branch of a CHECK-IF block.
    elif_line = _extract_line(prefix + "-ELIF", line)
    if elif_line is not None:
        return (elif_line, TestStatement.Variant.ELIF, line_no), None, None

    # 'CHECK-ELSE' lines mark the beginning of the `else` branch of a CHECK-IF block.
    else_line = _extract_line(prefix + "-ELSE", line)
    if else_line is not None:
        return (else_line, TestStatement.Variant.ELSE, line_no), None, None

    # 'CHECK-FI' lines mark the end of a CHECK-IF block.
    fi_line = _extract_line(prefix + "-FI", line)
    if fi_line is not None:
        return (fi_line, TestStatement.Variant.FI, line_no), None, None

    Logger.fail("Checker statement could not be parsed: '" + line + "'",
                filename, line_no)
Beispiel #31
0
 def fn_line_outside_chunk(line, line_no):
     Logger.fail("Checker line not inside a group", file_name, line_no)
Beispiel #32
0
def parse_checker_statement(parent, line, variant, line_no):
    """ This method parses the content of a check line stripped of the initial
      comment symbol and the CHECK-* keyword.
  """
    statement = TestStatement(parent, variant, line, line_no)

    if statement.is_no_content_statement() and line:
        Logger.fail("Expected empty statement: '{}'".format(line),
                    statement.filename, statement.line_no)

    # Loop as long as there is something to parse.
    while line:
        # Search for the nearest occurrence of the special markers.
        if statement.is_eval_content_statement():
            # The following constructs are not supported in CHECK-EVAL, -IF and -ELIF lines
            match_whitespace = None
            match_pattern = None
            match_variable_definition = None
        else:
            match_whitespace = re.search(r"\s+", line)
            match_pattern = re.search(TestExpression.Regex.REGEX_PATTERN, line)
            match_variable_definition = re.search(
                TestExpression.Regex.REGEX_VARIABLE_DEFINITION, line)
        match_variable_reference = re.search(
            TestExpression.Regex.REGEX_VARIABLE_REFERENCE, line)

        # If one of the above was identified at the current position, extract them
        # from the line, parse them and add to the list of line parts.
        if _is_match_at_start(match_whitespace):
            # A whitespace in the check line creates a new separator of line parts.
            # This allows for ignored output between the previous and next parts.
            line = line[match_whitespace.end():]
            statement.add_expression(TestExpression.create_separator())
        elif _is_match_at_start(match_pattern):
            pattern = line[0:match_pattern.end()]
            pattern = pattern[2:-2]
            line = line[match_pattern.end():]
            statement.add_expression(TestExpression.create_pattern(pattern))
        elif _is_match_at_start(match_variable_reference):
            var = line[0:match_variable_reference.end()]
            line = line[match_variable_reference.end():]
            name = var[2:-2]
            statement.add_expression(
                TestExpression.create_variable_reference(name))
        elif _is_match_at_start(match_variable_definition):
            var = line[0:match_variable_definition.end()]
            line = line[match_variable_definition.end():]
            colon_pos = var.find(":")
            name = var[2:colon_pos]
            body = var[colon_pos + 1:-2]
            statement.add_expression(
                TestExpression.create_variable_definition(name, body))
        else:
            # If we're not currently looking at a special marker, this is a plain
            # text match all the way until the first special marker (or the end
            # of the line).
            first_match = _first_match([
                match_whitespace, match_pattern, match_variable_reference,
                match_variable_definition
            ], line)
            text = line[0:first_match]
            line = line[first_match:]
            if statement.is_eval_content_statement():
                statement.add_expression(
                    TestExpression.create_plain_text(text))
            else:
                statement.add_expression(
                    TestExpression.create_pattern_from_plain_text(text))
    return statement
Beispiel #33
0
 def fn_line_outside_chunk(line, line_no):
     Logger.fail("C1visualizer line not inside a group",
                 c1_file.base_file_name, line_no)
Beispiel #34
0
def _parse_c1_line(c1_file, line, line_no, 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.current_state == C1ParserState.STARTING_CFG_BLOCK:
        # 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(r'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.current_state = C1ParserState.INSIDE_CFG_BLOCK
            return None, state.last_method_name + " " + line.split(
                '"')[1], None
        else:
            Logger.fail("Expected output group name", filename, line_no)

    elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK:
        if line == "end_cfg":
            state.current_state = C1ParserState.OUTSIDE_BLOCK
            return None, None, None
        else:
            return line, None, None

    elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK:
        # Search for the method's name. Format: method "<name>"
        if re.match(r'method\s+"[^"]*"', line):
            method_name = line.split('"')[1].strip()
            if not method_name:
                Logger.fail("Empty method name in output", filename, line_no)

            match = re.search(r"isa_features:([\w,-]+)", method_name)
            if match:
                raw_features = match.group(1).split(",")
                # Create a map of features in the form {feature_name: is_enabled}.
                features = {}
                for rf in raw_features:
                    feature_name = rf
                    is_enabled = True
                    # A '-' in front of the feature name indicates that the feature wasn't enabled at compile
                    # time.
                    if rf[0] == "-":
                        feature_name = rf[1:]
                        is_enabled = False
                    features[feature_name] = is_enabled

                c1_file.set_isa_features(features)
            else:
                state.last_method_name = method_name
        elif line == "end_compilation":
            state.current_state = C1ParserState.OUTSIDE_BLOCK
        return None, None, None

    else:
        assert state.current_state == C1ParserState.OUTSIDE_BLOCK
        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.last_method_name is None:
                Logger.fail("Expected method header", filename, line_no)
            state.current_state = C1ParserState.STARTING_CFG_BLOCK
            return None, None, None
        elif line == "begin_compilation":
            state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK
            return None, None, None
        else:
            Logger.fail("C1visualizer line not inside a group", filename,
                        line_no)