spirv: Add a prepass to set types on vtn_values

This autogenerated pass will automatically find and set the type field
on all vtn_values.  This way we always have the type and can use it for
validation and other checks.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
Jason Ekstrand 2017-12-05 22:31:02 -08:00
parent 2c84b49ddf
commit bb1e6ff161
6 changed files with 149 additions and 3 deletions

View File

@ -56,6 +56,10 @@ spirv/spirv_info.c: spirv/spirv_info_c.py spirv/spirv.core.grammar.json
$(MKDIR_GEN)
$(PYTHON_GEN) $(srcdir)/spirv/spirv_info_c.py $(srcdir)/spirv/spirv.core.grammar.json $@ || ($(RM) $@; false)
spirv/vtn_gather_types.c: spirv/vtn_gather_types_c.py spirv/spirv.core.grammar.json
$(MKDIR_GEN)
$(PYTHON_GEN) $(srcdir)/spirv/vtn_gather_types_c.py $(srcdir)/spirv/spirv.core.grammar.json $@ || ($(RM) $@; false)
noinst_PROGRAMS += spirv2nir
spirv2nir_SOURCES = \

View File

@ -290,7 +290,8 @@ NIR_FILES = \
nir/nir_worklist.h
SPIRV_GENERATED_FILES = \
spirv/spirv_info.c
spirv/spirv_info.c \
spirv/vtn_gather_types.c
SPIRV_FILES = \
spirv/GLSL.std.450.h \

View File

@ -72,6 +72,14 @@ spirv_info_c = custom_target(
command : [prog_python2, '@INPUT0@', '@INPUT1@', '@OUTPUT@'],
)
vtn_gather_types_c = custom_target(
'vtn_gather_types.c',
input : files('../spirv/vtn_gather_types_c.py',
'../spirv/spirv.core.grammar.json'),
output : 'vtn_gather_types.c',
command : [prog_python2, '@INPUT0@', '@INPUT1@', '@OUTPUT@'],
)
files_libnir = files(
'nir.c',
'nir.h',
@ -189,7 +197,8 @@ files_libnir = files(
libnir = static_library(
'nir',
[files_libnir, spirv_info_c, nir_opt_algebraic_c, nir_opcodes_c,
nir_opcodes_h, nir_constant_expressions_c, nir_builder_opcodes_h],
nir_opcodes_h, nir_constant_expressions_c, nir_builder_opcodes_h,
vtn_gather_types_c],
include_directories : [inc_common, inc_compiler, include_directories('../spirv')],
c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args],
link_with : libcompiler,

View File

@ -1265,7 +1265,6 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);
val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
val->constant = rzalloc(b, nir_constant);
switch (opcode) {
case SpvOpConstantTrue:
@ -3287,6 +3286,8 @@ static bool
vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
vtn_set_instruction_result_type(b, opcode, w, count);
switch (opcode) {
case SpvOpSource:
case SpvOpSourceContinued:
@ -3677,6 +3678,9 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
words = vtn_foreach_instruction(b, words, word_end,
vtn_handle_variable_or_type_instruction);
/* Set types on all vtn_values */
vtn_foreach_instruction(b, words, word_end, vtn_set_instruction_result_type);
vtn_build_cfg(b, words, word_end);
assert(b->entry_point->value_type == vtn_value_type_function);

View File

@ -0,0 +1,124 @@
COPYRIGHT = """\
/*
* Copyright (C) 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
"""
import argparse
import json
from sys import stdout
from mako.template import Template
def find_result_types(spirv):
for inst in spirv['instructions']:
name = inst['opname']
if 'operands' not in inst:
continue
res_arg_idx = -1
res_type_arg_idx = -1
for idx, arg in enumerate(inst['operands']):
if arg['kind'] == 'IdResult':
res_arg_idx = idx
elif arg['kind'] == 'IdResultType':
res_type_arg_idx = idx
if res_type_arg_idx >= 0:
assert res_arg_idx >= 0
elif res_arg_idx >= 0:
untyped_insts = [
'OpString',
'OpExtInstImport',
'OpDecorationGroup',
'OpLabel',
]
assert name.startswith('OpType') or name in untyped_insts
if res_arg_idx >= 0 or res_type_arg_idx >= 0:
yield (name, res_arg_idx, res_type_arg_idx)
TEMPLATE = Template(COPYRIGHT + """\
/* DO NOT EDIT - This file is generated automatically by the
* vtn_gather_types_c.py script
*/
#include "vtn_private.h"
struct type_args {
int res_idx;
int res_type_idx;
};
static struct type_args
result_type_args_for_opcode(SpvOp opcode)
{
switch (opcode) {
% for opcode in opcodes:
case Spv${opcode[0]}: return (struct type_args){ ${opcode[1]}, ${opcode[2]} };
% endfor
default: return (struct type_args){ -1, -1 };
}
}
bool
vtn_set_instruction_result_type(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
struct type_args args = result_type_args_for_opcode(opcode);
if (args.res_idx >= 0 && args.res_type_idx >= 0) {
struct vtn_value *val = vtn_untyped_value(b, w[1 + args.res_idx]);
val->type = vtn_value(b, w[1 + args.res_type_idx],
vtn_value_type_type)->type;
}
return true;
}
""")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("json")
p.add_argument("out")
args = p.parse_args()
spirv_info = json.JSONDecoder().decode(open(args.json, "r").read())
opcodes = list(find_result_types(spirv_info))
try:
with open(args.out, 'w') as f:
f.write(TEMPLATE.render(opcodes=opcodes))
except Exception:
# In the even there's an error this imports some helpers from mako
# to print a useful stack trace and prints it, then exits with
# status 1, if python is run with debug; otherwise it just raises
# the exception
if __debug__:
import sys
from mako import exceptions
sys.stderr.write(exceptions.text_error_template().render() + '\n')
sys.exit(1)
raise

View File

@ -620,6 +620,10 @@ vtn_value(struct vtn_builder *b, uint32_t value_id,
return val;
}
bool
vtn_set_instruction_result_type(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count);
struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
struct vtn_ssa_value *vtn_create_ssa_value(struct vtn_builder *b,