4 files changed, 22 insertions(+), 189 deletions(-)

M README.md
M examples/rendy.rs
M src/compile/mod.rs
M src/lib.rs
M README.md +9 -2
@@ 66,21 66,28 @@ Actually to do:
 
  * Replace unwrap with expect.
  * Ponder error handling better.
+ * Replace strings with interned symbols
+ * General cleanup
+ * Ponder vector operations
  * Get entry points working better.
- * Make an actual CLI -- final generated code testing with `spirv-val` maybe should be part of that?
  * Names/labels/stuff for better debugging.
+ * idk mang make a parser or something?
 
 To think about:
 
  * Vector swizzling -- do we need it?  Can we just do it all with
    pattern matching?  Let's try.
  * Vector types -- can they just be structs?  That would work well
-   with pattern matching.
+   with pattern matching.  But vec's are a special case in spir-v anyway.
  * Enums/option types
  * Structure layouts and binding
  * Loops (recursion?)
  * Math and type system
  * Play with fuzzing?
+ * Make more shader built-in state accessible?
+   https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap14.html#interfaces-builtin-variables
+ * Better handling of locations, bindings, groups, etc.
+
 
 To compare against code generated by a (hopefully) known-valid compiler:
 

          
M examples/rendy.rs +12 -6
@@ 23,12 23,18 @@ fn compile_shader() -> Vec<u8> {
     use ch::ast::*;
     let vert = Decl::Function(FunctionDecl {
         name: String::from("vertex"),
-        params: vec![Param {
-            name: "i".into(),
-            typ: Type("F32".into()),
-        }],
-        returns: Type("F32".into()),
-        body: vec![Expr::Var("i".into())],
+        params: vec![
+            Param {
+                name: "pos".into(),
+                typ: Type("Vec4F".into()),
+            },
+            Param {
+                name: "color".into(),
+                typ: Type("Vec4F".into()),
+            },
+        ],
+        returns: Type("Vec4F".into()),
+        body: vec![Expr::Var("color".into())],
     });
     let frag = Decl::Function(FunctionDecl {
         name: String::from("fragment"),

          
M src/compile/mod.rs +1 -173
@@ 144,6 144,7 @@ impl CContext {
         let consts = &mut self.consts;
         // Entry API doesn't work here 'cause we might have to recursively
         // make several modifications to the type table.
+        // TODO: ...really, Vec4F is more of a constructor than a literal...
         if let Some(res) = consts.get(&vl) {
             *res
         } else {

          
@@ 175,35 176,6 @@ impl CContext {
                 }
             }
         }
-        /*
-                *consts.entry(vl.clone()).or_insert_with(|| match vl {
-                    ast::Lit::F32(f) => b.constant_f32(type_float, f),
-                    ast::Lit::Bool(bl) => {
-                        if bl {
-                            b.constant_true(type_bool)
-                        } else {
-                            b.constant_false(type_bool)
-                        }
-                    }
-                    ast::Lit::Vec4F(x, y, z, w) => {
-                        let components = [
-                            self.define_const(ast::Lit::F32(x)),
-                            self.define_const(ast::Lit::F32(y)),
-                            self.define_const(ast::Lit::F32(z)),
-                            self.define_const(ast::Lit::F32(w)),
-                        ];
-                        b.constant_composite(type_vec4f, &components)
-                    }
-                    // TODO: This is WRONG WRONG WRONG but
-                    // I'm not entirely sure how to make it right
-                    // yet.  Unit is not actually a value, so.
-                    ast::Lit::Unit => {
-                        unimplemented!();
-                        0
-                        //b.constant_null(type_unit),
-                    }
-                })
-        */
     }
 
     /// Panics if the type does not exist.

          
@@ 324,22 296,6 @@ impl CContext {
                 let var_typedef = ctx.get_defined_type(&typ);
                 let var_typeword = self.get_type(var_typedef);
                 assert_eq!(expr_type_word, var_typeword);
-                // Allocate space for a variable
-                //
-                // TODO: I AM NOT CONVINCED that this is necessary,
-                // since our values are all immutable!  We might be
-                // able to just store the result value word of an
-                // expression directly into our scope block and not
-                // actually explicitly allocate local vars.
-                // But glslang does it this way so for now we follow
-                // its example.
-                /*
-                let var_addr =
-                    self.b
-                        .variable(var_typeword, None, spirv::StorageClass::Function, None);
-                // Save the result of the expression to the var.
-                self.b.store(var_addr, value_word, None, [])?;
-                 */
                 // TODO: For now, we don't actually implement any
                 // pattern matching.
                 match pattern {

          
@@ 755,70 711,6 @@ impl CContext {
         } else {
             unreachable!("Function type is not TypeDef::Function")
         }
-
-        /*
-                let ftype = self.add_type(&verify::TypeDef::Function(
-                    vec![],
-                    Box::new(verify::TypeDef::Unit),
-                ));
-                let void = self.add_type(&verify::TypeDef::Unit);
-
-                // Actually make our stub functions
-                let v_word = self.b.begin_function(
-                    void,
-                    None,
-                    spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
-                    ftype,
-                )?;
-                self.b.begin_basic_block(None)?;
-                self.b.ret()?;
-                self.b.end_function()?;
-
-                let f_word = self.b.begin_function(
-                    void,
-                    None,
-                    spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
-                    ftype,
-                )?;
-                self.b.begin_basic_block(None)?;
-                self.b.ret()?;
-                self.b.end_function()?;
-
-
-                // Compile arguments
-                let param_words: Result<Vec<(spirv::Word, spirv::Word)>, _> = params
-                    .clone()
-                    .iter()
-                    .map(|param| self.compile_expr(param, ctx))
-                    .collect();
-                let param_words = param_words?;
-                let param_words: Vec<spirv::Word> = param_words
-                    .into_iter()
-                    .map(|(value_word, _type_word)| value_word)
-                    .collect();
-                // Look up function word
-                // ...which requires having compiled the function first.  :|
-                // TODO: Fix!  Somehow...  If it isn't, this will panic
-                // with variable not found.
-                let binding = *self.lookup_var(&fname);
-                // Get the function's return type.  We have to fetch this
-                // from the VContext, since we can't really dig it back
-                // out of the SPIR-V.
-                let functiondef = ctx
-                    .functions
-                    .get(fname)
-                    .expect("Function does not exist for funcall");
-                if let verify::TypeDef::Function(ref _params, ref rettype) = functiondef.functiontype {
-                    // TODO: Tail call optimization would go here if it went anywhere.
-                    let rettype_word = self.get_type(rettype);
-                    let value_word =
-                        self.b
-                            .function_call(rettype_word, None, binding.address, param_words)?;
-                    (value_word, rettype_word)
-                } else {
-                    unreachable!("Function type is not TypeDef::Function")
-                }
-        */
     }
 
     /// Okay, so SPIR-V is a bit persnickity about entry points.

          
@@ 856,70 748,6 @@ impl CContext {
         }
 
         Ok(())
-
-        /*
-                let frag_name = "_fragment_entry";
-                self.b.name(f_word, frag_name);
-                self.b
-                    .entry_point(spirv::ExecutionModel::Vertex, v_word, vert_name, []);
-
-                let ftype = self.add_type(&verify::TypeDef::Function(
-                    vec![],
-                    Box::new(verify::TypeDef::Unit),
-                ));
-                let void = self.add_type(&verify::TypeDef::Unit);
-
-                // Actually make our stub functions
-                let v_word = self.b.begin_function(
-                    void,
-                    None,
-                    spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
-                    ftype,
-                )?;
-                self.b.begin_basic_block(None)?;
-                self.b.ret()?;
-                self.b.end_function()?;
-
-                let f_word = self.b.begin_function(
-                    void,
-                    None,
-                    spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
-                    ftype,
-                )?;
-                self.b.begin_basic_block(None)?;
-                self.b.ret()?;
-                self.b.end_function()?;
-
-                // We're allowed to reuse the same function as different
-                // entry points, so I guess we'll just do that for now
-                let vert_name = "_vertex_entry";
-                let frag_name = "_fragment_entry";
-                self.b.name(v_word, vert_name);
-                self.b.name(f_word, frag_name);
-                self.b
-                    .entry_point(spirv::ExecutionModel::Vertex, v_word, vert_name, []);
-                self.b
-                    .entry_point(spirv::ExecutionModel::Fragment, f_word, frag_name, []);
-                // TODO: Heck, what the heck to do with this??
-                // Well, GLSL uses OriginUpperLeft, so let's do that for now.
-                self.b
-                    .execution_mode(f_word, spirv::ExecutionMode::OriginUpperLeft, []);
-
-                Ok(())
-        */
-        /*
-        // If this function is an entry point we declare it such.
-        // TODO: This is a little jank but works.
-        if def.decl.name == "vertex" {
-            // Now if the function is an entry point we need to also add
-            // global variables that form the inputs to it...
-            self.b
-                .entry_point(spirv::ExecutionModel::Vertex, f_word, "vertex", []);
-        } else if def.decl.name == "fragment" {
-            self.b
-                .entry_point(spirv::ExecutionModel::Fragment, f_word, "vertex", []);
-        }
-        */
     }
 
     /// Returns the generated output instructions.

          
M src/lib.rs +0 -8
@@ 55,14 55,6 @@ pub fn words_to_bytes_le(words: &[u32]) 
     all the solutions I can come up with borrow it first
     when I want to move it.  Oh well, we do it the dumb way.
      */
-    /*
-    words
-        .iter()
-        .copied()
-        .flat_map(|word| word.to_le_bytes().into_iter())
-        .cloned()
-        .collect()
-     */
     let mut res = Vec::with_capacity(words.len() * 4);
     for word in words {
         let bytes = word.to_le_bytes();