#ifndef _VTN_PRIVATE_H_
#define _VTN_PRIVATE_H_
+#include <setjmp.h>
+
#include "nir/nir.h"
#include "nir/nir_builder.h"
#include "util/u_dynarray.h"
struct vtn_builder;
struct vtn_decoration;
+void vtn_log(struct vtn_builder *b, enum nir_spirv_debug_level level,
+ size_t spirv_offset, const char *message);
+
+void vtn_logf(struct vtn_builder *b, enum nir_spirv_debug_level level,
+ size_t spirv_offset, const char *fmt, ...) PRINTFLIKE(4, 5);
+
+#define vtn_info(...) vtn_logf(b, NIR_SPIRV_DEBUG_LEVEL_INFO, 0, __VA_ARGS__)
+
+void _vtn_warn(struct vtn_builder *b, const char *file, unsigned line,
+ const char *fmt, ...) PRINTFLIKE(4, 5);
+#define vtn_warn(...) _vtn_warn(b, __FILE__, __LINE__, __VA_ARGS__)
+
+/** Fail SPIR-V parsing
+ *
+ * This function logs an error and then bails out of the shader compile using
+ * longjmp. This being safe relies on two things:
+ *
+ * 1) We must guarantee that setjmp is called after allocating the builder
+ * and setting up b->debug (so that logging works) but before before any
+ * errors have a chance to occur.
+ *
+ * 2) While doing the SPIR-V -> NIR conversion, we need to be careful to
+ * ensure that all heap allocations happen through ralloc and are parented
+ * to the builder. This way they will get properly cleaned up on error.
+ *
+ * 3) We must ensure that _vtn_fail is never called while a mutex lock or a
+ * reference to any other resource is held with the exception of ralloc
+ * objects which are parented to the builder.
+ *
+ * So long as these two things continue to hold, we can easily longjmp back to
+ * spirv_to_nir(), clean up the builder, and return NULL.
+ */
+void _vtn_fail(struct vtn_builder *b, const char *file, unsigned line,
+ const char *fmt, ...) NORETURN PRINTFLIKE(4, 5);
+#define vtn_fail(...) _vtn_fail(b, __FILE__, __LINE__, __VA_ARGS__)
+
+/** Fail if the given expression evaluates to true */
+#define vtn_fail_if(expr, ...) \
+ do { \
+ if (unlikely(expr)) \
+ vtn_fail(__VA_ARGS__); \
+ } while (0)
+
+/** Assert that a condition is true and, if it isn't, vtn_fail
+ *
+ * This macro is transitional only and should not be used in new code. Use
+ * vtn_fail_if and provide a real message instead.
+ */
+#define vtn_assert(expr) \
+ do { \
+ if (!likely(expr)) \
+ vtn_fail("%s", #expr); \
+ } while (0)
+
enum vtn_value_type {
vtn_value_type_invalid = 0,
vtn_value_type_undef,
struct vtn_function {
struct exec_node node;
+ bool referenced;
+ bool emitted;
+
nir_function_impl *impl;
struct vtn_block *start_block;
vtn_base_type_pointer,
vtn_base_type_image,
vtn_base_type_sampler,
+ vtn_base_type_sampled_image,
vtn_base_type_function,
};
const struct glsl_type *type;
- /* The value that declares this type. Used for finding decorations */
- struct vtn_value *val;
+ /* The SPIR-V id of the given type. */
+ uint32_t id;
- /* Specifies the length of complex types. */
+ /* Specifies the length of complex types.
+ *
+ * For Workgroup pointers, this is the size of the referenced type.
+ */
unsigned length;
+ /* for arrays, matrices and pointers, the array stride */
+ unsigned stride;
+
union {
/* Members for scalar, vector, and array-like types */
struct {
/* for arrays, the vtn_type for the elements of the array */
struct vtn_type *array_element;
- /* for arrays and matrices, the array stride */
- unsigned stride;
-
/* for matrices, whether the matrix is stored row-major */
bool row_major:1;
/* Storage class for pointers */
SpvStorageClass storage_class;
+
+ /* Required alignment for pointers */
+ uint32_t align;
};
/* Members for image types */
SpvAccessQualifier access_qualifier;
};
+ /* Members for sampled image types */
+ struct {
+ /* For sampled images, the image type */
+ struct vtn_type *image;
+ };
+
/* Members for function types */
struct {
/* For functions, the vtn_type for each parameter */
};
};
+bool vtn_types_compatible(struct vtn_builder *b,
+ struct vtn_type *t1, struct vtn_type *t2);
+
struct vtn_variable;
enum vtn_access_mode {
struct vtn_access_chain {
uint32_t length;
+ /** Whether or not to treat the base pointer as an array. This is only
+ * true if this access chain came from an OpPtrAccessChain.
+ */
+ bool ptr_as_array;
+
/** Struct elements and array offsets.
*
* This is an array of 1 so that it can conveniently be created on the
nir_variable *var;
nir_variable **members;
+ int shared_location;
+
/**
* In some early released versions of GLSLang, it implemented all function
* calls by making copies of all parameters into temporary variables and
};
struct vtn_sampled_image {
+ struct vtn_type *type;
struct vtn_pointer *image; /* Image or array of images */
struct vtn_pointer *sampler; /* Sampler */
};
enum vtn_value_type value_type;
const char *name;
struct vtn_decoration *decoration;
+ struct vtn_type *type;
union {
void *ptr;
char *str;
- struct vtn_type *type;
- struct {
- nir_constant *constant;
- const struct glsl_type *const_type;
- };
+ nir_constant *constant;
struct vtn_pointer *pointer;
struct vtn_image_pointer *image;
struct vtn_sampled_image *sampled_image;
struct vtn_builder {
nir_builder nb;
+ /* Used by vtn_fail to jump back to the beginning of SPIR-V compilation */
+ jmp_buf fail_jump;
+
+ const uint32_t *spirv;
+ size_t spirv_word_count;
+
nir_shader *shader;
- nir_function_impl *impl;
- const struct nir_spirv_supported_extensions *ext;
+ const struct spirv_to_nir_options *options;
struct vtn_block *block;
- /* Current file, line, and column. Useful for debugging. Set
+ /* Current offset, file, line, and column. Useful for debugging. Set
* automatically by vtn_foreach_instruction.
*/
+ size_t spirv_offset;
char *file;
int line, col;
bool has_loop_continue;
};
+nir_ssa_def *
+vtn_pointer_to_ssa(struct vtn_builder *b, struct vtn_pointer *ptr);
+struct vtn_pointer *
+vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa,
+ struct vtn_type *ptr_type);
+
+static inline struct vtn_value *
+vtn_untyped_value(struct vtn_builder *b, uint32_t value_id)
+{
+ vtn_fail_if(value_id >= b->value_id_bound,
+ "SPIR-V id %u is out-of-bounds", value_id);
+ return &b->values[value_id];
+}
+
static inline struct vtn_value *
vtn_push_value(struct vtn_builder *b, uint32_t value_id,
enum vtn_value_type value_type)
{
- assert(value_id < b->value_id_bound);
- assert(b->values[value_id].value_type == vtn_value_type_invalid);
+ struct vtn_value *val = vtn_untyped_value(b, value_id);
- b->values[value_id].value_type = value_type;
+ vtn_fail_if(val->value_type != vtn_value_type_invalid,
+ "SPIR-V id %u has already been written by another instruction",
+ value_id);
+ val->value_type = value_type;
return &b->values[value_id];
}
static inline struct vtn_value *
-vtn_untyped_value(struct vtn_builder *b, uint32_t value_id)
+vtn_push_ssa(struct vtn_builder *b, uint32_t value_id,
+ struct vtn_type *type, struct vtn_ssa_value *ssa)
{
- assert(value_id < b->value_id_bound);
- return &b->values[value_id];
+ struct vtn_value *val;
+ if (type->base_type == vtn_base_type_pointer) {
+ val = vtn_push_value(b, value_id, vtn_value_type_pointer);
+ val->pointer = vtn_pointer_from_ssa(b, ssa->def, type);
+ } else {
+ val = vtn_push_value(b, value_id, vtn_value_type_ssa);
+ val->ssa = ssa;
+ }
+ return val;
}
static inline struct vtn_value *
enum vtn_value_type value_type)
{
struct vtn_value *val = vtn_untyped_value(b, value_id);
- assert(val->value_type == value_type);
+ vtn_fail_if(val->value_type != value_type,
+ "SPIR-V id %u is the wrong kind of value", value_id);
return val;
}
-void _vtn_warn(const char *file, int line, const char *msg, ...);
-#define vtn_warn(...) _vtn_warn(__FILE__, __LINE__, __VA_ARGS__)
+bool
+vtn_set_instruction_result_type(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count);
+
+static inline nir_constant *
+vtn_constant_value(struct vtn_builder *b, uint32_t value_id)
+{
+ return vtn_value(b, value_id, vtn_value_type_constant)->constant;
+}
struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
vtn_execution_mode_foreach_cb cb, void *data);
-nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
+nir_op vtn_nir_alu_op_for_spirv_opcode(struct vtn_builder *b,
+ SpvOp opcode, bool *swap,
nir_alu_type src, nir_alu_type dst);
void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count);
+void vtn_handle_subgroup(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count);
+
bool vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode,
const uint32_t *words, unsigned count);
+static inline uint32_t
+vtn_align_u32(uint32_t v, uint32_t a)
+{
+ assert(a != 0 && a == (a & -a));
+ return (v + a - 1) & ~(a - 1);
+}
+
static inline uint64_t
vtn_u64_literal(const uint32_t *w)
{