1use crate::{
2 backends::{Backend, GeneratedFiles},
3 config::GaiaConfig,
4 instruction::{CastKind, CmpCondition, CoreInstruction, GaiaInstruction, ManagedInstruction},
5 program::{GaiaFunction, GaiaModule},
6 types::GaiaType,
7};
8use gaia_binary::{BinaryWriter, Leb128};
9use gaia_types::{
10 helpers::{Architecture, ArtifactType, CompilationTarget},
11 Result,
12};
13use nyar_assembler::program::{
14 instructions::NyarCodec,
15 pool::NyarConstantPool,
16 types::{NyarChunk, NyarConstant, NyarModule},
17 NyarInstruction,
18};
19use std::collections::HashMap;
20
21pub struct NyarBackend;
25
26impl Backend for NyarBackend {
27 fn name(&self) -> &'static str {
28 "nyar"
29 }
30
31 fn primary_target(&self) -> CompilationTarget {
32 CompilationTarget::new("nyar", "nyar", "nyar")
33 }
34
35 fn artifact_type(&self) -> ArtifactType {
36 ArtifactType::Executable
37 }
38
39 fn match_score(&self, target: &CompilationTarget) -> f32 {
40 if target.build == Architecture::Nyar {
41 100.0
42 }
43 else {
44 0.0
45 }
46 }
47
48 fn generate(&self, program: &GaiaModule, config: &GaiaConfig) -> Result<GeneratedFiles> {
49 let mut nyar_module = NyarModule::default();
50 let mut constant_pool = NyarConstantPool::new();
51
52 for func in &program.functions {
53 let chunk = self.translate_function(func, &mut constant_pool)?;
54 nyar_module.chunks.push(chunk);
55 }
56
57 nyar_module.constants = constant_pool.pool;
58
59 Ok(GeneratedFiles {
60 artifact_type: ArtifactType::Executable,
61 files: HashMap::new(),
62 custom: Some(std::sync::Arc::new(nyar_module)),
63 diagnostics: vec![],
64 })
65 }
66}
67
68impl NyarBackend {
69 fn translate_function(&self, func: &GaiaFunction, pool: &mut NyarConstantPool) -> Result<NyarChunk> {
70 let mut chunk = NyarChunk::default();
71 let mut instructions = Vec::new();
72 let mut label_positions = std::collections::HashMap::new();
73
74 for block in &func.blocks {
76 label_positions.insert(block.label.clone(), instructions.len());
78
79 for inst in &block.instructions {
80 self.translate_instruction(inst, &mut instructions, pool)?;
81 }
82 self.translate_terminator(&block.terminator, &mut instructions, pool)?;
84 }
85
86 let mut fixed_instructions = Vec::new();
88 for (i, inst) in instructions.iter().enumerate() {
89 match inst {
90 NyarInstruction::Jump(_) => {
91 fixed_instructions.push(NyarInstruction::Jump(0));
93 }
94 NyarInstruction::JumpIfFalse(_) => {
95 fixed_instructions.push(NyarInstruction::JumpIfFalse(0));
96 }
97 NyarInstruction::JumpIfTrue(_) => {
98 fixed_instructions.push(NyarInstruction::JumpIfTrue(0));
99 }
100 _ => {
101 fixed_instructions.push(inst.clone());
102 }
103 }
104 }
105
106 let mut writer = BinaryWriter::<Vec<u8>, Leb128>::new(Vec::new());
107 for inst in fixed_instructions {
108 inst.encode(&mut writer).map_err(|e| gaia_types::GaiaError::custom_error(e.to_string()))?;
109 }
110 chunk.code = writer.into_inner();
111
112 Ok(chunk)
113 }
114
115
116 fn translate_instruction(
117 &self,
118 inst: &GaiaInstruction,
119 out: &mut Vec<NyarInstruction>,
120 pool: &mut NyarConstantPool,
121 ) -> Result<()> {
122 match inst {
123 GaiaInstruction::Core(core) => self.translate_core(core, out, pool),
124 GaiaInstruction::Managed(managed) => self.translate_managed(managed, out, pool),
125 GaiaInstruction::Domain(_) => Ok(()),
126 }
127 }
128
129 fn translate_core(
130 &self,
131 inst: &CoreInstruction,
132 out: &mut Vec<NyarInstruction>,
133 pool: &mut NyarConstantPool,
134 ) -> Result<()> {
135 use crate::program::GaiaConstant;
136 match inst {
137 CoreInstruction::PushConstant(c) => match c {
138 GaiaConstant::I64(v) => out.push(NyarInstruction::I64Const(*v)),
139 GaiaConstant::F64(v) => out.push(NyarInstruction::F64Const(*v)),
140 GaiaConstant::I32(v) => out.push(NyarInstruction::I32Const(*v)),
141 GaiaConstant::F32(v) => out.push(NyarInstruction::F32Const(*v)),
142 GaiaConstant::String(s) => {
143 let idx = pool.add(NyarConstant::String(s.clone()));
144 out.push(NyarInstruction::Push(idx));
145 }
146 other => {
147 eprintln!("Warning: Unhandled constant type: {:?}", other);
149 }
150 },
151 CoreInstruction::Add(ty) => {
152 match ty {
153 GaiaType::I32 => out.push(NyarInstruction::I32Add),
154 GaiaType::I64 => out.push(NyarInstruction::I64Add),
155 GaiaType::F32 => out.push(NyarInstruction::F32Add),
156 GaiaType::F64 => out.push(NyarInstruction::F64Add),
157 other => {
158 eprintln!("Warning: Unhandled type in Add: {:?}", other);
160 }
161 }
162 }
163 CoreInstruction::Sub(ty) => {
164 match ty {
165 GaiaType::I32 => out.push(NyarInstruction::I32Sub),
166 GaiaType::I64 => out.push(NyarInstruction::I64Sub),
167 GaiaType::F32 => out.push(NyarInstruction::F32Sub),
168 GaiaType::F64 => out.push(NyarInstruction::F64Sub),
169 other => {
170 eprintln!("Warning: Unhandled type in Sub: {:?}", other);
171 }
172 }
173 }
174 CoreInstruction::Mul(ty) => {
175 match ty {
176 GaiaType::I32 => out.push(NyarInstruction::I32Mul),
177 GaiaType::I64 => out.push(NyarInstruction::I64Mul),
178 GaiaType::F32 => out.push(NyarInstruction::F32Mul),
179 GaiaType::F64 => out.push(NyarInstruction::F64Mul),
180 other => {
181 eprintln!("Warning: Unhandled type in Mul: {:?}", other);
182 }
183 }
184 }
185 CoreInstruction::Div(ty) => {
186 match ty {
187 GaiaType::I32 => out.push(NyarInstruction::I32DivS),
188 GaiaType::I64 => out.push(NyarInstruction::I64DivS),
189 GaiaType::F32 => out.push(NyarInstruction::F32Div),
190 GaiaType::F64 => out.push(NyarInstruction::F64Div),
191 other => {
192 eprintln!("Warning: Unhandled type in Div: {:?}", other);
193 }
194 }
195 }
196 CoreInstruction::Rem(ty) => {
197 match ty {
198 GaiaType::I32 => out.push(NyarInstruction::I32RemS),
199 GaiaType::I64 => out.push(NyarInstruction::I64RemS),
200 other => {
201 eprintln!("Warning: Unhandled type in Rem: {:?}", other);
202 }
203 }
204 }
205 CoreInstruction::And(ty) => {
206 match ty {
207 GaiaType::I32 => out.push(NyarInstruction::I32And),
208 GaiaType::I64 => out.push(NyarInstruction::I64And),
209 other => {
210 eprintln!("Warning: Unhandled type in And: {:?}", other);
211 }
212 }
213 }
214 CoreInstruction::Or(ty) => {
215 match ty {
216 GaiaType::I32 => out.push(NyarInstruction::I32Or),
217 GaiaType::I64 => out.push(NyarInstruction::I64Or),
218 other => {
219 eprintln!("Warning: Unhandled type in Or: {:?}", other);
220 }
221 }
222 }
223 CoreInstruction::Xor(ty) => {
224 match ty {
225 GaiaType::I32 => out.push(NyarInstruction::I32Xor),
226 GaiaType::I64 => out.push(NyarInstruction::I64Xor),
227 other => {
228 eprintln!("Warning: Unhandled type in Xor: {:?}", other);
229 }
230 }
231 }
232 CoreInstruction::Shl(ty) => {
233 match ty {
234 GaiaType::I32 => out.push(NyarInstruction::I32Shl),
235 GaiaType::I64 => out.push(NyarInstruction::I64Shl),
236 other => {
237 eprintln!("Warning: Unhandled type in Shl: {:?}", other);
238 }
239 }
240 }
241 CoreInstruction::Shr(ty) => {
242 match ty {
243 GaiaType::I32 => out.push(NyarInstruction::I32ShrS),
244 GaiaType::I64 => out.push(NyarInstruction::I64ShrS),
245 other => {
246 eprintln!("Warning: Unhandled type in Shr: {:?}", other);
247 }
248 }
249 }
250 CoreInstruction::Neg(ty) => {
251 match ty {
252 GaiaType::I32 => out.push(NyarInstruction::I32Neg),
253 GaiaType::I64 => out.push(NyarInstruction::I64Neg),
254 GaiaType::F32 => out.push(NyarInstruction::F32Neg),
255 GaiaType::F64 => out.push(NyarInstruction::F64Neg),
256 other => {
257 eprintln!("Warning: Unhandled type in Neg: {:?}", other);
258 }
259 }
260 }
261 CoreInstruction::Not(ty) => {
262 match ty {
263 GaiaType::I32 => out.push(NyarInstruction::I32Not),
264 GaiaType::I64 => out.push(NyarInstruction::I64Not),
265 other => {
266 eprintln!("Warning: Unhandled type in Not: {:?}", other);
267 }
268 }
269 }
270 CoreInstruction::Ret => out.push(NyarInstruction::Return),
271 CoreInstruction::LoadLocal(idx, _) => out.push(NyarInstruction::LoadLocal(*idx as u8)),
272 CoreInstruction::StoreLocal(idx, _) => out.push(NyarInstruction::StoreLocal(*idx as u8)),
273 CoreInstruction::LoadArg(idx, _) => out.push(NyarInstruction::LoadLocal(*idx as u8)),
274 CoreInstruction::StoreArg(idx, _) => out.push(NyarInstruction::StoreLocal(*idx as u8)),
275 CoreInstruction::Pop => out.push(NyarInstruction::Pop),
276 CoreInstruction::Dup => out.push(NyarInstruction::Dup(0)),
277 CoreInstruction::Cmp(cond, ty) => {
278 match ty {
279 GaiaType::I32 => match cond {
280 CmpCondition::Eq => out.push(NyarInstruction::I32Eq),
281 CmpCondition::Ne => out.push(NyarInstruction::I32Ne),
282 CmpCondition::Lt => out.push(NyarInstruction::I32LtS),
283 CmpCondition::Le => out.push(NyarInstruction::I32LeS),
284 CmpCondition::Gt => out.push(NyarInstruction::I32GtS),
285 CmpCondition::Ge => out.push(NyarInstruction::I32GeS),
286 },
287 GaiaType::I64 => match cond {
288 CmpCondition::Eq => out.push(NyarInstruction::I64Eq),
289 CmpCondition::Ne => out.push(NyarInstruction::I64Ne),
290 CmpCondition::Lt => out.push(NyarInstruction::I64LtS),
291 CmpCondition::Le => out.push(NyarInstruction::I64LeS),
292 CmpCondition::Gt => out.push(NyarInstruction::I64GtS),
293 CmpCondition::Ge => out.push(NyarInstruction::I64GeS),
294 },
295 GaiaType::F32 => match cond {
296 CmpCondition::Eq => out.push(NyarInstruction::F32Eq),
297 CmpCondition::Ne => out.push(NyarInstruction::F32Ne),
298 CmpCondition::Lt => out.push(NyarInstruction::F32Lt),
299 CmpCondition::Le => out.push(NyarInstruction::F32Le),
300 CmpCondition::Gt => out.push(NyarInstruction::F32Gt),
301 CmpCondition::Ge => out.push(NyarInstruction::F32Ge),
302 },
303 GaiaType::F64 => match cond {
304 CmpCondition::Eq => out.push(NyarInstruction::F64Eq),
305 CmpCondition::Ne => out.push(NyarInstruction::F64Ne),
306 CmpCondition::Lt => out.push(NyarInstruction::F64Lt),
307 CmpCondition::Le => out.push(NyarInstruction::F64Le),
308 CmpCondition::Gt => out.push(NyarInstruction::F64Gt),
309 CmpCondition::Ge => out.push(NyarInstruction::F64Ge),
310 },
311 other => {
312 eprintln!("Warning: Unhandled type in Cmp: {:?}", other);
313 }
314 }
315 }
316 CoreInstruction::Br(label) => {
317 out.push(NyarInstruction::Jump(0));
319 }
320 CoreInstruction::BrTrue(_label) => {
321 out.push(NyarInstruction::JumpIfTrue(0));
323 }
324 CoreInstruction::BrFalse(_label) => {
325 out.push(NyarInstruction::JumpIfFalse(0));
327 }
328 CoreInstruction::Call(func_name, args_count) => {
329 let idx = pool.add(NyarConstant::String(func_name.clone()));
330 out.push(NyarInstruction::Call(idx, *args_count as u8));
331 }
332 CoreInstruction::CallIndirect(args_count) => {
333 out.push(NyarInstruction::CallClosure(*args_count as u8));
334 }
335 CoreInstruction::New(type_name) => {
336 let idx = pool.add(NyarConstant::String(type_name.clone()));
337 out.push(NyarInstruction::NewObject(idx));
338 }
339 CoreInstruction::NewArray(_ty, _is_length_on_stack) => {
340 out.push(NyarInstruction::NewArray(0));
342 }
343 CoreInstruction::LoadField(_obj_type, field_name) => {
344 let idx = pool.add(NyarConstant::String(field_name.clone()));
345 out.push(NyarInstruction::GetField(idx));
346 }
347 CoreInstruction::StoreField(_obj_type, field_name) => {
348 let idx = pool.add(NyarConstant::String(field_name.clone()));
349 out.push(NyarInstruction::SetField(idx));
350 }
351 CoreInstruction::LoadElement(_ty) => {
352 out.push(NyarInstruction::GetElement);
353 }
354 CoreInstruction::StoreElement(_ty) => {
355 out.push(NyarInstruction::SetElement);
356 }
357 CoreInstruction::ArrayLength => {
358 out.push(NyarInstruction::SizeOf);
359 }
360 CoreInstruction::ArrayPush => {
361 out.push(NyarInstruction::PushElementRight);
362 }
363 CoreInstruction::StructNew(struct_name) => {
364 let idx = pool.add(NyarConstant::String(struct_name.clone()));
365 out.push(NyarInstruction::NewObject(idx));
366 }
367 CoreInstruction::StructGet { struct_name: _, field_index, is_signed: _ } => {
368 let idx = pool.add(NyarConstant::String(format!("field_{}", field_index)));
370 out.push(NyarInstruction::GetField(idx));
371 }
372 CoreInstruction::StructSet { struct_name: _, field_index } => {
373 let idx = pool.add(NyarConstant::String(format!("field_{}", field_index)));
375 out.push(NyarInstruction::SetField(idx));
376 }
377 CoreInstruction::ArrayNew(array_name) => {
378 pool.add(NyarConstant::String(array_name.clone()));
379 out.push(NyarInstruction::NewArray(0));
380 }
381 CoreInstruction::ArrayGet { array_name: _, is_signed: _ } => {
382 out.push(NyarInstruction::GetElement);
383 }
384 CoreInstruction::ArraySet(_array_name) => {
385 out.push(NyarInstruction::SetElement);
386 }
387 CoreInstruction::Cast { from, to, kind: _ } => {
388 match (from, to) {
390 (GaiaType::I32, GaiaType::I64) => out.push(NyarInstruction::I32Extend64S),
391 (GaiaType::I32, GaiaType::F32) => out.push(NyarInstruction::I32ToF32S),
392 (GaiaType::I32, GaiaType::F64) => out.push(NyarInstruction::I32ToF64S),
393 (GaiaType::I64, GaiaType::I32) => out.push(NyarInstruction::I32Trunc64S),
394 (GaiaType::I64, GaiaType::F32) => out.push(NyarInstruction::I64ToF32S),
395 (GaiaType::I64, GaiaType::F64) => out.push(NyarInstruction::I64ToF64S),
396 (GaiaType::F32, GaiaType::I32) => out.push(NyarInstruction::F32ToI32S),
397 (GaiaType::F32, GaiaType::I64) => out.push(NyarInstruction::F32ToI64S),
398 (GaiaType::F32, GaiaType::F64) => out.push(NyarInstruction::F32ToF64),
399 (GaiaType::F64, GaiaType::I32) => out.push(NyarInstruction::F64ToI32S),
400 (GaiaType::F64, GaiaType::I64) => out.push(NyarInstruction::F64ToI64S),
401 (GaiaType::F64, GaiaType::F32) => out.push(NyarInstruction::F64ToF32),
402 _ => {
403 let idx = pool.add(NyarConstant::String(to.to_string()));
405 out.push(NyarInstruction::Cast(idx));
406 }
407 }
408 }
409 CoreInstruction::Alloca(_ty, count) => {
410 for _ in 0..*count {
412 out.push(NyarInstruction::PushNone);
413 }
414 }
415 CoreInstruction::Load(_ty) => {
416 out.push(NyarInstruction::GetElement);
418 }
419 CoreInstruction::Store(_ty) => {
420 out.push(NyarInstruction::SetElement);
422 }
423 CoreInstruction::Gep { base_type: _, indices } => {
424 for _ in 0..indices.len() {
426 out.push(NyarInstruction::GetElement);
427 }
428 }
429
430 CoreInstruction::Label(_label) => {
431 }
433 CoreInstruction::Throw => {
434 out.push(NyarInstruction::Halt);
436 }
437 }
438 Ok(())
439 }
440
441 fn translate_managed(
442 &self,
443 inst: &ManagedInstruction,
444 out: &mut Vec<NyarInstruction>,
445 pool: &mut NyarConstantPool,
446 ) -> Result<()> {
447 match inst {
448 ManagedInstruction::Initiate(args) => out.push(NyarInstruction::Initiate(*args as u8)),
449 ManagedInstruction::Finalize => out.push(NyarInstruction::Finalize),
450 ManagedInstruction::CallMethod { target: _, method, signature, is_virtual, call_site_id: _ } => {
451 let idx = pool.add(NyarConstant::String(method.clone()));
452 if *is_virtual {
453 out.push(NyarInstruction::CallVirtual(idx, signature.params.len() as u8));
454 } else {
455 out.push(NyarInstruction::InvokeMethod(idx, signature.params.len() as u8));
456 }
457 }
458 ManagedInstruction::CallStatic { target, method, signature } => {
459 let idx = pool.add(NyarConstant::String(format!("{}.{}", target, method)));
460 out.push(NyarInstruction::Call(idx, signature.params.len() as u8));
461 }
462 ManagedInstruction::Box(_ty) => {
463 }
465 ManagedInstruction::Unbox(_ty) => {
466 }
468 ManagedInstruction::InstanceOf(ty) => {
469 let idx = pool.add(NyarConstant::String(ty.to_string()));
470 out.push(NyarInstruction::InstanceOf(idx));
471 }
472 ManagedInstruction::CheckCast(ty) => {
473 let idx = pool.add(NyarConstant::String(ty.to_string()));
474 out.push(NyarInstruction::CheckCast(idx));
475 }
476 }
477 Ok(())
478 }
479
480 fn translate_terminator(
481 &self,
482 term: &crate::program::GaiaTerminator,
483 out: &mut Vec<NyarInstruction>,
484 pool: &mut NyarConstantPool,
485 ) -> Result<()> {
486 use crate::program::GaiaTerminator::*;
487 match term {
488 Return => out.push(NyarInstruction::Return),
489 Halt => out.push(NyarInstruction::Halt),
490 Jump(_) => {
491 out.push(NyarInstruction::Jump(0));
492 }
493 Branch { .. } => {
494 out.push(NyarInstruction::JumpIfFalse(0));
495 }
496 Call { callee, args_count, .. } => {
497 let idx = pool.add(NyarConstant::String(callee.clone()));
498 out.push(NyarInstruction::Call(idx, *args_count as u8));
499 }
500 }
501 Ok(())
502 }
503}