From 3d5369cc365478b31909138be5750841267ece46 Mon Sep 17 00:00:00 2001 From: itycodes Date: Thu, 6 Mar 2025 11:25:52 +0100 Subject: [PATCH] Broken; Rust's Display trait is weird. Help. --- src/compiler/backend/mod.rs | 118 ++++++++++++++++++++++++++++++++-- src/compiler/backend/tests.rs | 14 ++++ src/compiler/mod.rs | 12 ++++ src/compiler/tests.rs | 2 +- 4 files changed, 141 insertions(+), 5 deletions(-) diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs index 77e4b81..74193c5 100644 --- a/src/compiler/backend/mod.rs +++ b/src/compiler/backend/mod.rs @@ -2,9 +2,114 @@ mod tests; use crate::compiler::Module; -use std::{fmt::Write, ops::Add}; +use std::fmt::Write; +use std::fmt; -pub fn fix_name(name: &String) -> String { +use super::StorageClass; + +#[derive(Debug, PartialEq, Clone)] +pub enum Type { + Pointer(Box, StorageClass), + Vector(Box, u32), + Float(u32), + Int(u32), + Unsigned(u32), +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Type::Pointer(typ, storage_class) => { + match storage_class { + StorageClass::Input => write!(f, "*{}i", typ), + StorageClass::Output => write!(f, "*{}o", typ), + StorageClass::Undefined => panic!("Bound a non-declared variable"), + } + }, + Type::Vector(typ, size) => write!(f, "v{}{}", size, typ), + Type::Float(size) => write!(f, "f{}", size), + Type::Int(size) => write!(f, "s{}", size), + Type::Unsigned(size) => write!(f, "u{}", size), + } + } +} + +pub fn parse_type(typ: String) -> Type { + // pointers have the format *i or *o, for the storage class + // floats have the format f, so f32, f64... + // ints have the format s, so s32, s64... + // unsigned ints have the format u, so u32, u64... + // 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(); + chars.next(); + let typ = chars.collect::(); + 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::(); + 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(); + let typ = chars.collect::(); + Type::Vector(Box::new(parse_type(typ)), size) + }, + 'f' => { + let size = typ.chars().skip(1).collect::().parse().unwrap(); + Type::Float(size) + }, + 's' => { + let size = typ.chars().skip(1).collect::().parse().unwrap(); + Type::Int(size) + }, + 'u' => { + let size = typ.chars().skip(1).collect::().parse().unwrap(); + Type::Unsigned(size) + }, + _ => panic!("Invalid type"), + } + +} + +fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) { + match typ { + Type::Unsigned(size) => { + ops.push((format!("%u{}", size).to_string(), format!("OpTypeInt {}", size))); + }, + Type::Int(size) => { + ops.push((format!("%s{}", size).to_string(), format!("OpTypeInt {}", size))); + }, + Type::Float(size) => { + ops.push((format!("%f{}", size).to_string(), format!("OpTypeFloat {}", size))); + }, + Type::Vector(typ, size) => { + emit_type(*typ.clone(), ops); + let typ_id = format!("%{}", *typ.clone()); + ops.push((format!("%v{}{}", typ_id, size).to_string(), format!("OpTypeVector {} {}", typ_id, size))) + }, + Type::Pointer(typ, storage_class) => { + emit_type(*typ.clone(), ops); + let typ_id = format!("%{}", *typ.clone()); + let storage_class = match storage_class { + StorageClass::Input => "Input", + StorageClass::Output => "Output", + StorageClass::Undefined => panic!("Bound a non-declared variable"), + }; + ops.push((format!("%{}{}", typ_id, storage_class).to_string(), format!("OpTypePointer {} {}", storage_class, typ_id))) + }, + } +} + +fn fix_name(name: &String) -> String { format!("%{}", name.clone().replace("-", "_")) } @@ -51,13 +156,18 @@ 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"), }; - let typ_id = "%undefined_type"; + let typ_id = format!("%{}", _typ); + let mut type_ops = Vec::new(); + emit_type(parse_type(_typ), &mut type_ops); + for op in type_ops { + ops.push((Some(op.0), vec![op.1])); + } 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 diff --git a/src/compiler/backend/tests.rs b/src/compiler/backend/tests.rs index 87c258d..e84c06b 100644 --- a/src/compiler/backend/tests.rs +++ b/src/compiler/backend/tests.rs @@ -22,4 +22,18 @@ fn test_emit() { let module = meta_compile(&mut ast); let res = spirv_meta(module); println!("{}", res); +} + +#[test] +fn test_type_parse() { + use crate::compiler::backend::*; + use Type::*; + assert_eq!(parse_type("*v4f32i".to_string()), + Pointer(Box::new(Vector(Box::new(Float(32)), 4)), StorageClass::Input)); + assert_eq!(parse_type("*v4f32o".to_string()), + Pointer(Box::new(Vector(Box::new(Float(32)), 4)), StorageClass::Output)); + assert_eq!(parse_type("v2f32".to_string()), + Vector(Box::new(Float(32)), 2)); + assert_eq!(parse_type("f32".to_string()), Float(32)); + assert_eq!(parse_type("s32".to_string()), Int(32)); } \ No newline at end of file diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 9a83957..140a57a 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -2,6 +2,8 @@ use crate::parser::Ast; pub mod backend; +use std::fmt; + #[cfg(test)] mod tests; @@ -75,6 +77,16 @@ pub enum StorageClass { Output, } +impl fmt::Display for StorageClass { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + StorageClass::Undefined => write!(f, "Undefined"), + StorageClass::Input => write!(f, "Input"), + StorageClass::Output => write!(f, "Output"), + } + } +} + #[derive(Debug, PartialEq, Default, Clone)] pub struct GlobalVariable { pub name: String, diff --git a/src/compiler/tests.rs b/src/compiler/tests.rs index 08b18e9..33398bd 100644 --- a/src/compiler/tests.rs +++ b/src/compiler/tests.rs @@ -28,7 +28,7 @@ fn test_compile() { execution_model: ExecutionModel::Fragment, execution_mode: ExecutionMode::OriginUpperLeft, name: "main".to_string(), - interface: vec![":frag-coord".to_string(), ":out-color".to_string()], + interface: vec!["frag-coord".to_string(), "out-color".to_string()], }], globals: vec![ GlobalVariable {