Ejemplo n.º 1
0
    def from_yaml(yml: object, what: str,
                  insn_operands: List[Operand]) -> 'InsnInformationFlowRule':
        rule = check_keys(yml, what, ['to', 'from'], ['test'])

        to_what = '"to" list for {}'.format(what)
        flows_to = []
        for node_yml in check_list(rule['to'], to_what):
            node_what = 'node {} in {}'.format(node_yml, to_what)
            nodes = _parse_iflow_nodes(check_str(node_yml, node_what),
                                       node_what, insn_operands)
            flows_to.extend(nodes)

        from_what = '"from" list for {}'.format(what)
        flows_from = []
        for node_yml in check_list(rule['from'], from_what):
            node_what = 'node {} in {}'.format(node_yml, from_what)
            nodes = _parse_iflow_nodes(check_str(node_yml, node_what),
                                       node_what, insn_operands)
            flows_from.extend(nodes)

        test_yml = rule.get('test', None)
        if test_yml is None:
            tests = []
        else:
            test_what = 'test field for {}'.format(what)
            tests = [
                _parse_iflow_test(t, test_what, insn_operands)
                for t in check_list(test_yml, test_what)
            ]
        return InsnInformationFlowRule(flows_to, flows_from, MultiTest(tests))
Ejemplo n.º 2
0
    def from_yaml(yml: Optional[object], what: str,
                  insn_operands: List[Operand]) -> 'InsnInformationFlow':

        if yml is None:
            # Default behavior: all source registers flow to all destination
            # registers, no other information flow or special registers
            sources = [
                InsnRegOperandNode(op) for op in insn_operands if
                isinstance(op.op_type, RegOperandType) and op.op_type.is_src()
            ]
            dests = [
                InsnRegOperandNode(op) for op in insn_operands
                if isinstance(op.op_type, RegOperandType)
                and op.op_type.is_dest()
            ]
            return InsnInformationFlow(
                [InsnInformationFlowRule(dests, sources, MultiTest([]))])

        rule_list = check_list(yml, what)
        rules = []
        for idx, rule_yml in enumerate(rule_list):
            rule_what = 'rule at index {} for {}'.format(idx, what)
            rule = InsnInformationFlowRule.from_yaml(rule_yml, rule_what,
                                                     insn_operands)
            rules.append(rule)
        return InsnInformationFlow(rules)
Ejemplo n.º 3
0
 def __init__(self, path: str, encoding_schemes: Optional[EncSchemes],
              yml: object) -> None:
     self.groups = [
         InsnGroup(path, encoding_schemes, y)
         for y in check_list(yml, 'insn-groups')
     ]
     if not self.groups:
         raise ValueError('Empty list of instruction groups: '
                          'we need at least one as a base group.')
     self.key_to_group = index_list('insn-groups', self.groups,
                                    lambda ig: ig.key)
Ejemplo n.º 4
0
    def __init__(self, yml: object, name: str) -> None:
        what = 'encoding scheme {!r}'.format(name)
        yd = check_keys(yml, what, [], ['parents', 'fields'])

        if not yd:
            raise ValueError('{} has no parents or fields.'.format(what))

        fields_yml = yd.get('fields')
        self.direct_fields = (EncSchemeFields.from_yaml(fields_yml, name)
                              if fields_yml is not None else
                              EncSchemeFields.empty())

        parents_yml = yd.get('parents')
        parents_what = 'parents of {}'.format(what)
        parents = ([
            EncSchemeImport(y, name)
            for y in check_list(parents_yml, parents_what)
        ] if parents_yml is not None else [])
        self.parents = index_list(parents_what, parents,
                                  lambda imp: imp.parent)
Ejemplo n.º 5
0
    def __init__(self, path: str, encoding_schemes: Optional[EncSchemes],
                 yml: object) -> None:

        yd = check_keys(yml, 'insn-group', ['key', 'title', 'doc', 'insns'],
                        [])
        self.key = check_str(yd['key'], 'insn-group key')
        self.title = check_str(yd['title'], 'insn-group title')
        self.doc = check_str(yd['doc'], 'insn-group doc')

        insns_what = 'insns field for {!r} instruction group'.format(self.key)
        insns_rel_path = check_str(yd['insns'], insns_what)
        insns_path = os.path.normpath(
            os.path.join(os.path.dirname(path), insns_rel_path))
        insns_yaml = load_yaml(insns_path, insns_what)
        try:
            self.insns = [
                Insn(i, encoding_schemes)
                for i in check_list(insns_yaml, insns_what)
            ]
        except ValueError as err:
            raise RuntimeError(
                'Invalid schema in YAML file at {!r}: {}'.format(
                    insns_path, err)) from None
