Initial work on SPIR-V assembly generation

Atm it only handles the basic metadata in modules.
Doesn't generate code for functions, or types.
Type handling is just a placeholder %undefined_type.
pull/3/head
itycodes 3 weeks ago
parent 3a3d9b46f4
commit 6036a5fe90

@ -0,0 +1,87 @@
#[cfg(test)]
mod tests;
use crate::compiler::Module;
use std::{fmt::Write, ops::Add};
pub fn fix_name(name: &String) -> String {
format!("%{}", name.clone().replace("-", "_"))
}
pub fn spirv_meta(module: Module) -> String {
let mut spirv_asm = String::new();
let mut ops: Vec<(Option<String>, Vec<String>)> = Vec::new();
let capabilities: Vec<String> = module.capabilities.iter()
.map(|c| format!("{:?}", c))
.collect();
for cap in capabilities {
ops.push((None, vec!["OpCapability".to_string(), cap]));
}
let memory_model_address = match module.memory_model.addressing_model {
crate::compiler::AddressingModel::Logical => "Logical",
crate::compiler::AddressingModel::Physical32 => "Physical32",
crate::compiler::AddressingModel::Physical64 => "Physical64",
crate::compiler::AddressingModel::PhysicalStorageBuffer64 => "PhysicalStorageBuffer64",
};
let memory_model_model = match module.memory_model.memory_model {
crate::compiler::MemoryModel::Simple => "Simple",
crate::compiler::MemoryModel::GLSL450 => "GLSL450",
crate::compiler::MemoryModel::OpenCL => "OpenCL",
_ => todo!(),
};
ops.push((None, vec!["OpMemoryModel".to_string(), memory_model_address.to_string(), memory_model_model.to_string()]));
for entry in module.entry_points {
let exec_model = match entry.execution_model {
crate::compiler::ExecutionModel::Fragment => "Fragment",
crate::compiler::ExecutionModel::Vertex => "Vertex",
};
let name = entry.name;
let interface: Vec<String> = entry.interface.iter()
.map(|i| fix_name(&i.to_string()))
.collect();
let exec_mode = match entry.execution_mode {
crate::compiler::ExecutionMode::OriginUpperLeft => "OriginUpperLeft",
};
ops.push((None, vec!["OpEntryPoint".to_string(), exec_model.to_string(), fix_name(&name), format!("\"{}\"", name), interface.join(" ")]));
ops.push((None, vec!["OpExecutionMode".to_string(), fix_name(&name), exec_mode.to_string()]));
}
for global in module.globals {
let name = fix_name(&global.name);
let typ = global.typ;
let storage_class = match global.storage_class {
crate::compiler::StorageClass::Input => "Input",
crate::compiler::StorageClass::Output => "Output",
crate::compiler::StorageClass::Undefined => panic!("Bound a non-declared variable"),
};
let typ_id = "%undefined_type";
ops.push((Some(name.clone()), vec!["OpVariable".to_string(), typ_id.to_string(), storage_class.to_string()]));
for dec in global.decorations {
// Decorations have the format Location 0, or Builtin FragCoord
let dec = match dec {
crate::compiler::Decoration::Location(loc) => format!("Location {}", loc),
crate::compiler::Decoration::BuiltIn(builtin) => {
let builtin = match builtin {
crate::compiler::BuiltinDecoration::FragCoord => "FragCoord",
};
format!("BuiltIn {}", builtin)
},
};
ops.push((None, vec!["OpDecorate".to_string(), name.clone(), dec]));
}
}
for op in ops {
if op.0.is_some() {
write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();
}
for arg in op.1 {
write!(spirv_asm, "{} ", arg).unwrap();
}
writeln!(spirv_asm).unwrap();
}
spirv_asm
}

@ -0,0 +1,25 @@
#[test]
fn test_emit() {
use crate::compiler::*;
use crate::parser::*;
use crate::compiler::backend::*;
let src = "
(module Shader Logical GLSL450)
(import :std GLSL.std.450)
(bind (frag-coord:*v4f32i) (BuiltIn FragCoord))
(bind (out-color:*v4f32o) (Location 0))
(dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output)
(entry main Fragment OriginUpperLeft (:frag-coord :out-color))
(fun (main)
(store-ptr (out-color)
(v4f32i (/ (.xy (load-ptr frag-coord))
(v2f32 1920.0 1080.0))
1.0
1.0)))
";
let mut ast = parse(tokenize(src));
let module = meta_compile(&mut ast);
let res = spirv_meta(module);
println!("{}", res);
}

