Browse Source

nir: Add the start of a SPIR-V to NIR translator

At the moment, it can handle the very basics of strings and can ignore
debug instructions.  It also has basic support for decorations.
tags/12.0-branchpoint
Jason Ekstrand 10 years ago
parent
commit
b20d9f5643
3 changed files with 495 additions and 0 deletions
  1. 2
    0
      src/glsl/Makefile.sources
  2. 39
    0
      src/glsl/nir/nir_spirv.h
  3. 454
    0
      src/glsl/nir/spirv_to_nir.c

+ 2
- 0
src/glsl/Makefile.sources View File

@@ -64,6 +64,7 @@ NIR_FILES = \
nir/nir_remove_dead_variables.c \
nir/nir_search.c \
nir/nir_search.h \
nir/nir_spirv.h \
nir/nir_split_var_copies.c \
nir/nir_sweep.c \
nir/nir_to_ssa.c \
@@ -73,6 +74,7 @@ NIR_FILES = \
nir/nir_worklist.c \
nir/nir_worklist.h \
nir/nir_types.cpp \
nir/spirv_to_nir.c \
$(NIR_GENERATED_FILES)

# libglsl

+ 39
- 0
src/glsl/nir/nir_spirv.h View File

@@ -0,0 +1,39 @@
/*
* Copyright © 2015 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.
*
* Authors:
* Jason Ekstrand (jason@jlekstrand.net)
*
*/

#pragma once

#ifndef _NIR_SPIRV_H_
#define _NIR_SPIRV_H_

#include "nir.h"

nir_shader *spirv_to_nir(const uint32_t *words, size_t word_count,
gl_shader_stage stage,
const nir_shader_compiler_options *options);

#endif /* _NIR_SPIRV_H_ */

+ 454
- 0
src/glsl/nir/spirv_to_nir.c View File

@@ -0,0 +1,454 @@
/*
* Copyright © 2015 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.
*
* Authors:
* Jason Ekstrand (jason@jlekstrand.net)
*
*/

#include "nir_spirv.h"
#include "spirv.h"

struct vtn_decoration;

enum vtn_value_type {
vtn_value_type_invalid = 0,
vtn_value_type_undef,
vtn_value_type_string,
vtn_value_type_decoration_group,
vtn_value_type_ssa,
vtn_value_type_deref,
};

struct vtn_value {
enum vtn_value_type value_type;
const char *name;
struct vtn_decoration *decoration;
union {
void *ptr;
char *str;
nir_ssa_def *ssa;
nir_deref_var *deref;
};
};

struct vtn_decoration {
struct vtn_decoration *next;
const uint32_t *literals;
struct vtn_value *group;
SpvDecoration decoration;
};

struct vtn_builder {
nir_shader *shader;
nir_function_impl *impl;

unsigned value_id_bound;
struct vtn_value *values;
};

static void
vtn_push_value(struct vtn_builder *b, uint32_t value_id,
enum vtn_value_type value_type, void *ptr)
{
assert(value_id < b->value_id_bound);
assert(b->values[value_id].value_type == vtn_value_type_invalid);

b->values[value_id].value_type = value_type;
b->values[value_id].ptr = ptr;
}

static void
vtn_push_token(struct vtn_builder *b, uint32_t value_id,
enum vtn_value_type value_type)
{
vtn_push_value(b, value_id, value_type, NULL);
}

static char *
vtn_string_literal(struct vtn_builder *b, const uint32_t *words,
unsigned word_count)
{
return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words));
}

typedef void (*decoration_foreach_cb)(struct vtn_builder *,
struct vtn_value *,
const struct vtn_decoration *,
void *);

static void
_foreach_decoration_helper(struct vtn_builder *b,
struct vtn_value *base_value,
struct vtn_value *value,
decoration_foreach_cb cb, void *data)
{
for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) {
if (dec->group) {
assert(dec->group->value_type == vtn_value_type_decoration_group);
_foreach_decoration_helper(b, base_value, dec->group, cb, data);
} else {
cb(b, base_value, dec, data);
}
}
}

/** Iterates (recursively if needed) over all of the decorations on a value
*
* This function iterates over all of the decorations applied to a given
* value. If it encounters a decoration group, it recurses into the group
* and iterates over all of those decorations as well.
*/
static void
vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value,
decoration_foreach_cb cb, void *data)
{
_foreach_decoration_helper(b, value, value, cb, data);
}

