@@ 83,10 83,10 @@ impl CContext {
("w".into(), TypeDef::F32),
]));
// f32 -> f32
- s.add_type(&TypeDef::Function(
+ s.add_type(&TypeDef::Function((
vec![TypeDef::F32],
Box::new(TypeDef::F32),
- ));
+ )));
s.add_type(&TypeDef::Bool);
s.add_type(&TypeDef::Unit);
s
@@ 269,7 269,7 @@ impl CContext {
n
}
}
- TypeDef::Function(params, returns) => {
+ TypeDef::Function((params, returns)) => {
if let Some(val) = self.typetable.get(typedef) {
// Function already exists
*val
@@ 351,18 351,13 @@ impl CContext {
.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")
- }
+ let (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)
}
ast::Expr::Block(exprs) => {
assert!(
@@ 576,7 571,7 @@ impl CContext {
// Not sure if SPIR-V can really have function pointers though so idk if they
// can be first-class objects.
// I think this is good now, we treat function types like all the other types.
- let ftype = self.add_type(&def.functiontype);
+ let ftype = self.add_type(&verify::TypeDef::Function(def.functiontype.clone()));
let f_word = self.b.begin_function(
function_returns,
@@ 636,95 631,92 @@ impl CContext {
// Dig up the function def, and declare input/output global vars for it.
// TODO: Name strings for input/output vars?
let def = ctx.get_defined_function(name);
- if let verify::TypeDef::Function(ref params, ref rettype) = def.functiontype {
- // Value, value type, pointer type.
- let input_words: Vec<(spirv::Word, spirv::Word, spirv::Word)> = params
- .iter()
- .enumerate()
- .map(|(i, p)| {
- let t_word = self.get_type(p);
- // We don't bother storing pointer types in our typetable for now,
- // this is basically the only place they're used.
- let t_ptr_word = self
- .b
- .type_pointer(None, spirv::StorageClass::Input, t_word);
- let value_word =
- self.b
- .variable(t_ptr_word, None, spirv::StorageClass::Input, None);
- // Gotta tell it what locations/etc the inputs are.
- // FOR NOW we just enumerate the function args in order.
- self.b.decorate(
- value_word,
- spirv::Decoration::Location,
- [rspirv::mr::Operand::LiteralInt32(u32::try_from(i).unwrap())],
- );
- (value_word, t_word, t_ptr_word)
- })
- .collect();
-
- let (output_word, t_word, _t_ptr_word) = {
- let t_word = self.get_type(rettype);
+ let (ref params, ref rettype) = def.functiontype;
+ // Value, value type, pointer type.
+ let input_words: Vec<(spirv::Word, spirv::Word, spirv::Word)> = params
+ .iter()
+ .enumerate()
+ .map(|(i, p)| {
+ let t_word = self.get_type(p);
+ // We don't bother storing pointer types in our typetable for now,
+ // this is basically the only place they're used.
let t_ptr_word = self
.b
- .type_pointer(None, spirv::StorageClass::Output, t_word);
+ .type_pointer(None, spirv::StorageClass::Input, t_word);
let value_word =
self.b
- .variable(t_ptr_word, None, spirv::StorageClass::Output, None);
- // Output word is always just location=0
+ .variable(t_ptr_word, None, spirv::StorageClass::Input, None);
+ // Gotta tell it what locations/etc the inputs are.
+ // FOR NOW we just enumerate the function args in order.
self.b.decorate(
value_word,
spirv::Decoration::Location,
- [rspirv::mr::Operand::LiteralInt32(0)],
+ [rspirv::mr::Operand::LiteralInt32(u32::try_from(i).unwrap())],
);
(value_word, t_word, t_ptr_word)
- };
+ })
+ .collect();
- // Now actually compile the function that calls our real function.
- let functype_word = self.add_type(&verify::TypeDef::Function(
- vec![],
- Box::new(verify::TypeDef::Unit),
- ));
- let voidtype_word = self.add_type(&verify::TypeDef::Unit);
+ let (output_word, t_word, _t_ptr_word) = {
+ let t_word = self.get_type(rettype);
+ let t_ptr_word = self
+ .b
+ .type_pointer(None, spirv::StorageClass::Output, t_word);
+ let value_word = self
+ .b
+ .variable(t_ptr_word, None, spirv::StorageClass::Output, None);
+ // Output word is always just location=0
+ self.b.decorate(
+ value_word,
+ spirv::Decoration::Location,
+ [rspirv::mr::Operand::LiteralInt32(0)],
+ );
+ (value_word, t_word, t_ptr_word)
+ };
+
+ // Now actually compile the function that calls our real function.
+ let functype_word = self.add_type(&verify::TypeDef::Function((
+ vec![],
+ Box::new(verify::TypeDef::Unit),
+ )));
+ let voidtype_word = self.add_type(&verify::TypeDef::Unit);
- let f_word = self.b.begin_function(
- voidtype_word,
- None,
- spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
- functype_word,
- )?;
- self.b.begin_basic_block(None)?;
- // Load inputs
- let r_inputs: Result<Vec<spirv::Word>, _> = input_words
- .clone()
- .into_iter()
- .map(|(v_word, t_word, _t_ptr_word)| self.b.load(t_word, None, v_word, None, []))
- .collect();
- let inputs = r_inputs?;
- // Call function
- let fun_binding = *self.lookup_var(name);
- let funcall_result_word = self
- .b
- .function_call(t_word, None, fun_binding.address, &inputs)
- .unwrap();
- // Save output
- self.b.store(output_word, funcall_result_word, None, [])?;
- self.b.ret()?;
- self.b.end_function()?;
+ let f_word = self.b.begin_function(
+ voidtype_word,
+ None,
+ spirv::FunctionControl::DONT_INLINE | spirv::FunctionControl::CONST,
+ functype_word,
+ )?;
+ self.b.begin_basic_block(None)?;
+ // Load inputs
+ let r_inputs: Result<Vec<spirv::Word>, _> = input_words
+ .clone()
+ .into_iter()
+ .map(|(v_word, t_word, _t_ptr_word)| self.b.load(t_word, None, v_word, None, []))
+ .collect();
+ let inputs = r_inputs?;
+ // Call function
+ let fun_binding = *self.lookup_var(name);
+ let funcall_result_word = self
+ .b
+ .function_call(t_word, None, fun_binding.address, &inputs)
+ .unwrap();
+ // Save output
+ self.b.store(output_word, funcall_result_word, None, [])?;
+ self.b.ret()?;
+ self.b.end_function()?;
- // We must also return the function's interface, that is, the words of
- // all the global variables it touches.
- let mut interface: Vec<u32> = input_words
- .into_iter()
- .map(|(input_word, _, _)| input_word)
- .collect();
- interface.push(output_word);
+ // We must also return the function's interface, that is, the words of
+ // all the global variables it touches.
+ let mut interface: Vec<u32> = input_words
+ .into_iter()
+ .map(|(input_word, _, _)| input_word)
+ .collect();
+ interface.push(output_word);
- // That's it! The actual OpEntryPoint instructions and names and stuff
- // get handled by the caller.
- Ok((f_word, interface))
- } else {
- unreachable!("Function type is not TypeDef::Function")
- }
+ // That's it! The actual OpEntryPoint instructions and names and stuff
+ // get handled by the caller.
+ Ok((f_word, interface))
}
/// Okay, so SPIR-V is a bit persnickity about entry points.
@@ 79,10 79,10 @@ pub enum TypeDef {
Bool,
Unit,
Struct(Vec<(String, TypeDef)>),
- Function(Vec<TypeDef>, Box<TypeDef>),
+ Function(FunctionType),
}
-//RAR pub type FunctionType = (Vec<TypeDef>, Box<TypeDef>)
+pub type FunctionType = (Vec<TypeDef>, Box<TypeDef>);
/// A function definition; the AST and whatever
/// other information we care about that can get
@@ 90,7 90,7 @@ pub enum TypeDef {
#[derive(Clone, Debug)]
pub struct FunctionDef {
pub decl: FunctionDecl,
- pub functiontype: TypeDef,
+ pub functiontype: FunctionType,
}
/// Verification context.
@@ 267,12 267,12 @@ pub fn verify(program: Vec<Decl>) -> Res
.iter()
.map(|p| ctx.get_defined_type(&p.typ).clone())
.collect();
- let functiontype = TypeDef::Function(param_types, Box::new(return_type.clone()));
+ let functiontype = (param_types, Box::new(return_type.clone()));
// TODO: This is stupid but easy, make it better sometime.
let function_type_name = format!("{:?}", functiontype);
// Functions may define the same type multiple times and it's not an error...
if !ctx.type_exists(&function_type_name) {
- ctx.define_type(&function_type_name, functiontype.clone())?;
+ ctx.define_type(&function_type_name, TypeDef::Function(functiontype.clone()))?;
}
// This clone may be expensive, but it only
// happens once and if the definition fails