def check_yo_check(self, xform, expected_f): # type: (XForm, CheckProducer) -> None fmt = Formatter() type_sets = UniqueTable() for check in get_runtime_typechecks(xform): emit_runtime_typecheck(check, fmt, type_sets) # Remove comments got = "".join([l for l in fmt.lines if not l.strip().startswith("//")]) expected = expected_f(type_sets) self.assertEqual(got, expected)
def generate(isas, out_dir): # type: (Sequence[TargetISA], str) -> None shared_groups = set() # type: Set[XFormGroup] for isa in isas: fmt = Formatter() gen_isa(isa, fmt, shared_groups) fmt.update_file('legalize-{}.rs'.format(isa.name), out_dir) # Shared xform groups. fmt = Formatter() type_sets = UniqueTable() for xgrp in sorted(shared_groups, key=lambda g: g.name): gen_xform_group(xgrp, fmt, type_sets) gen_typesets_table(fmt, type_sets) fmt.update_file('legalizer.rs', out_dir)
def gen_isa(isa, fmt, shared_groups): # type: (TargetISA, Formatter, Set[XFormGroup]) -> None """ Generate legalization functions for `isa` and add any shared `XFormGroup`s encountered to `shared_groups`. Generate `TYPE_SETS` and `LEGALIZE_ACTION` tables. """ type_sets = UniqueTable() for xgrp in isa.legalize_codes.keys(): if xgrp.isa is None: shared_groups.add(xgrp) else: assert xgrp.isa == isa gen_xform_group(xgrp, fmt, type_sets) gen_typesets_table(fmt, type_sets) with fmt.indented( 'pub static LEGALIZE_ACTIONS: [isa::Legalize; {}] = ['.format( len(isa.legalize_codes)), '];'): for xgrp in isa.legalize_codes.keys(): fmt.format('{},', xgrp.rust_name())
def gen_type_constraints(fmt, instrs): # type: (srcgen.Formatter, Sequence[Instruction]) -> None """ Generate value type constraints for all instructions. - Emit a compact constant table of ValueTypeSet objects. - Emit a compact constant table of OperandConstraint objects. - Emit an opcode-indexed table of instruction constraints. """ # Table of TypeSet instances. type_sets = UniqueTable() # Table of operand constraint sequences (as tuples). Each operand # constraint is represented as a string, one of: # - `Concrete(vt)`, where `vt` is a value type name. # - `Free(idx)` where `idx` isan index into `type_sets`. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. operand_seqs = UniqueSeqTable() # Preload table with constraints for typical binops. operand_seqs.add(['Same'] * 3) fmt.comment('Table of opcode constraints.') with fmt.indented( 'const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = ['.format( len(instrs)), '];'): for i in instrs: # Collect constraints for the value results, not including # `variable_args` results which are always special cased. constraints = list() ctrl_typevar = None ctrl_typeset = typeset_limit if i.is_polymorphic: ctrl_typevar = i.ctrl_typevar ctrl_typeset = type_sets.add(ctrl_typevar.type_set) for idx in i.value_results: constraints.append( get_constraint(i.outs[idx], ctrl_typevar, type_sets)) for opnum in i.value_opnums: constraints.append( get_constraint(i.ins[opnum], ctrl_typevar, type_sets)) offset = operand_seqs.add(constraints) fixed_results = len(i.value_results) fixed_values = len(i.value_opnums) # Can the controlling type variable be inferred from the designated # operand? use_typevar_operand = i.is_polymorphic and i.use_typevar_operand # Can the controlling type variable be inferred from the result? use_result = (fixed_results > 0 and i.outs[i.value_results[0]].typevar == ctrl_typevar) # Are we required to use the designated operand instead of the # result? requires_typevar_operand = use_typevar_operand and not use_result fmt.comment('{}: fixed_results={}, use_typevar_operand={}, ' 'requires_typevar_operand={}, fixed_values={}'.format( i.camel_name, fixed_results, use_typevar_operand, requires_typevar_operand, fixed_values)) fmt.comment('Constraints={}'.format(constraints)) if i.is_polymorphic: fmt.comment('Polymorphic over {}'.format( ctrl_typevar.type_set)) # Compute the bit field encoding, c.f. instructions.rs. assert fixed_results < 8, "Bit field encoding too tight" flags = fixed_results if use_typevar_operand: flags |= 8 if requires_typevar_operand: flags |= 0x10 assert fixed_values < 8, "Bit field encoding too tight" flags |= fixed_values << 5 with fmt.indented('OpcodeConstraints {', '},'): fmt.line('flags: {:#04x},'.format(flags)) fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('constraint_offset: {},'.format(offset)) fmt.line() gen_typesets_table(fmt, type_sets) fmt.line() fmt.comment('Table of operand constraint sequences.') with fmt.indented( 'const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = ['.format( len(operand_seqs.table)), '];'): for c in operand_seqs.table: fmt.line('OperandConstraint::{},'.format(c))
def gen_type_constraints(fmt, instrs): # type: (srcgen.Formatter, Sequence[Instruction]) -> None """ Generate value type constraints for all instructions. - Emit a compact constant table of ValueTypeSet objects. - Emit a compact constant table of OperandConstraint objects. - Emit an opcode-indexed table of instruction constraints. """ # Table of TypeSet instances. type_sets = UniqueTable() # Table of operand constraint sequences (as tuples). Each operand # constraint is represented as a string, one of: # - `Concrete(vt)`, where `vt` is a value type name. # - `Free(idx)` where `idx` isan index into `type_sets`. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. operand_seqs = UniqueSeqTable() # Preload table with constraints for typical binops. operand_seqs.add(['Same'] * 3) fmt.comment('Table of opcode constraints.') with fmt.indented( 'const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [' .format(len(instrs)), '];'): for i in instrs: # Collect constraints for the value results, not including # `variable_args` results which are always special cased. constraints = list() ctrl_typevar = None ctrl_typeset = typeset_limit if i.is_polymorphic: ctrl_typevar = i.ctrl_typevar ctrl_typeset = type_sets.add(ctrl_typevar.type_set) for idx in i.value_results: constraints.append( get_constraint(i.outs[idx], ctrl_typevar, type_sets)) for opnum in i.value_opnums: constraints.append( get_constraint(i.ins[opnum], ctrl_typevar, type_sets)) offset = operand_seqs.add(constraints) fixed_results = len(i.value_results) fixed_values = len(i.value_opnums) # Can the controlling type variable be inferred from the designated # operand? use_typevar_operand = i.is_polymorphic and i.use_typevar_operand # Can the controlling type variable be inferred from the result? use_result = (fixed_results > 0 and i.outs[i.value_results[0]].typevar == ctrl_typevar) # Are we required to use the designated operand instead of the # result? requires_typevar_operand = use_typevar_operand and not use_result fmt.comment( '{}: fixed_results={}, use_typevar_operand={}, ' 'requires_typevar_operand={}, fixed_values={}' .format(i.camel_name, fixed_results, use_typevar_operand, requires_typevar_operand, fixed_values)) fmt.comment('Constraints={}'.format(constraints)) if i.is_polymorphic: fmt.comment( 'Polymorphic over {}'.format(ctrl_typevar.type_set)) # Compute the bit field encoding, c.f. instructions.rs. assert fixed_results < 8, "Bit field encoding too tight" flags = fixed_results if use_typevar_operand: flags |= 8 if requires_typevar_operand: flags |= 0x10 assert fixed_values < 8, "Bit field encoding too tight" flags |= fixed_values << 5 with fmt.indented('OpcodeConstraints {', '},'): fmt.line('flags: {:#04x},'.format(flags)) fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('constraint_offset: {},'.format(offset)) fmt.line() gen_typesets_table(fmt, type_sets) fmt.line() fmt.comment('Table of operand constraint sequences.') with fmt.indented( 'const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [' .format(len(operand_seqs.table)), '];'): for c in operand_seqs.table: fmt.line('OperandConstraint::{},'.format(c))
def gen_type_constraints(fmt, instrs): """ Generate value type constraints for all instructions. - Emit a compact constant table of ValueTypeSet objects. - Emit a compact constant table of OperandConstraint objects. - Emit an opcode-indexed table of instruction constraints. """ # Table of TypeSet instances. type_sets = UniqueTable() # Table of operand constraint sequences (as tuples). Each operand # constraint is represented as a string, one of: # - `Concrete(vt)`, where `vt` is a value type name. # - `Free(idx)` where `idx` isan index into `type_sets`. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. operand_seqs = UniqueSeqTable() # Preload table with constraints for typical binops. operand_seqs.add(['Same'] * 3) # TypeSet indexes are encoded in 8 bits, with `0xff` reserved. typeset_limit = 0xff fmt.comment('Table of opcode constraints.') with fmt.indented( 'const OPCODE_CONSTRAINTS : [OpcodeConstraints; {}] = [' .format(len(instrs)), '];'): for i in instrs: # Collect constraints for the value results, not including # `variable_args` results which are always special cased. constraints = list() ctrl_typevar = None ctrl_typeset = typeset_limit if i.is_polymorphic: ctrl_typevar = i.ctrl_typevar ctrl_typeset = type_sets.add(ctrl_typevar.type_set) for idx in i.value_results: constraints.append( get_constraint(i.outs[idx], ctrl_typevar, type_sets)) for idx in i.format.value_operands: constraints.append( get_constraint(i.ins[idx], ctrl_typevar, type_sets)) offset = operand_seqs.add(constraints) fixed_results = len(i.value_results) use_typevar_operand = i.is_polymorphic and i.use_typevar_operand fmt.comment( '{}: fixed_results={}, use_typevar_operand={}' .format(i.camel_name, fixed_results, use_typevar_operand)) fmt.comment('Constraints={}'.format(constraints)) if i.is_polymorphic: fmt.comment( 'Polymorphic over {}'.format(ctrl_typevar.type_set)) # Compute the bit field encoding, c.f. instructions.rs. assert fixed_results < 8, "Bit field encoding too tight" flags = fixed_results if use_typevar_operand: flags |= 8 with fmt.indented('OpcodeConstraints {', '},'): fmt.line('flags: {:#04x},'.format(flags)) fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('constraint_offset: {},'.format(offset)) fmt.comment('Table of value type sets.') assert len(type_sets.table) <= typeset_limit, "Too many type sets" with fmt.indented( 'const TYPE_SETS : [ValueTypeSet; {}] = [' .format(len(type_sets.table)), '];'): for ts in type_sets.table: with fmt.indented('ValueTypeSet {', '},'): ts.emit_fields(fmt) fmt.comment('Table of operand constraint sequences.') with fmt.indented( 'const OPERAND_CONSTRAINTS : [OperandConstraint; {}] = [' .format(len(operand_seqs.table)), '];'): for c in operand_seqs.table: fmt.line('OperandConstraint::{},'.format(c))
def gen_type_constraints(fmt, instrs): """ Generate value type constraints for all instructions. - Emit a compact constant table of ValueTypeSet objects. - Emit a compact constant table of OperandConstraint objects. - Emit an opcode-indexed table of instruction constraints. """ # Table of TypeSet instances. type_sets = UniqueTable() # Table of operand constraint sequences (as tuples). Each operand # constraint is represented as a string, one of: # - `Concrete(vt)`, where `vt` is a value type name. # - `Free(idx)` where `idx` isan index into `type_sets`. # - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints. operand_seqs = UniqueSeqTable() # Preload table with constraints for typical binops. operand_seqs.add(['Same'] * 3) # TypeSet indexes are encoded in 8 bits, with `0xff` reserved. typeset_limit = 0xff fmt.comment('Table of opcode constraints.') with fmt.indented( 'const OPCODE_CONSTRAINTS : [OpcodeConstraints; {}] = ['.format( len(instrs)), '];'): for i in instrs: # Collect constraints for the value results, not including # `variable_args` results which are always special cased. constraints = list() ctrl_typevar = None ctrl_typeset = typeset_limit if i.is_polymorphic: ctrl_typevar = i.ctrl_typevar ctrl_typeset = type_sets.add(ctrl_typevar.type_set) for idx in i.value_results: constraints.append( get_constraint(i.outs[idx], ctrl_typevar, type_sets)) for idx in i.format.value_operands: constraints.append( get_constraint(i.ins[idx], ctrl_typevar, type_sets)) offset = operand_seqs.add(constraints) fixed_results = len(i.value_results) use_typevar_operand = i.is_polymorphic and i.use_typevar_operand fmt.comment('{}: fixed_results={}, use_typevar_operand={}'.format( i.camel_name, fixed_results, use_typevar_operand)) fmt.comment('Constraints={}'.format(constraints)) if i.is_polymorphic: fmt.comment('Polymorphic over {}'.format( ctrl_typevar.type_set)) # Compute the bit field encoding, c.f. instructions.rs. assert fixed_results < 8, "Bit field encoding too tight" flags = fixed_results if use_typevar_operand: flags |= 8 with fmt.indented('OpcodeConstraints {', '},'): fmt.line('flags: {:#04x},'.format(flags)) fmt.line('typeset_offset: {},'.format(ctrl_typeset)) fmt.line('constraint_offset: {},'.format(offset)) fmt.comment('Table of value type sets.') assert len(type_sets.table) <= typeset_limit, "Too many type sets" with fmt.indented( 'const TYPE_SETS : [ValueTypeSet; {}] = ['.format( len(type_sets.table)), '];'): for ts in type_sets.table: with fmt.indented('ValueTypeSet {', '},'): ts.emit_fields(fmt) fmt.comment('Table of operand constraint sequences.') with fmt.indented( 'const OPERAND_CONSTRAINTS : [OperandConstraint; {}] = ['.format( len(operand_seqs.table)), '];'): for c in operand_seqs.table: fmt.line('OperandConstraint::{},'.format(c))