|
|
|
@ -1,11 +1,12 @@
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
|
|
use crate::compiler::{Instruction, Module};
|
|
|
|
|
use crate::compiler::{
|
|
|
|
|
AddressingModel, BuiltinDecoration, Decoration, ExecutionMode, ExecutionModel, Instruction,
|
|
|
|
|
MemoryModel, Module, StorageClass,
|
|
|
|
|
};
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
use super::StorageClass;
|
|
|
|
|
|
|
|
|
|
use crate::parser::Ast;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
@ -43,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()));
|
|
|
|
@ -108,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",
|
|
|
|
@ -138,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<T>(name: String, ops: &Vec<(Option<String>, T)>) -> bool {
|
|
|
|
|
for op in ops {
|
|
|
|
|
if op.0.is_some() && op.0.clone().unwrap() == name {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
fn has_id<T>(name: &str, ops: &Vec<(Option<String>, T)>) -> bool {
|
|
|
|
|
ops.iter()
|
|
|
|
|
.find(|op| op.0.as_ref().map(|s| *s == name).unwrap_or(false))
|
|
|
|
|
.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
@ -170,15 +158,15 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<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((
|
|
|
|
@ -192,8 +180,8 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
|
|
|
|
|
for entry in module.entry_points.clone() {
|
|
|
|
|
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
|
|
|
|
@ -202,7 +190,7 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<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,
|
|
|
|
@ -226,16 +214,16 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
|
|
|
|
|
for global in module.globals.clone() {
|
|
|
|
|
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]));
|
|
|
|
@ -244,17 +232,17 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<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)
|
|
|
|
|
}
|
|
|
|
@ -267,17 +255,15 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
let name = fix_name(&format!("l_{}", 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]));
|
|
|
|
|
}
|
|
|
|
|
ops.push((
|
|
|
|
|
Some(name.clone()),
|
|
|
|
|
vec!["OpTypeFunction".to_string(), return_type.clone()],
|
|
|
|
|
));
|
|
|
|
|
// Push OpFunctionType
|
|
|
|
|
ops.push((Some(name), vec!["OpTypeFunction".to_string(), return_type]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for op in ops {
|
|
|
|
@ -289,7 +275,6 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
// }
|
|
|
|
|
// writeln!(spirv_asm).unwrap();
|
|
|
|
|
// }
|
|
|
|
|
// spirv_asm
|
|
|
|
|
ops
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -370,8 +355,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
|
|
|
|
@ -421,9 +405,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);
|
|
|
|
@ -500,14 +482,14 @@ pub fn compile_fun_ssa(module: &mut Module, ops: &Vec<(Option<String>, String)>)
|
|
|
|
|
let mut out_pre = vec![];
|
|
|
|
|
for t in &types {
|
|
|
|
|
let typ = parse_type(t);
|
|
|
|
|
if has_id(fix_name(&typ.to_string()), ops) {
|
|
|
|
|
if has_id(&fix_name(&typ.to_string()), ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if has_id(fix_name(&typ.to_string()), &out_pre) {
|
|
|
|
|
if has_id(&fix_name(&typ.to_string()), &out_pre) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let mut type_ops = vec![];
|
|
|
|
|
emit_type(typ, &mut type_ops);
|
|
|
|
|
emit_type(&typ, &mut type_ops);
|
|
|
|
|
for type_op in type_ops {
|
|
|
|
|
out_pre.push((Some(type_op.0), type_op.1));
|
|
|
|
|
}
|
|
|
|
|