Ejemplo n.º 6
0
    def __init__(self, yml: object,
                 encoding_schemes: Optional[EncSchemes]) -> None:
        yd = check_keys(yml, 'instruction', ['mnemonic', 'operands'], [
            'group', 'rv32i', 'synopsis', 'syntax', 'doc', 'errs', 'note',
            'encoding', 'glued-ops', 'literal-pseudo-op', 'python-pseudo-op',
            'lsu', 'straight-line'
        ])

        self.mnemonic = check_str(yd['mnemonic'], 'mnemonic for instruction')

        what = 'instruction with mnemonic {!r}'.format(self.mnemonic)

        encoding_yml = yd.get('encoding')
        self.encoding = None
        if encoding_yml is not None:
            if encoding_schemes is None:
                raise ValueError(
                    '{} specifies an encoding, but the file '
                    'didn\'t specify any encoding schemes.'.format(what))

            self.encoding = Encoding(encoding_yml, encoding_schemes,
                                     self.mnemonic)

        self.operands = [
            Operand(y, self.mnemonic, self.encoding)
            for y in check_list(yd['operands'], 'operands for ' + what)
        ]
        self.name_to_operand = index_list('operands for ' + what,
                                          self.operands, lambda op: op.name)

        # The call to index_list has checked that operand names are distinct.
        # We also need to check that no operand abbreviation clashes with
        # anything else.
        operand_names = set(self.name_to_operand.keys())
        for op in self.operands:
            if op.abbrev is not None:
                if op.abbrev in operand_names:
                    raise ValueError('The name {!r} appears as an operand or '
                                     'abbreviation more than once for '
                                     'instruction {!r}.'.format(
                                         op.abbrev, self.mnemonic))
                operand_names.add(op.abbrev)

        if self.encoding is not None:
            # If we have an encoding, we passed it to the Operand constructors
            # above. This ensured that each operand has a field. However, it's
            # possible that there are some operand names the encoding mentions
            # that don't actually have an operand. Check for that here.
            missing_ops = (set(self.encoding.op_to_field_name.keys()) -
                           set(self.name_to_operand.keys()))
            if missing_ops:
                raise ValueError('Encoding scheme for {} specifies '
                                 'some non-existent operands: {}.'.format(
                                     what, ', '.join(list(missing_ops))))

        self.rv32i = check_bool(yd.get('rv32i', False),
                                'rv32i flag for ' + what)
        self.glued_ops = check_bool(yd.get('glued-ops', False),
                                    'glued-ops flag for ' + what)
        self.synopsis = get_optional_str(yd, 'synopsis', what)
        self.doc = get_optional_str(yd, 'doc', what)
        self.note = get_optional_str(yd, 'note', what)

        self.errs = None
        if 'errs' in yd:
            errs_what = 'errs field for ' + what
            y_errs = check_list(yd.get('errs'), errs_what)
            self.errs = []
            for idx, err_desc in enumerate(y_errs):
                self.errs.append(
                    check_str(err_desc,
                              'element {} of the {}'.format(idx, errs_what)))

        raw_syntax = get_optional_str(yd, 'syntax', what)
        if raw_syntax is not None:
            self.syntax = InsnSyntax.from_yaml(self.mnemonic,
                                               raw_syntax.strip())
        else:
            self.syntax = InsnSyntax.from_list(
                [op.name for op in self.operands])

        pattern, op_to_grp = self.syntax.asm_pattern()
        self.asm_pattern = re.compile(pattern)
        self.pattern_op_to_grp = op_to_grp

        # Make sure we have exactly the operands we expect.
        if set(self.name_to_operand.keys()) != self.syntax.op_set:
            raise ValueError("Operand syntax for {!r} doesn't have the "
                             "same list of operands as given in the "
                             "operand list. The syntax uses {}, "
                             "but the list of operands gives {}.".format(
                                 self.mnemonic,
                                 list(sorted(self.syntax.op_set)),
                                 list(sorted(self.name_to_operand))))

        self.python_pseudo_op = check_bool(yd.get('python-pseudo-op', False),
                                           'python-pseudo-op flag for ' + what)
        if self.python_pseudo_op and self.encoding is not None:
            raise ValueError('{} specifies an encoding and also sets '
                             'python-pseudo-op.'.format(what))

        lpo = yd.get('literal-pseudo-op')
        if lpo is None:
            self.literal_pseudo_op = None
        else:
            lpo_lst = check_list(lpo, 'literal-pseudo-op flag for ' + what)
            for idx, item in enumerate(lpo_lst):
                if not isinstance(item, str):
                    raise ValueError(
                        'Item {} of literal-pseudo-op list for '
                        '{} is {!r}, which is not a string.'.format(
                            idx, what, item))
            self.literal_pseudo_op = cast(Optional[List[str]], lpo_lst)

            if self.python_pseudo_op:
                raise ValueError('{} specifies both python-pseudo-op and '
                                 'literal-pseudo-op.'.format(what))
            if self.encoding is not None:
                raise ValueError('{} specifies both an encoding and '
                                 'literal-pseudo-op.'.format(what))

        lsu_yaml = yd.get('lsu', None)
        if lsu_yaml is None:
            self.lsu = None
        else:
            self.lsu = LSUDesc.from_yaml(lsu_yaml,
                                         'lsu field for {}'.format(what))
            for idx, op_name in enumerate(self.lsu.target):
                if op_name not in self.name_to_operand:
                    raise ValueError('element {} of the target for the lsu '
                                     'field for {} is {!r}, which is not a '
                                     'operand name of the instruction.'.format(
                                         idx, what, op_name))

        self.straight_line = yd.get('straight-line', True)