[Mesa-dev] [PATCH 7/9] spirv: Add vtn_fail and vtn_assert helpers
Jason Ekstrand
jason at jlekstrand.net
Wed Sep 6 00:57:02 UTC 2017
On Tue, Sep 5, 2017 at 5:32 PM, Ian Romanick <idr at freedesktop.org> wrote:
> On 08/17/2017 10:22 AM, Jason Ekstrand wrote:
> > These helpers are much nicer than just using assert because they don't
> > kill your process. Instead, it longjmps back to spirv_to_nir(), cleans
> > up all the temporary memory, and nicely returns NULL. While crashing is
> > completely OK in the Vulkan world, it's not considered to be quite so
> > nice in GL. This should help us to make SPIR-V parsing much more
> > robust. The one downside here is that vtn_assert is not compiled out in
> > release builds like assert() is so it isn't free.
> > ---
> > src/compiler/spirv/spirv_to_nir.c | 20 ++++++++++++++++++++
> > src/compiler/spirv/vtn_private.h | 31 +++++++++++++++++++++++++++++++
> > 2 files changed, 51 insertions(+)
> >
> > diff --git a/src/compiler/spirv/spirv_to_nir.c
> b/src/compiler/spirv/spirv_to_nir.c
> > index e59f2b2..af542e8 100644
> > --- a/src/compiler/spirv/spirv_to_nir.c
> > +++ b/src/compiler/spirv/spirv_to_nir.c
> > @@ -104,6 +104,20 @@ _vtn_warn(struct vtn_builder *b, const char *file,
> unsigned line,
> > va_end(args);
> > }
> >
> > +void
> > +_vtn_fail(struct vtn_builder *b, const char *file, unsigned line,
> > + const char *fmt, ...)
> > +{
> > + va_list args;
> > +
> > + va_start(args, fmt);
> > + vtn_log_err(b, NIR_SPIRV_DEBUG_LEVEL_ERROR, "SPIR-V parsing
> FAILED:\n",
> > + file, line, fmt, args);
> > + va_end(args);
> > +
> > + longjmp(b->fail_jump, 1);
> > +}
> > +
> > struct spec_constant_value {
> > bool is_double;
> > union {
> > @@ -3420,6 +3434,12 @@ spirv_to_nir(const uint32_t *words, size_t
> word_count,
> > b->entry_point_name = entry_point_name;
> > b->ext = ext;
> >
> > + /* See also _vtn_fail() */
> > + if (setjmp(b->fail_jump)) {
> > + ralloc_free(b);
> > + return NULL;
> > + }
> > +
> > const uint32_t *word_end = words + word_count;
> >
> > /* Handle the SPIR-V header (first 4 dwords) */
> > diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_
> private.h
> > index 3eb601d..f640289 100644
> > --- a/src/compiler/spirv/vtn_private.h
> > +++ b/src/compiler/spirv/vtn_private.h
> > @@ -28,6 +28,8 @@
> > #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"
> > @@ -49,6 +51,32 @@ 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.
> > + *
> > + * 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__)
> > +
> > +#define vtn_assert(expr) \
> > + do { \
> > + if (!likely(expr)) \
> > + vtn_fail("%s", #expr); \
> > + } while (0)
>
> I'm not a huge fan of this particular detail. When you see "assert" in
> a name, that carries a bunch of implicit information with it. In this
> case, that information is, by design, not true. Primarily, it does
> happen in release builds. It does still lead to an abrupt failure, but
> a different sort. Maybe vtn_fail_when() would be better... the down
> side of that is all the conditions would have to inverted in the next
> patch. Ugh.
>
Yeah, I understand both of those reservations. The one that concerns me
the most is that it happens in debug builds; that's definitely unexpected.
As far as aborting, it does perform a full stop, it's just not quite the
same. I'd be ok with switching over to something else. How about
vtn_fail_if? Or maybe we could follow the perl pattern and do
vtn_or_fail. Thoughs?
> For that reason, it makes me uncomfortable when I see things with
> side-effects in a thing called foo_assert() (the SpvOpExtInst in the
> next patch).
>
Yeah, the side-effects are a bit desturbing. I'm happy to change that.
> Hm... I'm not sure what to suggest, and this series has been out for a
> couple weeks. What are your thoughts?
>
No worries. I'm not in too much of a rush. But being in a little bit of a
rush can sometimes encourage patch review to actually happen. :-) Thanks!
--Jason
> > +
> > enum vtn_value_type {
> > vtn_value_type_invalid = 0,
> > vtn_value_type_undef,
> > @@ -474,6 +502,9 @@ struct vtn_decoration {
> > 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;
> >
> > nir_shader *shader;
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170905/6c644af8/attachment-0001.html>
More information about the mesa-dev
mailing list