diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs index 53c59ac..d692d14 100644 --- a/src/compiler/backend/mod.rs +++ b/src/compiler/backend/mod.rs @@ -1,12 +1,11 @@ #[cfg(test)] mod tests; -use crate::compiler::{Instruction, Module}; +use crate::compiler::{ + AddressingModel, ExecutionMode, ExecutionModel, MemoryModel, Module, StorageClass, +}; use std::fmt; - -use super::StorageClass; - -use crate::parser::Ast; +use std::fmt::Write; #[derive(Debug, PartialEq, Clone)] pub enum Type { @@ -148,7 +147,7 @@ fn fix_name(name: &String) -> String { ) } -fn has_id(name: String, ops: &Vec<(Option, T)>) -> bool { +fn has_id(name: String, ops: &Vec<(Option, Vec)>) -> bool { for op in ops { if op.0.is_some() && op.0.clone().unwrap() == name { return true; @@ -157,7 +156,8 @@ fn has_id(name: String, ops: &Vec<(Option, T)>) -> bool { false } -pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { +pub fn spirv_meta(module: Module) -> String { + let mut spirv_asm = String::new(); let mut ops: Vec<(Option, Vec)> = Vec::new(); let capabilities: Vec = module @@ -170,15 +170,15 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { } 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(( @@ -190,10 +190,10 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { ], )); - for entry in module.entry_points.clone() { + 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 = entry @@ -202,7 +202,7 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { .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, @@ -224,16 +224,16 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { )); } - for global in module.globals.clone() { + 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) { continue; @@ -244,7 +244,7 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { Some(name.clone()), vec![ "OpVariable".to_string(), - fix_name(&_typ), + fix_name(&typ), storage_class.to_string(), ], )); @@ -263,8 +263,8 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { } } - 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); @@ -274,277 +274,21 @@ pub fn spirv_meta(module: &mut Module) -> Vec<(Option, Vec)> { } ops.push((Some(op.0), vec![op.1])); } + // Push OpFunctionType ops.push(( Some(name.clone()), vec!["OpTypeFunction".to_string(), return_type.clone()], )); } - // 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, - vars: &mut Vec<(String, String)>, - constants: &mut Vec<(String, String)>, - types: &mut Vec, - counter: &mut i32, - stack: &mut Vec, - out: &mut Vec<(Option, String)>, -) { - 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("f32")), - fix_name(&lhs_id), - fix_name(&rhs_id), - ), - )); - stack.push(id); -} - -pub fn compile_ast_ssa( - ast: Ast, - vars: &mut Vec<(String, String)>, - constants: &mut Vec<(String, String)>, - types: &mut Vec, - counter: &mut i32, - stack: &mut Vec, - out: &mut Vec<(Option, String)>, -) { - match ast.clone().list() { - Some(l) => { - let mut lst = l.clone(); - 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(); - match fun_name.as_str() { - "store-ptr" => { - assert!(lst.len() == 2); - let ptr = lst.pop().unwrap(); - let val = lst.pop().unwrap(); - compile_ast_ssa(ptr, vars, constants, types, counter, stack, out); - compile_ast_ssa(val, 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)), - )); - } - "/" => { - compile_biop( - "OpFDiv", &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( - "OpFSub", &mut lst, vars, constants, types, counter, stack, out, - ); - } - s => { - panic!( - "Unknown function: {} with params {:#?} in context:\n{:#?}", - s, lst, ast - ); - } - } - } - None => { - let sym = ast.clone().symbol(); - assert!(sym.is_some()); - let sym = sym.unwrap(); - 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); - } - } - } - } -} - -pub fn compile_fun_ssa(module: &mut Module, ops: &Vec<(Option, 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())); - } - 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)); - } + for op in ops { + if op.0.is_some() { + write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap(); } - for op in out_ops { - let split: Vec = op.1.split(" ").map(|s| s.to_string()).collect(); - let op_name: String = (&split[0]).clone(); - let op_args: Vec = 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 } diff --git a/src/compiler/backend/tests.rs b/src/compiler/backend/tests.rs index 6420b62..2f0cce5 100644 --- a/src/compiler/backend/tests.rs +++ b/src/compiler/backend/tests.rs @@ -12,17 +12,16 @@ fn test_emit() { (dec out-color:*v4f32o Output) (entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (fun (main) :<> - (store-ptr out-color + (store-ptr (out-color) (v4f32i (/ (.xy (load-ptr frag-coord)) (v2f32 1920.0 1080.0)) 1.0 1.0))) "; let ast = parse(tokenize(src)); - let mut module = meta_compile(ast.unwrap()).unwrap(); - let res = spirv_meta(&mut module); - println!("{:#?}", res); - // TODO add an assert + let module = meta_compile(ast.unwrap()).unwrap(); + let res = spirv_meta(module); + println!("{}", res); } #[test] @@ -50,127 +49,3 @@ fn test_type_parse() { assert_eq!(parse_type(&"f32".to_string()), Float(32)); assert_eq!(parse_type(&"s32".to_string()), Int(32)); } - -#[test] -fn test_block_ssa() { - use crate::compiler::backend::*; - use crate::compiler::*; - use crate::parser::*; - let src = " - (module Shader Logical GLSL450) -(import :std GLSL.std.450) -(bind (out-color:*f32o) (Location 0)) -(dec out-color:*f32o Output) -(entry main Fragment OriginUpperLeft (:out-color)) -(fun (main) :<> - (store-ptr out-color (/ 1.0 (+ 1.0 1.0)))) -"; - let ast = parse(tokenize(src)); - let mut module = meta_compile(ast.unwrap()).unwrap(); - let fun = module.functions.pop().unwrap(); - let block = fun.ast.unwrap(); - let block = block.list().unwrap().get(0).unwrap().clone(); - println!("{:#?}", block); - 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 = vec![]; - for v in &module.globals { - vars.push((v.name.clone(), v.typ.clone())); - } - compile_ast_ssa( - block, - &mut vars, - &mut constants, - &mut types, - &mut counter, - &mut stack, - &mut out, - ); - println!("\n---vars:---\n{:#?}\n-----------", vars); - println!("\n---constants:---\n{:#?}\n----------------", constants); - println!("\n---types:---\n{:#?}\n------------", types); - println!("\n---stack:---\n{:#?}\n------------", stack); - println!("\n---counter:---\n{}\n--------------", counter); - println!("\n---out:---"); - for (a, b) in &out { - match a { - Some(a) => println!("%{} = {}", a, b), - None => println!("{}", b), - } - } - println!("----------"); - assert!(stack.is_empty()); -} - -#[test] -fn test_fun_ssa() { - use crate::compiler::backend::*; - use crate::compiler::*; - use crate::parser::*; - let src = " - (module Shader Logical GLSL450) - (import :std GLSL.std.450) - (bind (out-color:*f32o) (Location 0)) - (dec out-color:*f32o Output) - (entry main Fragment OriginUpperLeft (:out-color)) - (fun (main) :<> - (store-ptr out-color (/ 1.0 (+ 1.0 1.0)))) -"; - let ast = parse(tokenize(src)); - let mut module = meta_compile(ast.unwrap()).unwrap(); - let ops = vec![]; - compile_fun_ssa(&mut module, &ops); - let res = module.functions.pop().unwrap(); - let res = res.body.unwrap(); - println!("{:#?}", res); - // TODO we need to unify the place where we call fix_name - let res_spv: Vec = vec![ - Instruction { - result_id: Some("%f32".to_string()), - op: "OpTypeFloat".to_string(), - operands: vec!["32".to_string()], - }, - Instruction { - result_id: Some("%f32_1".to_string()), - op: "OpConstant".to_string(), - operands: vec!["%f32".to_string(), "1".to_string()], - }, - Instruction { - result_id: Some("%main".to_string()), - op: "OpFunction".to_string(), - operands: vec![ - "%void".to_string(), - "None".to_string(), - "%l_main".to_string(), - ], - }, - Instruction { - result_id: Some("%n_0".to_string()), - op: "OpLabel".to_string(), - operands: vec![], - }, - Instruction { - result_id: Some("%0".to_string()), - op: "OpFAdd".to_string(), - operands: vec![ - "%f32".to_string(), - "%f32_1".to_string(), - "%f32_1".to_string(), - ], - }, - Instruction { - result_id: Some("%1".to_string()), - op: "OpFDiv".to_string(), - operands: vec!["%f32".to_string(), "%f32_1".to_string(), "%0".to_string()], - }, - Instruction { - result_id: None, - op: "OpStore".to_string(), - operands: vec!["%out_color".to_string(), "%1".to_string()], - }, - ]; - assert_eq!(res, res_spv); -} diff --git a/src/main.rs b/src/main.rs index ae97a6e..70e44c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,31 @@ -use compiler::{ - backend::{compile_fun_ssa, spirv_meta}, - meta_compile, -}; +use compiler::{backend::spirv_meta, meta_compile}; use error::print_error; -use std::{env, fs, path::PathBuf, process::ExitCode}; +use std::{env, fs, path::PathBuf}; -use parser::parse_string; +use parser::{parse_string, tokenize, Token}; pub mod compiler; mod error; pub mod parser; +#[derive(Debug, Default, PartialEq)] +enum Trace { + Tokens, + AST, + #[default] Normal +} + #[derive(Debug, Default)] struct CompilerArgs { input: Option, output: Option, + trace: Trace, print_help: bool, print_version: bool, } const SPIRV_VERSION: &'static str = "1.0"; -fn main() -> ExitCode { +fn main() { let args = parse_args(); if args.print_version || args.print_help { if args.print_help { @@ -29,78 +34,59 @@ fn main() -> ExitCode { if args.print_version { print_version(); } - return ExitCode::FAILURE; + return; } let Some(input) = args.input else { eprintln!("No input specified"); - return ExitCode::FAILURE; + return; }; - let output = args.output.unwrap_or(PathBuf::from("./out.spvas")); + let output = args.output.unwrap_or(PathBuf::from("./out.spv")); let src = match fs::read_to_string(input) { Ok(i) => i, Err(e) => { eprintln!("{e}"); - return ExitCode::FAILURE; + return; } }; + if args.trace == Trace::Tokens { + let tokens = tokenize(&src); + for tok in tokens { + match tok.item { + Token::LeftParen => println!("{:>3}:{:<3} LeftParen",tok.location.line_start(), tok.location.col_start()), + Token::RightParen => println!("{:>3}:{:<3} RightParen",tok.location.line_start(), tok.location.col_start()), + Token::Symbol( val ) => println!("{:>3}:{:<3} Symbol `{}`",tok.location.line_start(), tok.location.col_start(), val) + } + } + return; + } let ast = match parse_string(&src) { Ok(i) => i, Err(e) => { print_error(e, Some(&src)); - return ExitCode::FAILURE; + return; } }; + + if args.trace == Trace::AST { + ast.pretty_print(None,None); + return; + } - let mut module = match meta_compile(ast) { + let module = match meta_compile(ast) { Ok(m) => m, Err(e) => { print_error(e, Some(&src)); - return ExitCode::FAILURE; + return; } }; - use std::fmt::Write; - - let ops_split_params = spirv_meta(&mut module); - let mut ops_merged_param = vec![]; - for op in ops_split_params.clone() { - ops_merged_param.push((op.0, op.1.join(" "))); - } - compile_fun_ssa(&mut module, &ops_merged_param); - - let mut res = String::new(); - - for op in ops_split_params { - if op.0.is_some() { - write!(res, "{} = ", op.0.unwrap()).unwrap(); - } - for arg in op.1 { - write!(res, "{} ", arg).unwrap(); - } - writeln!(res).unwrap(); - } - - for fun in module.functions.iter() { - // TODO non-void type - for inst in fun.body.clone().unwrap().iter() { - if let Some(id) = inst.result_id.as_ref() { - write!(res, "{} = ", id).unwrap(); - } - write!(res, "{}", inst.op).unwrap(); - for op in inst.operands.iter() { - write!(res, " {}", op).unwrap(); - } - writeln!(res).unwrap(); - } - } + let res = spirv_meta(module); fs::write(output, res).unwrap(); - - ExitCode::SUCCESS } fn parse_args() -> CompilerArgs { @@ -149,6 +135,36 @@ fn parse_args() -> CompilerArgs { return parsed_args; } } + "trace" => { + if parsed_args.trace == Trace::Normal { + let Some(output) = args.next() else { + parsed_args.print_help = true; + eprintln!("trace needs a file"); + eprintln!(); + return parsed_args; + }; + match output.as_str() { + "ast" | "AST" | "Ast" => { + parsed_args.trace = Trace::AST; + } + "token" | "tokens" => { + parsed_args.trace = Trace::Tokens; + } + a => { + eprintln!("unknown trace value {a}"); + eprintln!(); + parsed_args.print_help = true; + return parsed_args; + } + } + + } else { + eprintln!("trace can be passed only once"); + eprintln!(); + parsed_args.print_help = true; + return parsed_args; + } + } a => { eprintln!("unknown arg --{a}"); eprintln!(); @@ -239,7 +255,7 @@ fn print_help() { println!("\t\tThe shader to be parsed and compiled, manadory argument"); println!(); println!("\t-o --output:"); - println!("\t\tWhere to output the compiled spirv assembly to, default: out.spvas"); + println!("\t\tWhere to output the compiled spirv assembly to, default: out.spv"); println!(); println!("\t-h --help:"); println!("\t\tPrint this and exit"); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d175e81..9c7c797 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -148,13 +148,6 @@ impl Ast { } } - pub fn list(self) -> Option> { - match self { - Ast::List(Localised { item, .. }) => Some(item), - _ => None, - } - } - pub fn location(&self) -> &Location { match self { Ast::Symbol(Localised { location, .. }) => location, @@ -162,6 +155,31 @@ impl Ast { Ast::Root(_) => &Location::All, } } + + pub fn pretty_print(&self, prefix: Option<&String>, body_prefix: Option<&String>) { + let empty_string_to_make_rust_happy = &String::from(""); + let prefix_ = prefix.unwrap_or(&empty_string_to_make_rust_happy); + let body_prefix_ = body_prefix.unwrap_or(&empty_string_to_make_rust_happy); + match self { + Ast::Symbol(Localised { item, location }) => { + println!("{} Symbol `{}` ({}:{})", prefix_, item, location.line_start(), location.col_start()); + }, + Ast::List(Localised { item, location }) => { + println!("{} List ({}:{})", prefix_, location.line_start(), location.col_start()); + for i in 0..item.len()-1 { + item[i].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ├─ "))), Some(&(body_prefix_.to_owned() + &String::from(" │ ")))); + } + item[item.len()-1].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ╰─ "))), Some(&(body_prefix_.to_owned() + &String::from(" ")))); + }, + Ast::Root( items ) => { + println!("{} Root", prefix_); + for i in 0..items.len()-2 { + items[i].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ├─ "))), Some(&(body_prefix_.to_owned() + &String::from(" │ ")))); + } + items[items.len()-1].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ╰─ "))), Some(&(body_prefix_.to_owned() + &String::from(" ")))); + }, + } + } } pub fn tokenize(input: &str) -> Vec> { diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 4a96b68..8e94147 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -44,7 +44,7 @@ fn test_parse() { (dec out-color:*v4f32o Output) (entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (fun (main) :<> - (store-ptr out-color + (store-ptr (out-color) (v4f32i (/ (.xy (load-ptr frag-coord)) (v2f32 1920.0 1080.0)) 1.0 @@ -111,7 +111,9 @@ fn test_parse() { Ast::Symbol(Localised::dummy_location(":<>".to_string())), Ast::List(Localised::dummy_location(vec![ Ast::Symbol(Localised::dummy_location("store-ptr".to_string())), - Ast::Symbol(Localised::dummy_location("out-color".to_string())), + Ast::List(Localised::dummy_location(vec![Ast::Symbol( + Localised::dummy_location("out-color".to_string()), + )])), Ast::List(Localised::dummy_location(vec![ Ast::Symbol(Localised::dummy_location("v4f32i".to_string())), Ast::List(Localised::dummy_location(vec![ diff --git a/test.sdr b/test.sdr new file mode 100644 index 0000000..1f0a4cd --- /dev/null +++ b/test.sdr @@ -0,0 +1,14 @@ +(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) +(decr 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))) + diff --git a/test.spv b/test.spv new file mode 100644 index 0000000..105937a --- /dev/null +++ b/test.spv @@ -0,0 +1,12 @@ +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %frag_coord %out_color +OpExecutionMode %main OriginUpperLeft +%f32 = OpTypeFloat 32 +%v4f32 = OpTypeVector %f32 4 +%pv4f32i = OpTypePointer Input %v4f32 +%frag_coord = OpVariable %pv4f32i Input +OpDecorate %frag_coord BuiltIn FragCoord +%pv4f32o = OpTypePointer Output %v4f32 +%out_color = OpVariable %pv4f32o Output +OpDecorate %out_color Location 0