diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs
index 74193c5..e88ceed 100644
--- a/src/compiler/backend/mod.rs
+++ b/src/compiler/backend/mod.rs
@@ -34,7 +34,7 @@ impl fmt::Display for Type {
     }
 }
 
-pub fn parse_type(typ: String) -> Type {
+pub fn parse_type(typ: &String) -> Type {
     // pointers have the format *<t>i or *<t>o, for the storage class
     // floats have the format f<size>, so f32, f64...
     // ints have the format s<size>, so s32, s64...
@@ -54,14 +54,14 @@ pub fn parse_type(typ: String) -> Type {
                 _ => panic!("Invalid storage class"),
             };
             let typ = typ.chars().take(typ.len() - 1).collect::<String>();
-            Type::Pointer(Box::new(parse_type(typ)), storage_class)
+            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::<String>();
-            Type::Vector(Box::new(parse_type(typ)), size)
+            Type::Vector(Box::new(parse_type(&typ)), size)
         },
         'f' => {
             let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
@@ -81,7 +81,7 @@ pub fn parse_type(typ: String) -> Type {
 }
 
 fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
-    match typ {
+    match &typ {
         Type::Unsigned(size) => {
             ops.push((format!("%u{}", size).to_string(), format!("OpTypeInt {}", size)));
         },
@@ -91,26 +91,34 @@ fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
         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::Vector(in_typ, size) => {
+            emit_type(*in_typ.clone(), ops);
+            ops.push((fix_name(&typ.to_string()), format!("OpTypeVector {} {}", fix_name(&in_typ.clone().to_string()), size)))
         },
-        Type::Pointer(typ, storage_class) => {
-            emit_type(*typ.clone(), ops);
-            let typ_id = format!("%{}", *typ.clone());
+        Type::Pointer(in_typ, storage_class) => {
+            emit_type(*in_typ.clone(), ops);
+            let typ_id = fix_name(&typ.to_string());
             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)))
+            ops.push((typ_id, format!("OpTypePointer {} {}", storage_class, fix_name(&in_typ.to_string()))))
         },
     }
 }
 
 fn fix_name(name: &String) -> String {
-    format!("%{}", name.clone().replace("-", "_"))
+    format!("%{}", name.clone().replace("-", "_").replace("*", "p"))
+}
+
+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: Module) -> String {
@@ -162,13 +170,15 @@ pub fn spirv_meta(module: Module) -> String {
             crate::compiler::StorageClass::Output => "Output",
             crate::compiler::StorageClass::Undefined => panic!("Bound a non-declared variable"),
         };
-        let typ_id = format!("%{}", _typ);
         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;
+            }
             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()]));
+        ops.push((Some(name.clone()), vec!["OpVariable".to_string(), 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 {
diff --git a/src/compiler/backend/tests.rs b/src/compiler/backend/tests.rs
index e84c06b..0f21e2f 100644
--- a/src/compiler/backend/tests.rs
+++ b/src/compiler/backend/tests.rs
@@ -28,12 +28,12 @@ fn test_emit() {
 fn test_type_parse() {
     use crate::compiler::backend::*;
     use Type::*;
-    assert_eq!(parse_type("*v4f32i".to_string()),
+    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()),
+    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()),
+    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));
+    assert_eq!(parse_type(&"f32".to_string()), Float(32));
+    assert_eq!(parse_type(&"s32".to_string()), Int(32));
 }
\ No newline at end of file