@ -1,5 +1,7 @@
use crate::parser::Ast;
pub mod backend;
#[cfg(test)]
mod tests;
@ -18,7 +20,8 @@ pub enum ExecutionMode {
#[derive(Debug, PartialEq, Default, Clone)]
pub enum ExecutionModel {
#[default]
Fragment
Fragment,
Vertex,
}
#[derive(Debug, PartialEq, Default, Clone)]
@ -60,7 +63,7 @@ pub enum BuiltinDecoration {
#[derive(Debug, PartialEq, Clone)]
pub enum Decoration {
Builtin(BuiltinDecoration),
BuiltIn(BuiltinDecoration),
Location(u32),
}
@ -175,7 +178,7 @@ pub fn meta_compile(ast: &mut Ast) -> Module {
}
}).collect();
let bind_name = match bind[0].as_str() {
"Builtin" => Decoration::Builtin(BuiltinDecoration::FragCoord),
"BuiltIn" => Decoration::BuiltIn(BuiltinDecoration::FragCoord),
"Location" => Decoration::Location(bind[1].parse::<u32>().unwrap()),
_ => panic!("Unknown bind! {:?}", bind),
};
@ -249,7 +252,9 @@ pub fn meta_compile(ast: &mut Ast) -> Module {
};
let interface: Vec<String> = interface.iter().map(|x| {
match x {
Ast::Symbol(s) => s.to_string(),
Ast::Symbol(s) => {
s.to_string().replace(":", "")
},
_ => panic!("Expected symbol! {:?}", x),
}
}).collect();

@ -6,7 +6,7 @@ fn test_compile() {
let src = "
(module Shader Logical GLSL450)
(import :std GLSL.std.450)
(bind (frag-coord:*v4f32i) (Builtin FragCoord))
(bind (frag-coord:*v4f32i) (BuiltIn FragCoord))
(bind (out-color:*v4f32o) (Location 0))
(dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output)
@ -22,7 +22,6 @@ fn test_compile() {
println!("{:#?}", ast);
let module = meta_compile(&mut ast);
println!("{:#?}", module);
//let test_module: Module = Module { capabilities: [Shader], entry_points: [EntryPoint { execution_model: Fragment, execution_mode: OriginUpperLeft, name: "main", interface: [":frag-coord", ":out-color"] }], globals: [GlobalVariable { name: "frag-coord", typ: "*v4f32i", storage_class: Input, decorations: [Builtin(FragCoord)] }, GlobalVariable { name: "out-color", typ: "*v4f32o", storage_class: Output, decorations: [Location(0)] }], functions: [Function { name: "main", return_type: "void", arguments: [], body: Some([]), ast: Some(List([List([Symbol("store-ptr"), List([Symbol("out-color")]), List([Symbol("v4f32i"), List([Symbol("/"), List([Symbol(".xy"), List([Symbol("load-ptr"), Symbol("frag-coord")])]), List([Symbol("v2f32"), Symbol("1920.0"), Symbol("1080.0")])]), Symbol("1.0"), Symbol("1.0")])])])) }], memory_model: Memory { addressing_model: Logical, memory_model: GLSL450 }, imports: [Import { name: ":std", value: "GLSL.std.450" }] };
let test_module = Module {
capabilities: vec![Capability::Shader],
entry_points: vec![EntryPoint {
@ -36,7 +35,7 @@ fn test_compile() {
name: "frag-coord".to_string(),
typ: "*v4f32i".to_string(),
storage_class: StorageClass::Input,
decorations: vec![Decoration::Builtin(BuiltinDecoration::FragCoord)],
decorations: vec![Decoration::BuiltIn(BuiltinDecoration::FragCoord)],
},
GlobalVariable {
name: "out-color".to_string(),

@ -22,7 +22,7 @@ fn test_parse() {
let src = "
(module Shader Logical GLSL450)
(import :std GLSL.std.450)
(bind (frag-coord:*v4f32i) (Builtin FragCoord))
(bind (frag-coord:*v4f32i) (BuiltIn FragCoord))
(bind (out-color:*v4f32o) (Location 0))
(dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output)
@ -54,7 +54,7 @@ fn test_parse() {
Ast::Symbol("frag-coord:*v4f32i".to_string()),
]),
Ast::List(vec![
Ast::Symbol("Builtin".to_string()),
Ast::Symbol("BuiltIn".to_string()),
Ast::Symbol("FragCoord".to_string()),
]),
]),

Loading…
Cancel
Save