static void
vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
switch (opcode) {
case SpvOpDecorationGroup:
vtn_push_token(b, w[1], vtn_value_type_undef);
break;

case SpvOpDecorate: {
struct vtn_value *val = &b->values[w[1]];

struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
dec->decoration = w[2];
dec->literals = &w[3];

/* Link into the list */
dec->next = val->decoration;
val->decoration = dec;
break;
}

case SpvOpGroupDecorate: {
struct vtn_value *group = &b->values[w[1]];
assert(group->value_type == vtn_value_type_decoration_group);

for (unsigned i = 2; i < count; i++) {
struct vtn_value *val = &b->values[w[i]];
struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
dec->group = group;

/* Link into the list */
dec->next = val->decoration;
val->decoration = dec;
}
break;
}

case SpvOpGroupMemberDecorate:
assert(!"Bad instruction. Khronos Bug #13513");
break;

default:
unreachable("Unhandled opcode");
}
}

static void
vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
unreachable("Unhandled opcode");
}

static void
vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
unreachable("Unhandled opcode");
}

static void
vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
unreachable("Unhandled opcode");
}

static void
vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
unreachable("Unhandled opcode");
}

static void
vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
unreachable("Unhandled opcode");
}

static void
vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
switch (opcode) {
case SpvOpSource:
case SpvOpSourceExtension:
case SpvOpMemberName:
case SpvOpLine:
/* Unhandled, but these are for debug so that's ok. */
break;

case SpvOpName:
b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2);
break;

case SpvOpString:
vtn_push_value(b, w[1], vtn_value_type_string,
vtn_string_literal(b, &w[2], count - 2));
break;

case SpvOpUndef:
vtn_push_token(b, w[2], vtn_value_type_undef);
break;

case SpvOpTypeVoid:
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case SpvOpTypeSampler:
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeStruct:
case SpvOpTypeOpaque:
case SpvOpTypePointer:
case SpvOpTypeFunction:
case SpvOpTypeEvent:
case SpvOpTypeDeviceEvent:
case SpvOpTypeReserveId:
case SpvOpTypeQueue:
case SpvOpTypePipe:
vtn_handle_type(b, opcode, w, count);
break;

case SpvOpConstantTrue:
case SpvOpConstantFalse:
case SpvOpConstant:
case SpvOpConstantComposite:
case SpvOpConstantSampler:
case SpvOpConstantNullPointer:
case SpvOpConstantNullObject:
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstant:
case SpvOpSpecConstantComposite:
vtn_handle_constant(b, opcode, w, count);
break;

case SpvOpVariable:
case SpvOpVariableArray:
case SpvOpLoad:
case SpvOpStore:
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpArrayLength:
case SpvOpImagePointer:
vtn_handle_variables(b, opcode, w, count);
break;

case SpvOpDecorationGroup:
case SpvOpDecorate:
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
vtn_handle_decoration(b, opcode, w, count);
break;

case SpvOpTextureSample:
case SpvOpTextureSampleDref:
case SpvOpTextureSampleLod:
case SpvOpTextureSampleProj:
case SpvOpTextureSampleGrad:
case SpvOpTextureSampleOffset:
case SpvOpTextureSampleProjLod:
case SpvOpTextureSampleProjGrad:
case SpvOpTextureSampleLodOffset:
case SpvOpTextureSampleProjOffset:
case SpvOpTextureSampleGradOffset:
case SpvOpTextureSampleProjLodOffset:
case SpvOpTextureSampleProjGradOffset:
case SpvOpTextureFetchTexelLod:
case SpvOpTextureFetchTexelOffset:
case SpvOpTextureFetchSample:
case SpvOpTextureFetchTexel:
case SpvOpTextureGather:
case SpvOpTextureGatherOffset:
case SpvOpTextureGatherOffsets:
case SpvOpTextureQuerySizeLod:
case SpvOpTextureQuerySize:
case SpvOpTextureQueryLod:
case SpvOpTextureQueryLevels:
case SpvOpTextureQuerySamples:
vtn_handle_texture(b, opcode, w, count);
break;

