shady-gang / shady

Research shading language IR
MIT License
206 stars 11 forks source link

Shady

shady is a small intermediate shading language and compiler for research purposes. It strives to be a testbed for improved GPU programming models, and also provide support for emulating features either missing from SPIR-V, or suffering from poor support.

Shady is ideal for projects that aim to target SPIR-V, but already make use of features that are not found in vanilla Vulkan compute. See feature support below.

Shady is used as part of the AnyDSL to provide experimental Vulkan accelerator support.

Vcc - the Vulkan Clang Compiler

Shady features a front-end called Vcc that calls into Clang and parses the resulting LLVM IR, giving you effectively a C/C++ to SPIR-V compiler.

This project is called 'Shady' and is the IR/middle-end part of Vcc. Vcc currently does live in this repository, inside src/frontends/llvm and src/driver/vcc.c.

This might change later to keep the IR issues tracked separately. Please check out the Vcc website if you have not already.

Feature support

Not all supported features are listed, these are just the more notable ones that are either already working, or are planned.

Platform support

Additionally, the compiler supports alternative backends:

Metal shading language and C backends are on the table in the future.

Compiler design

The grammar is defined in grammar.json, this file is used to define the various nodes in the IR, and generate much of the boilerplate code (node hashing, rewriting, visitors, ...). Some finer concepts are expressed in ir.h or even type.h. There is also a number of x-macros used as "rich" enums.

Language syntax

The textual syntax of the language is C-like in that return types come first. Variance annotations are supported. Overall the language is structurally close to SPIR-V and LLVM, very much on purpose. There is a 'front-end' (slim) variant of the IR that allows for mutable variables and using instructions as values.

// line comments are supported
fn identity varying i32(varying i32 i) {
    return (i);
};

fn f i32(varying i32 i) {
    val j = call(identity, i);
    val k = add(j, 1);
    return (k);
};

const i32 answer = 42;

The textual syntax allows nesting basic blocks inside functions. The syntax is superficially similar to C labels, but with an added parameters list. Note that this is mostly for making handwritten examples look nicer, the actual nesting of functions/continuations is determined by the CFG analysis after name binding.

fn f i32(varying bool b) {
    jump bb1(7);

    cont bb1(varying i32 n) {
        branch (b, bb2(), bb3(n));
    }

    cont bb2() {
        return (0);
    }

    cont bb3(varying i32 n) {
        return (n);
    }
};