|
|
|
@ -1,11 +1,11 @@
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
|
|
use crate::compiler::Module;
|
|
|
|
|
use std::fmt;
|
|
|
|
|
use std::fmt::Write;
|
|
|
|
|
|
|
|
|
|
use super::StorageClass;
|
|
|
|
|
use crate::compiler::{
|
|
|
|
|
AddressingModel, BuiltinDecoration, Decoration, ExecutionMode, ExecutionModel, MemoryModel,
|
|
|
|
|
Module, StorageClass,
|
|
|
|
|
};
|
|
|
|
|
use std::fmt::{self, Write};
|
|
|
|
|
|
|
|
|
|
use crate::parser::Ast;
|
|
|
|
|
|
|
|
|
@ -44,48 +44,43 @@ pub fn parse_type(typ: &String) -> Type {
|
|
|
|
|
// So, *v4f32i is a pointer to a vector of 4 floats, with the storage class Input.
|
|
|
|
|
// *v4f32o is a pointer to a vector of 4 floats, with the storage class Output.
|
|
|
|
|
|
|
|
|
|
let c = typ.chars().next().unwrap();
|
|
|
|
|
match c {
|
|
|
|
|
'<' => {
|
|
|
|
|
let mut chars = typ.chars();
|
|
|
|
|
match chars.next() {
|
|
|
|
|
Some('<') => {
|
|
|
|
|
assert_eq!(typ.as_str(), "<>");
|
|
|
|
|
Type::Void
|
|
|
|
|
}
|
|
|
|
|
'*' => {
|
|
|
|
|
let mut chars = typ.chars();
|
|
|
|
|
chars.next();
|
|
|
|
|
let typ = chars.collect::<String>();
|
|
|
|
|
let storage_class = match typ.chars().last().unwrap() {
|
|
|
|
|
'i' => StorageClass::Input,
|
|
|
|
|
'o' => StorageClass::Output,
|
|
|
|
|
Some('*') => {
|
|
|
|
|
let mut typ = chars.collect::<String>();
|
|
|
|
|
let storage_class = match typ.pop() {
|
|
|
|
|
Some('i') => StorageClass::Input,
|
|
|
|
|
Some('o') => StorageClass::Output,
|
|
|
|
|
_ => panic!("Invalid storage class"),
|
|
|
|
|
};
|
|
|
|
|
let typ = typ.chars().take(typ.len() - 1).collect::<String>();
|
|
|
|
|
Type::Pointer(Box::new(parse_type(&typ)), storage_class)
|
|
|
|
|
}
|
|
|
|
|
'v' => {
|
|
|
|
|
let mut chars = typ.chars();
|
|
|
|
|
chars.next();
|
|
|
|
|
let size = chars.next().unwrap().to_digit(10).unwrap();
|
|
|
|
|
Some('v') => {
|
|
|
|
|
let size = chars.next().map(|s| s.to_digit(10)).flatten().unwrap();
|
|
|
|
|
let typ = chars.collect::<String>();
|
|
|
|
|
Type::Vector(Box::new(parse_type(&typ)), size)
|
|
|
|
|
}
|
|
|
|
|
'f' => {
|
|
|
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
|
|
|
Some('f') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
Type::Float(size)
|
|
|
|
|
}
|
|
|
|
|
's' => {
|
|
|
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
|
|
|
Some('s') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
Type::Int(size)
|
|
|
|
|
}
|
|
|
|
|
'u' => {
|
|
|
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
|
|
|
Some('u') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
Type::Unsigned(size)
|
|
|
|
|
}
|
|
|
|
|
_ => panic!("Invalid type"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
fn emit_type(typ: &Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
match &typ {
|
|
|
|
|
Type::Void => {
|
|
|
|
|
ops.push(("%void".to_string(), "OpTypeVoid".to_string()));
|
|
|
|
@ -109,18 +104,14 @@ fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
Type::Vector(in_typ, size) => {
|
|
|
|
|
emit_type(*in_typ.clone(), ops);
|
|
|
|
|
emit_type(in_typ, ops);
|
|
|
|
|
ops.push((
|
|
|
|
|
fix_name(&typ.to_string()),
|
|
|
|
|
format!(
|
|
|
|
|
"OpTypeVector {} {}",
|
|
|
|
|
fix_name(&in_typ.clone().to_string()),
|
|
|
|
|
size
|
|
|
|
|
),
|
|
|
|
|
format!("OpTypeVector {} {}", fix_name(&in_typ.to_string()), size),
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
Type::Pointer(in_typ, storage_class) => {
|
|
|
|
|
emit_type(*in_typ.clone(), ops);
|
|
|
|
|
emit_type(in_typ, ops);
|
|
|
|
|
let typ_id = fix_name(&typ.to_string());
|
|
|
|
|
let storage_class = match storage_class {
|
|
|
|
|
StorageClass::Input => "Input",
|
|
|
|
@ -139,23 +130,19 @@ fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn fix_name(name: &String) -> String {
|
|
|
|
|
fn fix_name(name: &str) -> String {
|
|
|
|
|
format!(
|
|
|
|
|
"%{}",
|
|
|
|
|
name.clone()
|
|
|
|
|
.replace("-", "_")
|
|
|
|
|
name.replace("-", "_")
|
|
|
|
|
.replace("*", "p")
|
|
|
|
|
.replace("<>", "void")
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn has_id(name: String, ops: &Vec<(Option<String>, Vec<String>)>) -> bool {
|
|
|
|
|
for op in ops {
|
|
|
|
|
if op.0.is_some() && op.0.clone().unwrap() == name {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
fn has_id(name: &str, ops: &Vec<(Option<String>, Vec<String>)>) -> bool {
|
|
|
|
|
ops.iter()
|
|
|
|
|
.find(|op| op.0.as_ref().map(|s| *s == name).unwrap_or(false))
|
|
|
|
|
.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn spirv_meta(module: Module) -> String {
|
|
|
|
@ -172,15 +159,15 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
|
AddressingModel::Logical => "Logical",
|
|
|
|
|
AddressingModel::Physical32 => "Physical32",
|
|
|
|
|
AddressingModel::Physical64 => "Physical64",
|
|
|
|
|
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",
|
|
|
|
|
MemoryModel::Simple => "Simple",
|
|
|
|
|
MemoryModel::GLSL450 => "GLSL450",
|
|
|
|
|
MemoryModel::OpenCL => "OpenCL",
|
|
|
|
|
_ => todo!(),
|
|
|
|
|
};
|
|
|
|
|
ops.push((
|
|
|
|
@ -194,8 +181,8 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
|
|
|
|
|
for entry in module.entry_points {
|
|
|
|
|
let exec_model = match entry.execution_model {
|
|
|
|
|
crate::compiler::ExecutionModel::Fragment => "Fragment",
|
|
|
|
|
crate::compiler::ExecutionModel::Vertex => "Vertex",
|
|
|
|
|
ExecutionModel::Fragment => "Fragment",
|
|
|
|
|
ExecutionModel::Vertex => "Vertex",
|
|
|
|
|
};
|
|
|
|
|
let name = entry.name;
|
|
|
|
|
let interface: Vec<String> = entry
|
|
|
|
@ -204,7 +191,7 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
.map(|i| fix_name(&i.to_string()))
|
|
|
|
|
.collect();
|
|
|
|
|
let exec_mode = match entry.execution_mode {
|
|
|
|
|
crate::compiler::ExecutionMode::OriginUpperLeft => "OriginUpperLeft",
|
|
|
|
|
ExecutionMode::OriginUpperLeft => "OriginUpperLeft",
|
|
|
|
|
};
|
|
|
|
|
ops.push((
|
|
|
|
|
None,
|
|
|
|
@ -228,16 +215,16 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
|
|
|
|
|
for global in module.globals {
|
|
|
|
|
let name = fix_name(&global.name);
|
|
|
|
|
let _typ = global.typ;
|
|
|
|
|
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"),
|
|
|
|
|
StorageClass::Input => "Input",
|
|
|
|
|
StorageClass::Output => "Output",
|
|
|
|
|
StorageClass::Undefined => panic!("Bound a non-declared variable"),
|
|
|
|
|
};
|
|
|
|
|
let mut type_ops = Vec::new();
|
|
|
|
|
emit_type(parse_type(&_typ), &mut type_ops);
|
|
|
|
|
emit_type(&parse_type(&typ), &mut type_ops);
|
|
|
|
|
for op in type_ops {
|
|
|
|
|
if has_id(op.0.clone(), &ops) {
|
|
|
|
|
if has_id(&op.0, &ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
ops.push((Some(op.0), vec![op.1]));
|
|
|
|
@ -246,17 +233,17 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
Some(name.clone()),
|
|
|
|
|
vec![
|
|
|
|
|
"OpVariable".to_string(),
|
|
|
|
|
fix_name(&_typ),
|
|
|
|
|
fix_name(&typ),
|
|
|
|
|
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) => {
|
|
|
|
|
Decoration::Location(loc) => format!("Location {}", loc),
|
|
|
|
|
Decoration::BuiltIn(builtin) => {
|
|
|
|
|
let builtin = match builtin {
|
|
|
|
|
crate::compiler::BuiltinDecoration::FragCoord => "FragCoord",
|
|
|
|
|
BuiltinDecoration::FragCoord => "FragCoord",
|
|
|
|
|
};
|
|
|
|
|
format!("BuiltIn {}", builtin)
|
|
|
|
|
}
|
|
|
|
@ -269,23 +256,20 @@ pub fn spirv_meta(module: Module) -> String {
|
|
|
|
|
let name = fix_name(&fun.name);
|
|
|
|
|
let return_type = fix_name(&fun.return_type);
|
|
|
|
|
let mut type_ops = Vec::new();
|
|
|
|
|
emit_type(parse_type(&fun.return_type), &mut type_ops);
|
|
|
|
|
emit_type(&parse_type(&fun.return_type), &mut type_ops);
|
|
|
|
|
for op in type_ops {
|
|
|
|
|
if has_id(op.0.clone(), &ops) {
|
|
|
|
|
if has_id(&op.0, &ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
ops.push((Some(op.0), vec![op.1]));
|
|
|
|
|
}
|
|
|
|
|
// Push OpFunctionType
|
|
|
|
|
ops.push((
|
|
|
|
|
Some(name.clone()),
|
|
|
|
|
vec!["OpTypeFunction".to_string(), return_type.clone()],
|
|
|
|
|
));
|
|
|
|
|
ops.push((Some(name), vec!["OpTypeFunction".to_string(), return_type]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for op in ops {
|
|
|
|
|
if op.0.is_some() {
|
|
|
|
|
write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();
|
|
|
|
|
if let Some(op0) = op.0 {
|
|
|
|
|
write!(spirv_asm, "{} = ", op0).unwrap();
|
|
|
|
|
}
|
|
|
|
|
for arg in op.1 {
|
|
|
|
|
write!(spirv_asm, "{} ", arg).unwrap();
|
|
|
|
@ -372,8 +356,7 @@ pub fn compile_ast_ssa(
|
|
|
|
|
out: &mut Vec<(Option<String>, String)>,
|
|
|
|
|
) {
|
|
|
|
|
match ast.clone().list() {
|
|
|
|
|
Some(l) => {
|
|
|
|
|
let mut lst = l.clone();
|
|
|
|
|
Some(mut lst) => {
|
|
|
|
|
assert!(!lst.is_empty());
|
|
|
|
|
let fun = lst.remove(0);
|
|
|
|
|
assert!(true); // no safe remove, thanks Rust
|
|
|
|
@ -395,16 +378,24 @@ pub fn compile_ast_ssa(
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
"/" => {
|
|
|
|
|
compile_biop("OpFDiv", &mut lst, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFDiv", &mut lst, vars, constants, types, counter, stack, out,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
"*" => {
|
|
|
|
|
compile_biop("OpFMul", &mut lst, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFMul", &mut lst, vars, constants, types, counter, stack, out,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
"+" => {
|
|
|
|
|
compile_biop("OpFAdd", &mut lst, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFAdd", &mut lst, vars, constants, types, counter, stack, out,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
"-" => {
|
|
|
|
|
compile_biop("OpFSub", &mut lst, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFSub", &mut lst, vars, constants, types, counter, stack, out,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
s => {
|
|
|
|
|
panic!(
|
|
|
|
@ -415,9 +406,7 @@ pub fn compile_ast_ssa(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
let sym = ast.clone().symbol();
|
|
|
|
|
assert!(sym.is_some());
|
|
|
|
|
let sym = sym.unwrap();
|
|
|
|
|
let sym = ast.symbol().unwrap();
|
|
|
|
|
match match_number(&sym) {
|
|
|
|
|
Number::Int(i) => {
|
|
|
|
|
let key = format!("i32_{}", i);
|
|
|
|
|