# HG changeset patch # User Simon Heath # Date 1565379256 14400 # Fri Aug 09 15:34:16 2019 -0400 # Node ID ef91dd42beb91c57282036b611571b5e159d3623 # Parent 25a8ba2f6b8bd3a66e5c83bac8cd1e1944239e4e cleanup diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -66,21 +66,28 @@ * 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: diff --git a/examples/rendy.rs b/examples/rendy.rs --- a/examples/rendy.rs +++ b/examples/rendy.rs @@ -23,12 +23,18 @@ 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"), diff --git a/src/compile/mod.rs b/src/compile/mod.rs --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -144,6 +144,7 @@ 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 @@ } } } - /* - *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 @@ 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 @@ } 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, _> = params - .clone() - .iter() - .map(|param| self.compile_expr(param, ctx)) - .collect(); - let param_words = param_words?; - let param_words: Vec = 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 @@ } 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. diff --git a/src/lib.rs b/src/lib.rs --- a/src/lib.rs +++ b/src/lib.rs @@ -55,14 +55,6 @@ 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();