Quoting Ian Romanick (2017-11-10 14:32:50) [snip] > + > +def can_have_extra_operands(name, enums): > + """Determine whether an enum can have extra operands. > + > + Some enums, like SpvDecoration, can have extra operands with some values. > + Other enums, like SpvMemorySemantics, cannot. > + """ > + > + if name not in enums: > + return False > + > + for parameter in enums[name][1]: > + if len(parameter[2]) > 0:
Not using len() here would be faster: if parameter[2]: return True Or, if you like a more functional approach you could do something like: return any(p[2] for p in enums[name][1]) > + return True > + > + return False > + > +def prototype_for_instruction_emit(inst, all_enums, bit_enums): > + parameters = ["spirv_program *prog"] > + > + if "operands" in inst: > + parameters = parameters + [declare_parameter(operand, all_enums, > bit_enums) for operand in inst["operands"]] > + > + return textwrap.dedent("""\ > + static inline void > + emit_Spv{name}({parameters})""".format(name=inst["opname"], > + parameters=",\n > ".join(parameters))) > + > + > +def default_value(parameter, bit_enums): > + """Determine whether an enum has a value that is the default when the > enum is > + not specified. > + > + Some enums are almost always marked as optional on the instructions that > + use them. Some of these, like SpvMemoryAccess, have a value that is > + assumed when the value is not specificed in the instruction. > + """ > + > + pass This function appears to be unused. > + > +def instruction_size(instruction, enums): > + """Determine the size of an instruction based on its operands > + > + Instructions that have only operands without ? or * quantifiers are sized > + by the number of operands. In addition, instructions that have certain > + BitEnum and ValueEnum parameters also have varying sizes. > + """ > + > + if "operands" not in instruction: > + # Instructions like OpNop that have no operands. Handle these with a > + # trivial special case. > + return 1 > + > + for operand in instruction["operands"]: > + if "quantifier" in operand: > + return 0 > + elif operand["kind"] == "LiteralString": > + return 0 > + elif operand["kind"] in enums and enums[operand["kind"]][0]: > + return 0 > + > + return len(instruction["operands"]) + 1 > + > +def optional_parameter_flag(operand, bit_enums): > + """Return the name of the flag for an optional parameter, None otherwise > + > + Optional parameters are noted in the JSON with a "?" quantifier. For > some > + types, it is possible to infer that a value does not exist by examining > + the value. For example, if a optional LiteralString parameter is NULL, > it > + is not included. The same applies for some BitEnum kinds such as > + ImageOperands. For cases where the existence cannot be infered from the > + value, a "has_foo" flag is added to the parameter list. > + > + This function returns either the has_foo name as a string or None. > + """ > + > + if operand["kind"] == "LiteralString": > + return None > + > + if operand["kind"] == "ImageOperands": > + return None > + > + if operand["kind"] in bit_enums: > + return None > + > + if "quantifier" not in operand or operand["quantifier"] != "?": > + return None > + > + return "has_" + operand_name(operand) > + > +def operand_name(operand): > + if operand["kind"] == "IdResult": > + return "result" > + elif operand["kind"] == "IdResultType": > + return "result_type" > + elif "name" in operand: > + if "quantifier" in operand and "+" in operand["name"]: > + return operand["kind"] > + elif operand["name"] == "'D~ref~'": > + return "deref" > + else: > + name=operand["name"].replace("'", "").replace(" ", > "_").replace(".", "").replace("~","_").lower() > + return name if name not in ["default"] else "_" + name > + else: > + return operand["kind"] > + > +def list_is_same(a, b): > + if len(a) != len(b): > + return False > + > + for x in a: > + if x not in b: > + return False > + > + return True is there a reason you canot just do `a == b`? > + > +def capabilities_are_same(enums): > + for parameter in enums[1:]: > + if not list_is_same(enums[0][1], parameter[1]): > + return False > + > + return True > + > +def render_enable_capability(capability_list, indent=" "): > + if len(capability_list) == 0: > + return "" > + > + execution_modes = ["Kernel", "Shader", "Geometry", "Tessellation"] > + > + if set(capability_list) <= set(execution_modes): > + # If all of the capabilities are execution mode capabilities, then > one > + # of the must already be set. > + > + if len(capability_list) == 1: > + text = > "assert(prog->capabilities->is_enabled(SpvCapability{}));".format(capability_list[0]) > + else: > + template = Template("""\ > + > assert(prog->capabilities->is_enabled(SpvCapability${capability_list[0]}) || > + % for cap in capability_list[1:-1]: > + prog->capabilities->is_enabled(SpvCapability${cap}) || > + % endfor > + > prog->capabilities->is_enabled(SpvCapability${capability_list[-1]}));""") > + > + text = template.render(capability_list=capability_list) > + elif len(capability_list) == 2 and capability_list[0] in execution_modes: > + # If there are two capabilities listed and one is either > + # SpvCapabilityKernel or SpvCapabilityShader, then enable the other > + # capability if the non-SpvCapabilityKernel-or-SpvCapabilityShader > + # capablity is not enabled. > + > + text = """\ > + if (!prog->capabilities->is_enabled(SpvCapability{})) > + > prog->capabilities->enable(SpvCapability{});""".format(capability_list[0], > + > capability_list[1]) > + elif len(capability_list) == 1: > + # If there is a single capability listed that is neither > + # SpvCapabilityKernel nor SpvCapabilityShader, then enable it. > + > + text = > "prog->capabilities->enable(SpvCapability{});".format(capability_list[0]) > + else: > + # If there are multiple capabilities listed, things become > + # complicated. There is generally not enough information available > to > + # know which capability should be enabled. > + > + template = Template("""\ > + if > (!prog->capabilities->is_enabled(SpvCapability${capability_list[0]}) && > + % for cap in capability_list[1:-1]: > + !prog->capabilities->is_enabled(SpvCapability${cap}) && > + % endfor > + > !prog->capabilities->is_enabled(SpvCapability${capability_list[-1]})) { > + // FINISHME: Do something smart. > + }""") > + > + text = template.render(capability_list=capability_list) > + > + text = textwrap.dedent(text) > + return "\n".join([(indent + l).rstrip() for l in text.splitlines()]) > + > +TEMPLATE = Template(COPYRIGHT + """\ > +#ifndef SPIRV_BUILDER_FUNCTIONS_H > +#define SPIRV_BUILDER_FUNCTIONS_H > + > +% for name in bit_enums: > + > +static inline void > +Spv${name}_validate_and_set_capabilities(MAYBE_UNUSED spirv_program *prog, > MAYBE_UNUSED ${type_map[name]} bits${", MAYBE_UNUSED const uint32_t > *parameters" if bit_enums[name][0] else ""}) > +{ > + assert((bits & ~(${bit_enums[name][1][0][0]} | > + % for parameter in bit_enums[name][1][1:]: > + ${parameter[0]}${" |" if parameter != > bit_enums[name][1][-1] else ")) == 0);"} > + % endfor > + % for parameter in bit_enums[name][1]: > + % if len(parameter[1]) == 1 and parameter[1][0] in ["Shader", > "Kernel"]: > + assert((bits & ${parameter[0]}) == 0 || > + prog->capabilities->is_enabled(SpvCapability${parameter[1][0]})); > + % elif len(parameter[1]) > 0: > + > + if ((bits & ${parameter[0]})) > + prog->capabilities->enable(SpvCapability${parameter[1][0]}); > + % endif > + % endfor > +} > + % if bit_enums[name][0]: > + > +static inline unsigned > +${type_map[name]}_parameter_count(${type_map[name]} bits) > +{ > + unsigned count = 0; > + % for parameter in bit_enums[name][1]: > + % if len(parameter[2]) > 0: > + > + if ((bits & ${parameter[0]}) != 0) > + count += ${len(parameter[2])}; > + % endif > + % endfor > + > + return count; > +} > + % endif > +% endfor > +% for name in value_enums: > + > +static inline void > +Spv${name}_validate_and_set_capabilities(MAYBE_UNUSED spirv_program *prog, > ${type_map[name]} value${", MAYBE_UNUSED const uint32_t *parameters" if > value_enums[name][0] else ""}) > +{ > + switch (value) { > + % if name == "Capability": > + % for parameter in value_enums[name][1]: > + case ${type_map[name]}${parameter[0]}: > + % endfor > + break; > + % else: > + % for parameter in value_enums[name][1]: > + case ${type_map[name]}${parameter[0]}: > + % for i in range(len(parameter[2])): > + % if parameter[2][i]["kind"] in all_enums: > + Spv${parameter[2][i]["kind"]}_validate_and_set_capabilities(prog, > (${type_map[parameter[2][i]["kind"]]}) parameters[${i}]); > + % endif > + % endfor > + % if not capabilities_are_same(value_enums[name][1]) or > parameter == value_enums[name][1][-1]: > + % if len(parameter[1]) > 0: > +${render_enable_capability(parameter[1], " ")} > + % endif > + break; > + % endif > + % endfor > + % endif > + default: > + unreachable("Invalid ${type_map[name]} value."); > + } > +} > + % if value_enums[name][0]: > + > +static inline unsigned > +Spv${name}_parameter_count(${type_map[name]} value) > +{ > + switch (value) { > + % for parameter in value_enums[name][1]: > + case ${type_map[name]}${parameter[0]}: return ${len(parameter[2])}; > + % endfor > + default: unreachable("Invalid ${type_map[name]} value."); > + } > +} > + % endif > +% endfor > + > +static inline void > +emit_SpvHeader(spirv_program *prog, uint32_t magic, uint32_t id_bound) > +{ > + prog->write_word(SpvMagicNumber); > + prog->write_word(SpvVersion); > + prog->write_word(magic); > + prog->write_word(id_bound); > + prog->write_word(0); > +} > +% for inst in instructions: > + > + % if "operands" in inst and "quantifier" in inst["operands"][-1] and > inst["operands"][-1]["quantifier"] == "*": > +static inline void > +begin_Spv${inst["opname"]}( > + ${", ".join(["spirv_program *prog"] + [declare_parameter(operand, > all_enums, bit_enums) for operand in inst["operands"][:-1]])}) > +{ > + % if "capabilities" in inst: > +${render_enable_capability(inst["capabilities"], " ")} > + > + % endif > + > + % if len(inst["operands"]) < 2: > + /* Write the instruction header now, even though it will be rewritten in > + * end_Spv${inst["opname"]}, to aid debugging. Having something in the > + * output stream can be helpful. > + */ > + % endif > + prog->start_instruction(Spv${inst["opname"]}); > + % for operand in inst["operands"][:-1]: > + % if operand["kind"] == "LiteralString": > + prog->write_string(${operand_name(operand)}); > + % else: > + prog->write_word((uint32_t) ${operand_name(operand)}); > + % endif > + % endfor > +} > + > +static inline void > +emit_Spv${inst["opname"]}_data( > + spirv_program *prog, > + % if inst["operands"][-1]["kind"] in composite_types: > + % for i in > range(len(composite_types[inst["operands"][-1]["kind"]]) - 1): > + ${type_map[composite_types[inst["operands"][-1]["kind"]][i]]} p${i}, > + % endfor > + ${type_map[composite_types[inst["operands"][-1]["kind"]][-1]]} > p${len(composite_types[inst["operands"][-1]["kind"]]) - 1}) > + % else: > + ${declare_parameter(inst["operands"][-1], all_enums, bit_enums)}) > + % endif > +{ > + //assert(prog->begin != NULL); > + % if inst["operands"][-1]["kind"] in composite_types: > + % for i in > range(len(composite_types[inst["operands"][-1]["kind"]])): > + prog->write_word((uint32_t) p${i}); > + % endfor > + % else: > + prog->write_word((uint32_t) ${operand_name(inst["operands"][-1])}); > + % endif > +} > + > +static inline void > +end_Spv${inst["opname"]}(spirv_program *prog) > +{ > + prog->finish_instruction(Spv${inst["opname"]}); > +} > + % elif instruction_size(inst, all_enums) == 0: > +${prototype_for_instruction_emit(inst, all_enums, bit_enums)} > +{ > + % if "capabilities" in inst: > +${render_enable_capability(inst["capabilities"], " ")} > + > + % endif > + % if "operands" in inst: > + % for operand in inst["operands"]: > + % if operand["kind"] in all_enums: > + % if optional_parameter_flag(operand, bit_enums) is not > None: > + if (${optional_parameter_flag(operand, bit_enums)}) > + Spv${operand["kind"]}_validate_and_set_capabilities(prog, > ${operand_name(operand)}${", (const uint32_t > *){}_parameters".format(operand_name(operand)) if > can_have_extra_operands(operand["kind"], all_enums) else ""}); > + % else: > + Spv${operand["kind"]}_validate_and_set_capabilities(prog, > ${operand_name(operand)}${", (const uint32_t > *){}_parameters".format(operand_name(operand)) if > can_have_extra_operands(operand["kind"], all_enums) else ""}); > + % endif > + % endif > + % endfor > + > + % endif > + % if instruction_size(inst, all_enums) == 0: > + prog->start_instruction(Spv${inst["opname"]}); > + % else: > + prog->start_instruction(Spv${inst["opname"]}, ${instruction_size(inst, > all_enums)}); > + % endif > + % if "operands" in inst: > + % for operand in inst["operands"]: > + % if optional_parameter_flag(operand, bit_enums) is not None: > + > + if (${optional_parameter_flag(operand, bit_enums)}) > + prog->write_word((uint32_t) ${operand_name(operand)}); > + % elif operand["kind"] == "LiteralString" and "quantifier" > in operand and operand["quantifier"] == "?": > + > + if (${operand_name(operand)} != NULL) > + prog->write_string(${operand_name(operand)}); > + % elif operand["kind"] == "LiteralString": > + prog->write_string(${operand_name(operand)}); > + % elif operand["kind"] in bit_enums and > bit_enums[operand["kind"]][0]: > + % if "quantifier" in operand and operand["quantifier"] > == "?": > + > + if (${operand_name(operand)} != ${type_map[operand["kind"]]}None) { > + prog->write_word((uint32_t) ${operand_name(operand)}); > + prog->write(${operand_name(operand)}_parameters, > + > ${type_map[operand["kind"]]}_parameter_count(${operand_name(operand)})); > + } > + % else: > + > + prog->write_word((uint32_t) ${operand_name(operand)}); > + % if operand["kind"] == "ImageOperands": > + assert(${operand_name(operand)} != ${type_map[operand["kind"]]}None); > + > + prog->write(${operand_name(operand)}_parameters, > + > ${type_map[operand["kind"]]}_parameter_count(${operand_name(operand)})); > + % else: > + if (${operand_name(operand)} != ${type_map[operand["kind"]]}None) { > + prog->write(${operand_name(operand)}_parameters, > + > ${type_map[operand["kind"]]}_parameter_count(${operand_name(operand)})); > + } > + % endif > + % endif > + % elif operand["kind"] in value_enums and > value_enums[operand["kind"]][0]: > + prog->write_word((uint32_t) ${operand_name(operand)}); > + prog->write(${operand_name(operand)}_parameters, > + > ${type_map[operand["kind"]]}_parameter_count(${operand_name(operand)})); > + % else: > + prog->write_word((uint32_t) ${operand_name(operand)}); > + % endif > + % endfor > + % endif > + > + /* Fix the size based on what was actually emitted. */ > + prog->finish_instruction(Spv${inst["opname"]}); > +} > + % else: > +${prototype_for_instruction_emit(inst, all_enums, bit_enums)} > +{ > + % if "capabilities" in inst: > +${render_enable_capability(inst["capabilities"], " ")} > + > + % endif > + % if inst["opname"] == "OpTypeInt": > + switch (width) { > + case 8: > + assert(prog->capabilities->is_enabled(SpvCapabilityKernel)); > + prog->capabilities->enable(SpvCapabilityInt8); > + break; > + case 16: > + prog->capabilities->enable(SpvCapabilityInt16); > + break; > + case 32: > + break; > + case 64: > + prog->capabilities->enable(SpvCapabilityInt64); > + break; > + default: > + assert(!"Invalid integer width."); > + } > + > + % elif inst["opname"] == "OpTypeFloat": > + switch (width) { > + case 16: > + prog->capabilities->enable(SpvCapabilityFloat16); > + break; > + case 32: > + break; > + case 64: > + prog->capabilities->enable(SpvCapabilityFloat64); > + break; > + default: > + assert(!"Invalid float width."); > + } > + > + % endif > + % if "operands" in inst: > + % for operand in inst["operands"]: > + % if operand["kind"] in all_enums: > + Spv${operand["kind"]}_validate_and_set_capabilities(prog, > ${operand_name(operand)}${", (const uint32_t > *){}_parameters".format(operand_name(operand)) if > can_have_extra_operands(operand["kind"], all_enums) else ""}); > + % endif > + % endfor > + > + % endif > + prog->start_instruction(Spv${inst["opname"]}, ${instruction_size(inst, > all_enums)}); > + % if "operands" in inst: > + % for operand in inst["operands"]: > + prog->write_word((uint32_t) ${operand_name(operand)}); > + % endfor > + % endif > + prog->finish_instruction(Spv${inst["opname"]}); > +} > + % endif > +% endfor > + > +#endif /* SPIRV_BUILDER_FUNCTIONS_H */ > +""") > + > +if __name__ == "__main__": > + pargs = parse_args() > + > + spirv_info = json.JSONDecoder().decode(open(pargs.json, "r").read()) > + > + type_map = {"LiteralContextDependentNumber": "int", > + "LiteralExtInstInteger": "int", > + "LiteralInteger": "int", > + "LiteralString": "const char *", > + "LiteralSpecConstantOpInteger": "int" > + } > + > + composite_types = {} > + bit_enums = {} > + value_enums = {} > + for operand_kind in spirv_info["operand_kinds"]: > + kind = operand_kind["kind"] > + > + if operand_kind["category"] == "BitEnum": > + type_map[kind] = "Spv" + kind + "Mask" > + > + values = [] > + has_parameters = False > + for enum in operand_kind["enumerants"]: > + # For some reason, spirv.h does not include names for > 0-values > + # of BitEnums that are not None. For example, there is no > + # SpvMemorySemanticsRelaxedMask even though it appears in the > + # JSON. > + if int(enum["value"], 16) == 0 and enum["enumerant"] != > "None": > + continue > + > + capabilities = enum["capabilities"] if "capabilities" in > enum else [] > + parameters = enum["parameters"] if "parameters" in enum else > [] > + > + if enum["enumerant"] == "None": > + enum_name = "Spv" + kind + "MaskNone" > + else: > + enum_name = "Spv" + kind + enum["enumerant"] + "Mask" > + > + values.append((enum_name, capabilities, parameters)) > + > + if len(parameters) > 0: just `if parameters:` > + has_parameters = True > + > + bit_enums[kind] = (has_parameters, values) > + elif operand_kind["category"] == "ValueEnum": > + type_map[kind] = "Spv" + kind > + > + values = [] > + has_parameters = False > + last_value = -1 > + for enum in operand_kind["enumerants"]: > + if enum["value"] == last_value: > + continue > + > + last_value = enum["value"] > + capabilities = enum["capabilities"] if "capabilities" in > enum else [] > + parameters = enum["parameters"] if "parameters" in enum else > [] > + values.append((enum["enumerant"], capabilities, parameters)) > + > + if len(parameters) > 0: > + has_parameters = True > + > + value_enums[kind] = (has_parameters, values) > + elif operand_kind["category"] == "Id": > + type_map[kind] = "SpvId" > + elif operand_kind["category"] == "Composite": > + type_map[kind] = "struct Spv" + kind > + composite_types[kind] = operand_kind["bases"] > + elif operand_kind["category"] != "Literal" or kind not in type_map: > + print("Don't know how to handle {} in category {}".format(kind, > operand_kind["category"])) > + exit(1) > + > + all_enums = dict(value_enums); > + all_enums.update(bit_enums); > + > + with open(pargs.out, 'w') as f: > + f.write(TEMPLATE.render(instructions=spirv_info["instructions"], > + composite_types=composite_types, > + type_map=type_map, > + operand_name=operand_name, > + instruction_size=instruction_size, > + > optional_parameter_flag=optional_parameter_flag, > + declare_parameter=declare_parameter, > + > can_have_extra_operands=can_have_extra_operands, > + > prototype_for_instruction_emit=prototype_for_instruction_emit, > + bit_enums=bit_enums, > + value_enums=value_enums, > + all_enums=all_enums, > + capabilities_are_same=capabilities_are_same, > + > render_enable_capability=render_enable_capability)) > -- > 2.9.5 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev
signature.asc
Description: signature
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev