gaia_assembler/assembler/
mod.rs1mod performance;
6
7use crate::{backends::*, program::GaiaModule};
8use gaia_types::{helpers::CompilationTarget, GaiaErrorKind, *};
9use std::collections::HashMap;
10use performance::{PerformanceGuard, PerformanceMonitor};
11
12pub struct GaiaAssembler {
14 backends: Vec<Box<dyn Backend>>,
15 backend_cache: std::sync::Arc<std::sync::Mutex<HashMap<CompilationTarget, Box<dyn Backend>>>>,
16 performance_monitor: PerformanceMonitor,
17}
18
19impl GaiaAssembler {
20 pub fn new() -> Self {
22 #[allow(unused_mut)]
23 let mut backends: Vec<Box<dyn Backend>> = vec![];
24
25 #[cfg(feature = "jvm-assembler")]
26 backends.push(Box::new(JvmBackend {}));
27 #[cfg(feature = "pe-assembler")]
28 backends.push(Box::new(WindowsBackend {}));
29 #[cfg(feature = "wasi-assembler")]
30 backends.push(Box::new(WasiBackend {}));
31 #[cfg(feature = "x86_64-assembler")]
32 backends.push(Box::new(X64Backend::new()));
33 #[cfg(feature = "gcn-assembler")]
34 backends.push(Box::new(GcnBackend::new()));
35 #[cfg(feature = "sass-assembler")]
36 backends.push(Box::new(SassBackend::new()));
37 #[cfg(feature = "clr-assembler")]
38 backends.push(Box::new(ClrBackend {}));
39 #[cfg(feature = "elf-assembler")]
40 backends.push(Box::new(ElfBackend {}));
41 #[cfg(feature = "macho-assembler")]
42 backends.push(Box::new(MachoBackend {}));
43 #[cfg(feature = "lua-assembler")]
44 backends.push(Box::new(LuaBackend {}));
45 #[cfg(feature = "llvm-assembler")]
46 backends.push(Box::new(LlvmBackend {}));
47 #[cfg(feature = "msl-assembler")]
48 backends.push(Box::new(MslBackend {}));
49 #[cfg(feature = "spirv-assembler")]
50 backends.push(Box::new(SpirvBackend {}));
51 #[cfg(feature = "python-assembler")]
52 backends.push(Box::new(PythonBackend {}));
53 #[cfg(feature = "nyar-assembler")]
54 backends.push(Box::new(NyarBackend {}));
55
56 Self {
57 backends,
58 backend_cache: std::sync::Arc::new(std::sync::Mutex::new(HashMap::new())),
59 performance_monitor: PerformanceMonitor::new()
60 }
61 }
62
63 pub fn compile(&mut self, program: &GaiaModule, target: &CompilationTarget) -> Result<GeneratedFiles> {
65 self.performance_monitor.start("compile");
66
67 self.performance_monitor.start("cache_check");
69 let cache_result: Option<Result<GeneratedFiles>> = {
70 if let Ok(mut cache) = self.backend_cache.lock() {
71 if let Some(cached_backend) = cache.get(target) {
72 let mut config = crate::config::GaiaConfig::default();
73 config.target = target.clone();
74 let result = cached_backend.generate(program, &config);
75 if let Ok(mut generated_files) = result {
76 let backend_name = cached_backend.name();
78 let diagnostic = GaiaError::custom_error(format!("Using cached backend: {}", backend_name));
79 generated_files.diagnostics.push(diagnostic);
80 self.performance_monitor.stop("cache_check");
81 self.performance_monitor.stop("compile");
82 return Ok(generated_files);
83 }
84 self.performance_monitor.stop("cache_check");
85 self.performance_monitor.stop("compile");
86 return result;
87 }
88 }
89 None
90 };
91 self.performance_monitor.stop("cache_check");
92
93 let mut best_backend: Option<&Box<dyn Backend>> = None;
95 let mut best_score = 0.0;
96
97 self.performance_monitor.start("backend_selection");
99 if let Some(candidate) = self.backends.iter().find(|b| {
100 let pt = b.primary_target();
101 pt.host == target.host && pt.build == target.build
102 }) {
103 best_backend = Some(candidate);
104 best_score = 100.0; }
106
107 if best_backend.is_none() {
109 for backend in &self.backends {
110 let score = backend.match_score(target);
111 if score > best_score {
112 best_score = score;
113 best_backend = Some(backend);
114 }
115 }
116 }
117 self.performance_monitor.stop("backend_selection");
118
119 if best_backend.is_none() || best_score <= 0.0 {
120 self.performance_monitor.stop("compile");
121 return Err(GaiaErrorKind::UnsupportedTarget { target: target.clone() }.into());
122 }
123
124 let mut config = crate::config::GaiaConfig::default();
126 config.target = target.clone();
127
128 self.performance_monitor.start("backend_generate");
130 let result = best_backend.unwrap().generate(program, &config);
131 self.performance_monitor.stop("backend_generate");
132
133 if let Ok(mut generated_files) = result {
134 let backend_name = best_backend.unwrap().name();
136 let diagnostic = GaiaError::custom_error(format!("Selected backend: {} with score: {:.2}", backend_name, best_score));
137 generated_files.diagnostics.push(diagnostic);
138 self.performance_monitor.stop("compile");
139 return Ok(generated_files);
140 }
141 self.performance_monitor.stop("compile");
142 result
143 }
144
145 pub fn print_performance_report(&self) {
147 self.performance_monitor.print_report();
148 }
149
150 pub fn performance_monitor(&self) -> &PerformanceMonitor {
152 &self.performance_monitor
153 }
154
155 pub fn backends(&self) -> &[Box<dyn Backend>] {
157 &self.backends
158 }
159}
160
161pub fn compile_to_platform(program: &GaiaModule, target: CompilationTarget) -> Result<Vec<u8>> {
163 let mut compiler = GaiaAssembler::new();
164 let generated_files = compiler.compile(program, &target)?;
165
166 if let Some((_, bytes)) = generated_files.files.iter().next() {
169 Ok(bytes.clone())
170 }
171 else {
172 Err(GaiaError::invalid_data("No output files generated"))
173 }
174}