#!/usr/bin/perl -w # # Copyright 2025 Henri Verbeet # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA use strict; use warnings; use JSON; use open ':utf8'; binmode STDOUT, ':utf8'; sub opcode_id($) { sprintf "0x%04x", shift; } sub fix_name($) { shift =~ s/([A-Z]+)/_$1/rg; } sub operand_type_name(_) { "SPIRV_PARSER_OPERAND_TYPE${\uc fix_name shift}"; } sub grammar_version($) { my ($grammar) = @_; "$grammar->{major_version}.$grammar->{minor_version}.$grammar->{revision}"; } sub instruction_operand(_) { my ($operand) = @_; "{${\operand_type_name $operand->{kind}}" . (defined $operand->{quantifier} ? ", '$operand->{quantifier}'}" : "}"); } sub print_opcode_info(_) { my ($instruction) = @_; my $operand_count = @{$instruction->{operands} // []}; if (!$operand_count) { print " {${\opcode_id $instruction->{opcode}}, \"$instruction->{opname}\"},\n"; return; } print " {\n"; print " ${\opcode_id $instruction->{opcode}}, \"$instruction->{opname}\", $operand_count,\n"; print " (struct spirv_parser_instruction_operand[])\n"; print " {\n"; print " ${\instruction_operand},\n" foreach @{$instruction->{operands}}; print " }\n"; print " },\n"; } sub print_header($) { my ($grammar) = @_; my @operand_types = sort {$a->{kind} cmp $b->{kind}} @{$grammar->{operand_kinds}}; print "/* This file is automatically generated from version ${\grammar_version $grammar} of the\n"; print " * machine-readable SPIR-V grammar.\n"; print " *\n"; print " * The original source is covered by the following license:\n"; print " *\n"; print map {" * $_" =~ s/ +$//r . "\n"} @{$grammar->{copyright}}; print " */\n\n"; print "enum spirv_parser_operand_type\n"; print "{\n"; print " ${\operand_type_name $_->{kind}},\n" foreach @operand_types; print "};\n\n"; print "static const struct spirv_parser_operand_type_info\n"; print "{\n"; print " const char *name;\n"; print "}\n"; print "spirv_parser_operand_type_info[] =\n"; print "{\n"; print " [${\operand_type_name $_->{kind}}] = {\"$_->{kind}\"},\n" foreach @operand_types; print "};\n\n"; print "static const struct spirv_parser_opcode_info\n"; print "{\n"; print " uint16_t op;\n"; print " const char *name;\n"; print " size_t operand_count;\n"; print " const struct spirv_parser_instruction_operand\n"; print " {\n"; print " enum spirv_parser_operand_type type;\n"; print " char quantifier;\n"; print " } *operands;\n"; print "}\n"; print "spirv_parser_opcode_info[] =\n"; print "{\n"; print_opcode_info foreach sort {$a->{opcode} <=> $b->{opcode}} @{$grammar->{instructions}}; print "};\n"; } die "No input file specified.\n" unless @ARGV; print_header do { local $/; open my $fh, '<', $ARGV[0] or die $!; decode_json <$fh>; };