|
|
|
@ -2,12 +2,10 @@
|
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
|
|
use crate::compiler::{
|
|
|
|
|
AddressingModel, BuiltinDecoration, Decoration, ExecutionMode, ExecutionModel, Instruction,
|
|
|
|
|
MemoryModel, Module, StorageClass,
|
|
|
|
|
AddressingModel, ExecutionMode, ExecutionModel, MemoryModel, Module, StorageClass,
|
|
|
|
|
};
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
use crate::parser::Ast;
|
|
|
|
|
use std::fmt::Write;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
|
pub enum Type {
|
|
|
|
@ -44,43 +42,48 @@ 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 mut chars = typ.chars();
|
|
|
|
|
match chars.next() {
|
|
|
|
|
Some('<') => {
|
|
|
|
|
let c = typ.chars().next().unwrap();
|
|
|
|
|
match c {
|
|
|
|
|
'<' => {
|
|
|
|
|
assert_eq!(typ.as_str(), "<>");
|
|
|
|
|
Type::Void
|
|
|
|
|
}
|
|
|
|
|
Some('*') => {
|
|
|
|
|
let mut typ = chars.collect::<String>();
|
|
|
|
|
let storage_class = match typ.pop() {
|
|
|
|
|
Some('i') => StorageClass::Input,
|
|
|
|
|
Some('o') => StorageClass::Output,
|
|
|
|
|
'*' => {
|
|
|
|
|
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,
|
|
|
|
|
_ => panic!("Invalid storage class"),
|
|
|
|
|
};
|
|
|
|
|
let typ = typ.chars().take(typ.len() - 1).collect::<String>();
|
|
|
|
|
Type::Pointer(Box::new(parse_type(&typ)), storage_class)
|
|
|
|
|
}
|
|
|
|
|
Some('v') => {
|
|
|
|
|
let size = chars.next().map(|s| s.to_digit(10)).flatten().unwrap();
|
|
|
|
|
'v' => {
|
|
|
|
|
let mut chars = typ.chars();
|
|
|
|
|
chars.next();
|
|
|
|
|
let size = chars.next().unwrap().to_digit(10).unwrap();
|
|
|
|
|
let typ = chars.collect::<String>();
|
|
|
|
|
Type::Vector(Box::new(parse_type(&typ)), size)
|
|
|
|
|
}
|
|
|
|
|
Some('f') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
'f' => {
|
|
|
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
|
|
|
Type::Float(size)
|
|
|
|
|
}
|
|
|
|
|
Some('s') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
's' => {
|
|
|
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
|
|
|
Type::Int(size)
|
|
|
|
|
}
|
|
|
|
|
Some('u') => {
|
|
|
|
|
let size = chars.collect::<String>().parse().unwrap();
|
|
|
|
|
'u' => {
|
|
|
|
|
let size = typ.chars().skip(1).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()));
|
|
|
|
@ -104,14 +107,18 @@ fn emit_type(typ: &Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
Type::Vector(in_typ, size) => {
|
|
|
|
|
emit_type(in_typ, ops);
|
|
|
|
|
emit_type(*in_typ.clone(), ops);
|
|
|
|
|
ops.push((
|
|
|
|
|
fix_name(&typ.to_string()),
|
|
|
|
|
format!("OpTypeVector {} {}", fix_name(&in_typ.to_string()), size),
|
|
|
|
|
format!(
|
|
|
|
|
"OpTypeVector {} {}",
|
|
|
|
|
fix_name(&in_typ.clone().to_string()),
|
|
|
|
|
size
|
|
|
|
|
),
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
Type::Pointer(in_typ, storage_class) => {
|
|
|
|
|
emit_type(in_typ, ops);
|
|
|
|
|
emit_type(*in_typ.clone(), ops);
|
|
|
|
|
let typ_id = fix_name(&typ.to_string());
|
|
|
|
|
let storage_class = match storage_class {
|
|
|
|
|
StorageClass::Input => "Input",
|
|
|
|
@ -130,23 +137,27 @@ fn emit_type(typ: &Type, ops: &mut Vec<(String, String)>) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn fix_name(name: &str) -> String {
|
|
|
|
|
fn fix_name(name: &String) -> String {
|
|
|
|
|
format!(
|
|
|
|
|
"%{}",
|
|
|
|
|
name.replace("-", "_")
|
|
|
|
|
name.clone()
|
|
|
|
|
.replace("-", "_")
|
|
|
|
|
.replace("*", "p")
|
|
|
|
|
.replace("<>", "void")
|
|
|
|
|
.replace(".", "_")
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
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
|
|
|
|
@ -179,7 +190,7 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
for entry in module.entry_points.clone() {
|
|
|
|
|
for entry in module.entry_points {
|
|
|
|
|
let exec_model = match entry.execution_model {
|
|
|
|
|
ExecutionModel::Fragment => "Fragment",
|
|
|
|
|
ExecutionModel::Vertex => "Vertex",
|
|
|
|
@ -212,25 +223,8 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
for global in module.globals.clone() {
|
|
|
|
|
let name: String = fix_name(&global.name);
|
|
|
|
|
|
|
|
|
|
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 global in module.globals.clone() {
|
|
|
|
|
for global in module.globals {
|
|
|
|
|
let name = fix_name(&global.name);
|
|
|
|
|
let typ = global.typ;
|
|
|
|
|
let storage_class = match global.storage_class {
|
|
|
|
@ -239,9 +233,9 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<String>)> {
|
|
|
|
|
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, &ops) {
|
|
|
|
|
if has_id(op.0.clone(), &ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
ops.push((Some(op.0), vec![op.1]));
|
|
|
|
@ -254,419 +248,47 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option<String>, Vec<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 fun in module.functions.clone() {
|
|
|
|
|
let name = fix_name(&format!("l_{}", fun.name));
|
|
|
|
|
for fun in module.functions {
|
|
|
|
|
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, &ops) {
|
|
|
|
|
if has_id(op.0.clone(), &ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
ops.push((Some(op.0), vec![op.1]));
|
|
|
|
|
}
|
|
|
|
|
// Push OpFunctionType
|
|
|
|
|
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();
|
|
|
|
|
// }
|
|
|
|
|
// for arg in op.1 {
|
|
|
|
|
// write!(spirv_asm, "{} ", arg).unwrap();
|
|
|
|
|
// }
|
|
|
|
|
// writeln!(spirv_asm).unwrap();
|
|
|
|
|
// }
|
|
|
|
|
// spirv_asm
|
|
|
|
|
ops
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum Number {
|
|
|
|
|
Int(i32),
|
|
|
|
|
Float(f32),
|
|
|
|
|
NotANumber,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn match_number(s: &str) -> Number {
|
|
|
|
|
// floats have to be in the format of [0-9]+\.[0-9]*
|
|
|
|
|
// integers have to be in the format of [0-9]+
|
|
|
|
|
let mut chars = s.chars();
|
|
|
|
|
let mut has_dot = false;
|
|
|
|
|
while let Some(c) = chars.next() {
|
|
|
|
|
if c == '.' {
|
|
|
|
|
if has_dot {
|
|
|
|
|
// only one dot allowed.
|
|
|
|
|
return Number::NotANumber;
|
|
|
|
|
}
|
|
|
|
|
has_dot = true;
|
|
|
|
|
} else if !c.is_digit(10) {
|
|
|
|
|
// not a number;
|
|
|
|
|
// has a character that is not a digit or a dot.
|
|
|
|
|
return Number::NotANumber;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if has_dot {
|
|
|
|
|
// we have checked that the whole thing is numbers and dots
|
|
|
|
|
// and that there is precisely one dot
|
|
|
|
|
// that matches the regex.
|
|
|
|
|
Number::Float(s.parse().unwrap())
|
|
|
|
|
} else {
|
|
|
|
|
// this is an integer, since no dots.
|
|
|
|
|
Number::Int(s.parse().unwrap())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile_biop(
|
|
|
|
|
op: &str,
|
|
|
|
|
lst: &mut Vec<Ast>,
|
|
|
|
|
vars: &mut Vec<(String, String)>,
|
|
|
|
|
constants: &mut Vec<(String, String)>,
|
|
|
|
|
types: &mut Vec<String>,
|
|
|
|
|
counter: &mut i32,
|
|
|
|
|
stack: &mut Vec<String>,
|
|
|
|
|
out: &mut Vec<(Option<String>, String)>,
|
|
|
|
|
typ: &str,
|
|
|
|
|
) {
|
|
|
|
|
assert!(lst.len() == 2);
|
|
|
|
|
let rhs = lst.pop().unwrap();
|
|
|
|
|
let lhs = lst.pop().unwrap();
|
|
|
|
|
compile_ast_ssa(lhs, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_ast_ssa(rhs, vars, constants, types, counter, stack, out);
|
|
|
|
|
let rhs_id = stack.pop().unwrap();
|
|
|
|
|
let lhs_id = stack.pop().unwrap();
|
|
|
|
|
let id = String::from(counter.to_string());
|
|
|
|
|
*counter += 1;
|
|
|
|
|
out.push((
|
|
|
|
|
Some(id.clone()),
|
|
|
|
|
format!(
|
|
|
|
|
"{} {} {} {}",
|
|
|
|
|
op,
|
|
|
|
|
fix_name(&String::from(typ)),
|
|
|
|
|
fix_name(&lhs_id),
|
|
|
|
|
fix_name(&rhs_id),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
stack.push(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile_comp_constr(
|
|
|
|
|
lst: &mut Vec<Ast>,
|
|
|
|
|
vars: &mut Vec<(String, String)>,
|
|
|
|
|
constants: &mut Vec<(String, String)>,
|
|
|
|
|
types: &mut Vec<String>,
|
|
|
|
|
counter: &mut i32,
|
|
|
|
|
stack: &mut Vec<String>,
|
|
|
|
|
out: &mut Vec<(Option<String>, String)>,
|
|
|
|
|
typ: &str,
|
|
|
|
|
) {
|
|
|
|
|
types.push(String::from(typ));
|
|
|
|
|
let typ_parsed = parse_type(&String::from(typ));
|
|
|
|
|
match typ_parsed {
|
|
|
|
|
Type::Vector(_, size) => {
|
|
|
|
|
assert!(lst.len() == size as usize);
|
|
|
|
|
let mut inners: Vec<String> = vec![];
|
|
|
|
|
for _ in 0..size {
|
|
|
|
|
let ast = lst.pop().unwrap();
|
|
|
|
|
compile_ast_ssa(ast, vars, constants, types, counter, stack, out);
|
|
|
|
|
let res_id = stack.pop().unwrap();
|
|
|
|
|
inners.push(res_id);
|
|
|
|
|
}
|
|
|
|
|
let id = String::from(counter.to_string());
|
|
|
|
|
*counter += 1;
|
|
|
|
|
let mut out_str = String::new();
|
|
|
|
|
out_str.push_str(
|
|
|
|
|
format!("OpCompositeConstruct {}", fix_name(&String::from(typ))).as_str(),
|
|
|
|
|
);
|
|
|
|
|
inners.reverse();
|
|
|
|
|
for inn in inners {
|
|
|
|
|
out_str.push_str(format!(" {}", fix_name(&inn)).as_str());
|
|
|
|
|
}
|
|
|
|
|
out.push((Some(id.clone()), out_str));
|
|
|
|
|
stack.push(id);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
panic!("Invalid vector!")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile_comp_extract(
|
|
|
|
|
lst: &mut Vec<Ast>,
|
|
|
|
|
vars: &mut Vec<(String, String)>,
|
|
|
|
|
constants: &mut Vec<(String, String)>,
|
|
|
|
|
types: &mut Vec<String>,
|
|
|
|
|
counter: &mut i32,
|
|
|
|
|
stack: &mut Vec<String>,
|
|
|
|
|
out: &mut Vec<(Option<String>, String)>,
|
|
|
|
|
typ: &str,
|
|
|
|
|
inx: u32,
|
|
|
|
|
) {
|
|
|
|
|
assert!(lst.len() == 1);
|
|
|
|
|
let vec = lst.pop().unwrap();
|
|
|
|
|
compile_ast_ssa(vec, vars, constants, types, counter, stack, out);
|
|
|
|
|
let vec_id = stack.pop().unwrap();
|
|
|
|
|
let id = counter.to_string();
|
|
|
|
|
*counter += 1;
|
|
|
|
|
out.push((
|
|
|
|
|
Some(id.clone()),
|
|
|
|
|
format!(
|
|
|
|
|
"OpCompositeExtract {} {} {}",
|
|
|
|
|
fix_name(&String::from(typ)),
|
|
|
|
|
fix_name(&vec_id),
|
|
|
|
|
inx
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
stack.push(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn compile_ast_ssa(
|
|
|
|
|
ast: Ast,
|
|
|
|
|
vars: &mut Vec<(String, String)>,
|
|
|
|
|
constants: &mut Vec<(String, String)>,
|
|
|
|
|
types: &mut Vec<String>,
|
|
|
|
|
counter: &mut i32,
|
|
|
|
|
stack: &mut Vec<String>,
|
|
|
|
|
out: &mut Vec<(Option<String>, String)>,
|
|
|
|
|
) {
|
|
|
|
|
match ast.clone().list() {
|
|
|
|
|
Some(mut lst) => {
|
|
|
|
|
assert!(!lst.is_empty());
|
|
|
|
|
let fun = lst.remove(0);
|
|
|
|
|
assert!(true); // no safe remove, thanks Rust
|
|
|
|
|
let fun_name = fun.symbol();
|
|
|
|
|
assert!(fun_name.is_some());
|
|
|
|
|
let fun_name = fun_name.unwrap();
|
|
|
|
|
if fun_name.starts_with(".") {
|
|
|
|
|
let to_split = &fun_name[1..fun_name.len()];
|
|
|
|
|
let split = to_split.split("-").collect::<Vec<&str>>();
|
|
|
|
|
assert!(split.len() == 2);
|
|
|
|
|
let inx = split[0];
|
|
|
|
|
let typ = split[1];
|
|
|
|
|
let inx = str::parse::<u32>(inx).expect("Invalid index!");
|
|
|
|
|
compile_comp_extract(
|
|
|
|
|
&mut lst, vars, constants, types, counter, stack, out, typ, inx,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("/") {
|
|
|
|
|
let typ = &fun_name[1..fun_name.len()];
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFDiv", &mut lst, vars, constants, types, counter, stack, out, typ,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("*") {
|
|
|
|
|
let typ = &fun_name[1..fun_name.len()];
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFMul", &mut lst, vars, constants, types, counter, stack, out, typ,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("+") {
|
|
|
|
|
let typ = &fun_name[1..fun_name.len()];
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFAdd", &mut lst, vars, constants, types, counter, stack, out, typ,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("-") {
|
|
|
|
|
let typ = &fun_name[1..fun_name.len()];
|
|
|
|
|
compile_biop(
|
|
|
|
|
"OpFSub", &mut lst, vars, constants, types, counter, stack, out, typ,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("v") {
|
|
|
|
|
compile_comp_constr(
|
|
|
|
|
&mut lst,
|
|
|
|
|
vars,
|
|
|
|
|
constants,
|
|
|
|
|
types,
|
|
|
|
|
counter,
|
|
|
|
|
stack,
|
|
|
|
|
out,
|
|
|
|
|
fun_name.as_str(),
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fun_name.starts_with("load-ptr-") {
|
|
|
|
|
let typ = &fun_name[9..fun_name.len()];
|
|
|
|
|
assert!(lst.len() == 1);
|
|
|
|
|
let ptr = lst.pop().unwrap();
|
|
|
|
|
compile_ast_ssa(ptr, vars, constants, types, counter, stack, out);
|
|
|
|
|
let ptr_id = stack.pop().unwrap();
|
|
|
|
|
let id: String = counter.to_string();
|
|
|
|
|
*counter += 1;
|
|
|
|
|
out.push((
|
|
|
|
|
Some(id.clone()),
|
|
|
|
|
format!(
|
|
|
|
|
"OpLoad {} {}",
|
|
|
|
|
fix_name(&String::from(typ)),
|
|
|
|
|
fix_name(&ptr_id)
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
stack.push(id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match fun_name.as_str() {
|
|
|
|
|
"store-ptr" => {
|
|
|
|
|
assert!(lst.len() == 2);
|
|
|
|
|
let val = lst.pop().unwrap();
|
|
|
|
|
let ptr = lst.pop().unwrap();
|
|
|
|
|
compile_ast_ssa(val, vars, constants, types, counter, stack, out);
|
|
|
|
|
compile_ast_ssa(ptr, vars, constants, types, counter, stack, out);
|
|
|
|
|
let val_id = stack.pop().unwrap();
|
|
|
|
|
let ptr_id = stack.pop().unwrap();
|
|
|
|
|
out.push((
|
|
|
|
|
None,
|
|
|
|
|
format!("OpStore {} {}", fix_name(&val_id), fix_name(&ptr_id)),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
s => {
|
|
|
|
|
panic!(
|
|
|
|
|
"Unknown function: {} with params {:#?} in context:\n{:#?}",
|
|
|
|
|
s, lst, ast
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
let sym = ast.symbol().expect("This must be a symbol");
|
|
|
|
|
match match_number(&sym) {
|
|
|
|
|
Number::Int(i) => {
|
|
|
|
|
let key = format!("i32_{}", i);
|
|
|
|
|
let mut contains = false;
|
|
|
|
|
for c in constants.iter() {
|
|
|
|
|
if c.0 == key {
|
|
|
|
|
contains = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !contains {
|
|
|
|
|
constants.push((key.clone(), format!("OpConstant %i32 {}", i.to_string())));
|
|
|
|
|
}
|
|
|
|
|
stack.push(key);
|
|
|
|
|
}
|
|
|
|
|
Number::Float(f) => {
|
|
|
|
|
let key = format!("f32_{}", f);
|
|
|
|
|
let mut contains = false;
|
|
|
|
|
for c in constants.iter() {
|
|
|
|
|
if c.0 == key {
|
|
|
|
|
contains = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !contains {
|
|
|
|
|
constants.push((key.clone(), format!("OpConstant %f32 {}", f.to_string())));
|
|
|
|
|
}
|
|
|
|
|
for t in types.iter() {
|
|
|
|
|
if t == "f32" {
|
|
|
|
|
contains = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !contains {
|
|
|
|
|
types.push("f32".to_string());
|
|
|
|
|
}
|
|
|
|
|
stack.push(key);
|
|
|
|
|
}
|
|
|
|
|
Number::NotANumber => {
|
|
|
|
|
for v in vars.iter() {
|
|
|
|
|
if v.0 == sym {
|
|
|
|
|
stack.push(v.0.clone());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
panic!("Unknown variable or constant: {}", sym);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ops.push((
|
|
|
|
|
Some(name.clone()),
|
|
|
|
|
vec!["OpTypeFunction".to_string(), return_type.clone()],
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn compile_fun_ssa(module: &mut Module, ops: &Vec<(Option<String>, String)>) {
|
|
|
|
|
let mut label_counter = Box::new(0);
|
|
|
|
|
for fun in module.functions.iter_mut() {
|
|
|
|
|
assert!(fun.ast.is_some());
|
|
|
|
|
let ast = fun.ast.as_mut().unwrap();
|
|
|
|
|
let block = ast.clone().list().unwrap().get(0).unwrap().clone();
|
|
|
|
|
let mut vars = vec![];
|
|
|
|
|
let mut constants = vec![];
|
|
|
|
|
let mut types = vec![];
|
|
|
|
|
let mut counter = Box::new(0);
|
|
|
|
|
let mut stack = vec![];
|
|
|
|
|
let mut out_op = vec![];
|
|
|
|
|
for v in &module.globals {
|
|
|
|
|
vars.push((v.name.clone(), v.typ.clone()));
|
|
|
|
|
for op in ops {
|
|
|
|
|
if op.0.is_some() {
|
|
|
|
|
write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();
|
|
|
|
|
}
|
|
|
|
|
compile_ast_ssa(
|
|
|
|
|
block,
|
|
|
|
|
&mut vars,
|
|
|
|
|
&mut constants,
|
|
|
|
|
&mut types,
|
|
|
|
|
&mut counter,
|
|
|
|
|
&mut stack,
|
|
|
|
|
&mut out_op,
|
|
|
|
|
);
|
|
|
|
|
let mut out_pre = vec![];
|
|
|
|
|
for t in &types {
|
|
|
|
|
let typ = parse_type(t);
|
|
|
|
|
if has_id(&fix_name(&typ.to_string()), ops) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if has_id(&fix_name(&typ.to_string()), &out_pre) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let mut type_ops = vec![];
|
|
|
|
|
emit_type(&typ, &mut type_ops);
|
|
|
|
|
for type_op in type_ops {
|
|
|
|
|
out_pre.push((Some(type_op.0), type_op.1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for c in &constants {
|
|
|
|
|
out_pre.push((Some(fix_name(&c.0.clone())), c.1.clone()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO non-void type
|
|
|
|
|
out_pre.push((
|
|
|
|
|
Some(fix_name(&fun.name)),
|
|
|
|
|
format!("OpFunction %void None %l_{}", fun.name),
|
|
|
|
|
));
|
|
|
|
|
out_pre.push((
|
|
|
|
|
Some(format!("%n_{}", label_counter.to_string())),
|
|
|
|
|
"OpLabel".to_string(),
|
|
|
|
|
));
|
|
|
|
|
*label_counter += 1;
|
|
|
|
|
let mut out_ops = out_pre.clone();
|
|
|
|
|
for op in out_op {
|
|
|
|
|
if op.0.is_some() {
|
|
|
|
|
out_ops.push((Some(fix_name(&op.0.unwrap())), op.1));
|
|
|
|
|
} else {
|
|
|
|
|
out_ops.push((None, op.1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_ops.push((None, String::from("OpReturn")));
|
|
|
|
|
out_ops.push((None, String::from("OpFunctionEnd")));
|
|
|
|
|
|
|
|
|
|
for op in out_ops {
|
|
|
|
|
let split: Vec<String> = op.1.split(" ").map(|s| s.to_string()).collect();
|
|
|
|
|
let op_name: String = (&split[0]).clone();
|
|
|
|
|
let op_args: Vec<String> = split[1..].iter().map(|s| s.clone()).collect();
|
|
|
|
|
let op_id = op.0.clone();
|
|
|
|
|
let ins: Instruction = Instruction {
|
|
|
|
|
result_id: op_id,
|
|
|
|
|
op: op_name,
|
|
|
|
|
operands: op_args,
|
|
|
|
|
};
|
|
|
|
|
fun.body.as_mut().unwrap().push(ins);
|
|
|
|
|
for arg in op.1 {
|
|
|
|
|
write!(spirv_asm, "{} ", arg).unwrap();
|
|
|
|
|
}
|
|
|
|
|
writeln!(spirv_asm).unwrap();
|
|
|
|
|
}
|
|
|
|
|
spirv_asm
|
|
|
|
|
}
|
|
|
|
|