case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpNot:
case SpvOpAny:
case SpvOpAll:
case SpvOpConvertFToU:
case SpvOpConvertFToS:
case SpvOpConvertSToF:
case SpvOpConvertUToF:
case SpvOpUConvert:
case SpvOpSConvert:
case SpvOpFConvert:
case SpvOpConvertPtrToU:
case SpvOpConvertUToPtr:
case SpvOpPtrCastToGeneric:
case SpvOpGenericCastToPtr:
case SpvOpBitcast:
case SpvOpTranspose:
case SpvOpIsNan:
case SpvOpIsInf:
case SpvOpIsFinite:
case SpvOpIsNormal:
case SpvOpSignBitSet:
case SpvOpLessOrGreater:
case SpvOpOrdered:
case SpvOpUnordered:
case SpvOpIAdd:
case SpvOpFAdd:
case SpvOpISub:
case SpvOpFSub:
case SpvOpIMul:
case SpvOpFMul:
case SpvOpUDiv:
case SpvOpSDiv:
case SpvOpFDiv:
case SpvOpUMod:
case SpvOpSRem:
case SpvOpSMod:
case SpvOpFRem:
case SpvOpFMod:
case SpvOpVectorTimesScalar:
case SpvOpMatrixTimesScalar:
case SpvOpVectorTimesMatrix:
case SpvOpMatrixTimesVector:
case SpvOpMatrixTimesMatrix:
case SpvOpOuterProduct:
case SpvOpDot:
case SpvOpShiftRightLogical:
case SpvOpShiftRightArithmetic:
case SpvOpShiftLeftLogical:
case SpvOpLogicalOr:
case SpvOpLogicalXor:
case SpvOpLogicalAnd:
case SpvOpBitwiseOr:
case SpvOpBitwiseXor:
case SpvOpBitwiseAnd:
case SpvOpSelect:
case SpvOpIEqual:
case SpvOpFOrdEqual:
case SpvOpFUnordEqual:
case SpvOpINotEqual:
case SpvOpFOrdNotEqual:
case SpvOpFUnordNotEqual:
case SpvOpULessThan:
case SpvOpSLessThan:
case SpvOpFOrdLessThan:
case SpvOpFUnordLessThan:
case SpvOpUGreaterThan:
case SpvOpSGreaterThan:
case SpvOpFOrdGreaterThan:
case SpvOpFUnordGreaterThan:
case SpvOpULessThanEqual:
case SpvOpSLessThanEqual:
case SpvOpFOrdLessThanEqual:
case SpvOpFUnordLessThanEqual:
case SpvOpUGreaterThanEqual:
case SpvOpSGreaterThanEqual:
case SpvOpFOrdGreaterThanEqual:
case SpvOpFUnordGreaterThanEqual:
case SpvOpDPdx:
case SpvOpDPdy:
case SpvOpFwidth:
case SpvOpDPdxFine:
case SpvOpDPdyFine:
case SpvOpFwidthFine:
case SpvOpDPdxCoarse:
case SpvOpDPdyCoarse:
case SpvOpFwidthCoarse:
vtn_handle_alu(b, opcode, w, count);
break;

default:
unreachable("Unhandled opcode");
}
}

nir_shader *
spirv_to_nir(const uint32_t *words, size_t word_count,
gl_shader_stage stage,
const nir_shader_compiler_options *options)
{
/* Handle the SPIR-V header (first 4 dwords) */
assert(word_count > 5);

assert(words[0] == SpvMagicNumber);
assert(words[1] == 99);
/* words[2] == generator magic */
unsigned value_id_bound = words[3];
assert(words[4] == 0);

words+= 5;

nir_shader *shader = nir_shader_create(NULL, stage, options);

/* Initialize the stn_builder object */
struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
b->shader = shader;
b->value_id_bound = value_id_bound;
b->values = ralloc_array(b, struct vtn_value, value_id_bound);

/* Start handling instructions */
const uint32_t *word_end = words + word_count;
while (words < word_end) {
SpvOp opcode = words[0] & SpvOpCodeMask;
unsigned count = words[0] >> SpvWordCountShift;
assert(words + count <= word_end);

vtn_handle_instruction(b, opcode, words, count);

words += count;
}

ralloc_free(b);

return shader;
}

Loading…
Cancel
Save