1use std::{
27 collections::HashMap,
28 ffi::{CStr, CString, c_void},
29 mem::ManuallyDrop,
30 path::{Path, PathBuf},
31 ptr::null_mut,
32 rc::Rc,
33 sync::OnceLock,
34};
35
36use gimli::{DW_ATE_boolean, DW_ATE_unsigned, DW_TAG_reference_type};
37use irvm::{
38 block::{BlockIdx, DebugOp, DebugVariable, Instruction},
39 common::Location,
40 datalayout::DataLayout,
41 function::Function,
42 module::Module,
43 target_lexicon::Triple,
44 types::{Type, TypeIdx, TypeStorage},
45 value::{ConstValue, Operand},
46};
47
48use itertools::Itertools;
49use llvm_sys::{
50 LLVMIntPredicate, LLVMModule, LLVMOpaqueMetadata, LLVMRealPredicate,
51 core::{self, LLVMDisposeMessage, LLVMDumpModule},
52 debuginfo::{self, LLVMDIFlagPublic, LLVMDWARFEmissionKind},
53 error::LLVMGetErrorMessage,
54 execution_engine::{self, LLVMExecutionEngineRef, LLVMLinkInMCJIT},
55 prelude::{
56 LLVMBasicBlockRef, LLVMBuilderRef, LLVMContextRef, LLVMDIBuilderRef, LLVMMetadataRef,
57 LLVMTypeRef, LLVMValueRef,
58 },
59 target::{
60 LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, LLVM_InitializeAllTargetMCs,
61 LLVM_InitializeAllTargets, LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter,
62 LLVM_InitializeNativeDisassembler, LLVM_InitializeNativeTarget,
63 },
64 target_machine::{
65 self, LLVMCodeGenFileType, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMDisposeTargetMachine,
66 LLVMGetHostCPUFeatures, LLVMGetHostCPUName, LLVMRelocMode, LLVMTargetMachineEmitToFile,
67 },
68 transforms::pass_builder::{
69 LLVMCreatePassBuilderOptions, LLVMDisposePassBuilderOptions, LLVMRunPasses,
70 },
71};
72
73#[derive(Debug)]
74pub enum OutputCompilation {
75 File(PathBuf),
76 Engine(*mut LLVMExecutionEngineRef),
77}
78
79#[derive(Debug, thiserror::Error, Clone)]
81pub enum Error {
82 #[error("llvm error: {:?}", 0)]
83 LLVMError(String),
84 #[error("jit error: {:?}", 0)]
85 JitError(String),
86 #[error(transparent)]
87 NulError(#[from] std::ffi::NulError),
88 #[error("irvm error: {:?}", 0)]
89 IRVMError(#[from] irvm::error::Error),
90}
91
92#[derive(Debug, Clone, Default)]
94pub enum TargetCpu {
95 #[default]
96 Host,
97 Name(String),
98}
99
100#[derive(Debug, Clone, Default)]
102pub enum TargetCpuFeatures {
103 #[default]
104 Host,
105 Features(String),
106}
107
108#[derive(Debug, Clone, Default)]
110pub enum OptLevel {
111 None,
112 Less,
113 #[default]
114 Default,
115 Aggressive,
116}
117
118#[derive(Debug, Clone, Default)]
120pub enum RelocModel {
121 #[default]
123 Default,
124 Static,
126 Pic,
128 DynamicNoPic,
130 Ropi,
135 Rwpi,
143 RopiRwpi,
147}
148
149#[derive(Debug, Clone, Default)]
151pub enum CodeModel {
152 #[default]
153 Default,
154 JitDefault,
155 Tiny,
156 Small,
157 Kernel,
158 Medium,
159 Large,
160}
161
162#[derive(Debug, Clone, Default)]
164pub struct CompileOptions {
165 pub target_cpu: TargetCpu,
166 pub target_cpu_features: TargetCpuFeatures,
167 pub relocation_model: RelocModel,
168 pub code_model: CodeModel,
169 pub opt_level: u8,
170}
171
172#[derive(Debug)]
174pub struct CompileResult {
175 context: LLVMContextRef,
176 module: *mut LLVMModule,
177}
178
179#[derive(Debug)]
181pub struct JitEngine {
182 context: LLVMContextRef,
183 engine: LLVMExecutionEngineRef,
184}
185
186impl Drop for CompileResult {
187 fn drop(&mut self) {
188 unsafe {
189 core::LLVMDisposeModule(self.module);
190 core::LLVMContextDispose(self.context);
191 }
192 }
193}
194
195impl Drop for JitEngine {
196 fn drop(&mut self) {
197 unsafe {
198 execution_engine::LLVMDisposeExecutionEngine(self.engine);
199 core::LLVMContextDispose(self.context);
200 }
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq)]
206pub enum JitValue {
207 U8(u8),
208 U16(u16),
209 U32(u32),
210 U64(u64),
211 I8(i8),
212 I16(i16),
213 I32(i32),
214 I64(i64),
215 F32(f32),
216 F64(f64),
217 Ptr(*mut c_void),
218 Void,
219}
220
221impl JitEngine {
222 pub unsafe fn execute(
228 &self,
229 symbol: &str,
230 args: &[JitValue],
231 return_ty: JitValue,
232 ) -> Result<JitValue, Error> {
233 unsafe {
234 let sym = CString::new(symbol)?;
235 let mut out_fn = null_mut();
236 let ok = execution_engine::LLVMFindFunction(self.engine, sym.as_ptr(), &raw mut out_fn);
237
238 if ok != 0 {
239 return Err(Error::LLVMError("Function not found".to_string()));
240 }
241
242 let mut value_args = Vec::new();
243
244 for arg in args {
245 let value = match arg {
246 JitValue::U8(value) => execution_engine::LLVMCreateGenericValueOfInt(
247 core::LLVMInt8Type(),
248 (*value) as _,
249 0,
250 ),
251 JitValue::U16(value) => execution_engine::LLVMCreateGenericValueOfInt(
252 core::LLVMInt16Type(),
253 (*value) as _,
254 0,
255 ),
256 JitValue::U32(value) => execution_engine::LLVMCreateGenericValueOfInt(
257 core::LLVMInt32Type(),
258 (*value) as _,
259 0,
260 ),
261 JitValue::U64(value) => execution_engine::LLVMCreateGenericValueOfInt(
262 core::LLVMInt64Type(),
263 (*value) as _,
264 0,
265 ),
266 JitValue::I8(value) => execution_engine::LLVMCreateGenericValueOfInt(
267 core::LLVMInt8Type(),
268 (*value) as _,
269 1,
270 ),
271 JitValue::I16(value) => execution_engine::LLVMCreateGenericValueOfInt(
272 core::LLVMInt16Type(),
273 (*value) as _,
274 1,
275 ),
276 JitValue::I32(value) => execution_engine::LLVMCreateGenericValueOfInt(
277 core::LLVMInt32Type(),
278 (*value) as _,
279 1,
280 ),
281 JitValue::I64(value) => execution_engine::LLVMCreateGenericValueOfInt(
282 core::LLVMInt64Type(),
283 (*value) as _,
284 1,
285 ),
286 JitValue::F32(value) => execution_engine::LLVMCreateGenericValueOfFloat(
287 core::LLVMFloatType(),
288 (*value) as _,
289 ),
290 JitValue::F64(value) => execution_engine::LLVMCreateGenericValueOfFloat(
291 core::LLVMDoubleType(),
292 (*value) as _,
293 ),
294 JitValue::Ptr(value) => {
295 execution_engine::LLVMCreateGenericValueOfPointer(*value)
296 }
297 JitValue::Void => {
298 return Err(Error::JitError(
299 "can't use void jit value as argument".to_string(),
300 ));
301 }
302 };
303 value_args.push(value);
304 }
305
306 let result = execution_engine::LLVMRunFunction(
307 self.engine,
308 out_fn,
309 value_args.len() as _,
310 value_args.as_mut_ptr(),
311 );
312
313 let res = match return_ty {
314 JitValue::U8(_) => {
315 JitValue::U8(execution_engine::LLVMGenericValueToInt(result, 0) as u8)
316 }
317 JitValue::U16(_) => {
318 JitValue::U16(execution_engine::LLVMGenericValueToInt(result, 0) as u16)
319 }
320 JitValue::U32(_) => {
321 JitValue::U32(execution_engine::LLVMGenericValueToInt(result, 0) as u32)
322 }
323 JitValue::U64(_) => {
324 JitValue::U64(execution_engine::LLVMGenericValueToInt(result, 0) as u64)
325 }
326 JitValue::I8(_) => {
327 JitValue::I8(execution_engine::LLVMGenericValueToInt(result, 1) as i8)
328 }
329 JitValue::I16(_) => {
330 JitValue::I16(execution_engine::LLVMGenericValueToInt(result, 1) as i16)
331 }
332 JitValue::I32(_) => {
333 JitValue::I32(execution_engine::LLVMGenericValueToInt(result, 1) as i32)
334 }
335 JitValue::I64(_) => {
336 JitValue::I64(execution_engine::LLVMGenericValueToInt(result, 1) as i64)
337 }
338 JitValue::F32(_) => JitValue::F32(execution_engine::LLVMGenericValueToFloat(
339 core::LLVMFloatType(),
340 result,
341 ) as f32),
342 JitValue::F64(_) => JitValue::F64(execution_engine::LLVMGenericValueToFloat(
343 core::LLVMDoubleType(),
344 result,
345 ) as f64),
346 JitValue::Ptr(_) => {
347 JitValue::Ptr(execution_engine::LLVMGenericValueToPointer(result))
348 }
349 JitValue::Void => JitValue::Void,
350 };
351
352 for arg in &value_args {
353 execution_engine::LLVMDisposeGenericValue(*arg);
354 }
355 execution_engine::LLVMDisposeGenericValue(result);
356
357 Ok(res)
358 }
359 }
360}
361
362impl CompileResult {
363 pub fn dump(&self) {
364 unsafe {
365 LLVMDumpModule(self.module);
366 }
367 }
368}
369
370pub fn lower_module_to_llvmir(
372 module: &Module,
373 storage: &TypeStorage,
374) -> Result<CompileResult, Error> {
375 unsafe {
376 let ctx = core::LLVMContextCreate();
377 let module_name = CString::new(module.name.clone())?;
378 let llvm_module = core::LLVMModuleCreateWithNameInContext(module_name.as_ptr(), ctx);
379
380 let datalayout_str = CString::new(module.data_layout.to_llvm_string()).unwrap();
381 core::LLVMSetDataLayout(llvm_module, datalayout_str.as_ptr());
382 let triple_str = CString::new(module.target_triple.to_string()).unwrap();
383 core::LLVMSetTarget(llvm_module, triple_str.as_ptr());
384
385 let mut functions: HashMap<_, _> = Default::default();
386 let mut dfunctions: HashMap<_, _> = Default::default();
387 let builder = core::LLVMCreateBuilderInContext(ctx);
389 let dibuilder = debuginfo::LLVMCreateDIBuilder(llvm_module);
390
391 let compile_unit_file = get_difile_location(dibuilder, &module.location);
392
393 let producer = c"IRVM version 0.1.0";
394 let flags = c"";
395 let splitname = c"";
396 let sysroot = c"";
397 let sdk = c"";
398
399 let compile_unit = debuginfo::LLVMDIBuilderCreateCompileUnit(
400 dibuilder,
401 debuginfo::LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageC17,
402 compile_unit_file,
403 producer.as_ptr(),
404 producer.count_bytes(),
405 0,
406 flags.as_ptr(),
407 flags.count_bytes(),
408 0,
409 splitname.as_ptr(),
410 splitname.count_bytes(),
411 LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull,
412 0,
413 0,
414 0,
415 sysroot.as_ptr(),
416 sysroot.count_bytes(),
417 sdk.as_ptr(),
418 sdk.count_bytes(),
419 );
420
421 let debug_module = debuginfo::LLVMDIBuilderCreateModule(
422 dibuilder,
423 compile_unit,
424 module_name.as_ptr(),
425 module.name.len(),
426 c"".as_ptr(),
427 0,
428 c"".as_ptr(),
429 0,
430 c"".as_ptr(),
431 0,
432 );
433
434 for (fun_idx, func) in module.functions().iter() {
435 let name = CString::new(func.name.as_str()).unwrap();
436
437 let ret_ty = if let Some(ret_ty) = func.result_type {
438 lower_type(ctx, storage, ret_ty)
439 } else {
440 core::LLVMVoidTypeInContext(ctx)
441 };
442 let mut params = func
443 .parameters
444 .iter()
445 .map(|x| lower_type(ctx, storage, x.ty))
446 .collect_vec();
447 let fn_ty = core::LLVMFunctionType(ret_ty, params.as_mut_ptr(), params.len() as u32, 0);
448 let fn_ptr = core::LLVMAddFunction(llvm_module, name.as_ptr(), fn_ty);
449 functions.insert(fun_idx.to_idx(), (fn_ptr, fn_ty));
450
451 let mut file = compile_unit_file;
452
453 let mut line = 0;
454 match &func.location {
455 Location::Unknown => {}
456 Location::File(file_location) => {
457 file = get_difile(dibuilder, &file_location.file);
458 line = file_location.line;
459 }
460 }
461
462 let mut debug_param_types = Vec::new();
463
464 for param in func.parameters.iter() {
465 let ptr = lower_debug_type(
466 &module.data_layout,
467 dibuilder,
468 storage,
469 debug_module,
470 param.ty,
471 );
472 debug_param_types.push(ptr);
473 }
474
475 let debug_func_ty = debuginfo::LLVMDIBuilderCreateSubroutineType(
476 dibuilder,
477 file,
478 debug_param_types.as_mut_ptr(),
479 debug_param_types.len() as u32,
480 0,
481 );
482
483 let di_func = debuginfo::LLVMDIBuilderCreateFunction(
484 dibuilder,
485 debug_module,
486 name.as_ptr(),
487 name.count_bytes(),
488 name.as_ptr(),
489 name.count_bytes(),
490 file,
491 line,
492 debug_func_ty,
493 0,
494 1,
495 line,
496 0,
497 0,
498 );
499 dfunctions.insert(fun_idx.to_idx(), di_func);
500 debuginfo::LLVMSetSubprogram(fn_ptr, di_func);
501 }
502
503 let functions = Rc::new(functions);
504
505 for (fun_idx, func) in module.functions().iter() {
506 let fn_ptr = functions.get(&fun_idx.to_idx()).unwrap().0;
507 let dfunc = *dfunctions.get(&fun_idx.to_idx()).unwrap();
508
509 let mut fn_ctx = FnCtx {
510 ctx,
511 fn_ptr,
512 func: func.clone(),
513 builder,
514 dibuilder,
515 storage,
516 blocks: Default::default(),
517 values: Default::default(),
518 block_args: Default::default(),
519 functions: Rc::clone(&functions),
520 debug_scope: dfunc,
521 datalayout: &module.data_layout,
522 };
523
524 for (id, _) in func.blocks.iter() {
525 add_block(&mut fn_ctx, id, None);
526 }
527
528 for (id, _) in func.blocks.iter() {
529 lower_block(&mut fn_ctx, id)?;
530 }
531
532 debuginfo::LLVMDIBuilderFinalizeSubprogram(dibuilder, dfunc);
533 }
534
535 debuginfo::LLVMDIBuilderFinalize(dibuilder);
536 debuginfo::LLVMDisposeDIBuilder(dibuilder);
537 core::LLVMDisposeBuilder(builder);
538
539 core::LLVMDumpModule(llvm_module);
540
541 let mut out_msg: *mut i8 = null_mut();
542 let ok = llvm_sys::analysis::LLVMVerifyModule(
543 llvm_module,
544 llvm_sys::analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction,
545 &raw mut out_msg,
546 );
547
548 if ok != 0 {
549 let msg = {
550 let msg = CStr::from_ptr(out_msg);
551 msg.to_string_lossy().to_string()
552 };
553
554 if !out_msg.is_null() {
555 core::LLVMDisposeMessage(out_msg);
556 }
557
558 core::LLVMDisposeModule(llvm_module);
559 core::LLVMContextDispose(ctx);
560
561 return Err(Error::LLVMError(msg));
562 }
563
564 if !out_msg.is_null() {
565 core::LLVMDisposeMessage(out_msg);
566 }
567
568 Ok(CompileResult {
569 context: ctx,
570 module: llvm_module,
571 })
572 }
573}
574
575pub fn compile_object(
579 compile_result: &CompileResult,
580 target_triple: Triple,
581 options: CompileOptions,
582 output_file: &Path,
583 output_assembly: bool,
584) -> Result<(), Error> {
585 unsafe {
586 static INITIALIZED: OnceLock<()> = OnceLock::new();
587 INITIALIZED.get_or_init(|| {
588 LLVM_InitializeAllTargets();
589 LLVM_InitializeAllTargetInfos();
590 LLVM_InitializeAllTargetMCs();
591 LLVM_InitializeAllAsmPrinters();
592 });
593
594 let target_triple = CString::new(target_triple.to_string())?;
595
596 let target_cpu = match &options.target_cpu {
597 TargetCpu::Host => {
598 let cpu = LLVMGetHostCPUName();
599 CString::from(CStr::from_ptr(cpu))
600 }
601 TargetCpu::Name(name) => CString::new(name.as_bytes())?,
602 };
603
604 let target_cpu_features = match &options.target_cpu_features {
605 TargetCpuFeatures::Host => {
606 let cpu = LLVMGetHostCPUFeatures();
607 CString::from(CStr::from_ptr(cpu))
608 }
609 TargetCpuFeatures::Features(name) => CString::new(name.as_bytes())?,
610 };
611
612 let mut out_msg = null_mut();
613
614 let mut target = null_mut();
615
616 let ok = target_machine::LLVMGetTargetFromTriple(
617 target_triple.as_ptr(),
618 &raw mut target,
619 &raw mut out_msg,
620 );
621
622 if ok != 0 {
623 let msg = {
624 let msg = CStr::from_ptr(out_msg);
625 msg.to_string_lossy().to_string()
626 };
627
628 if !out_msg.is_null() {
629 core::LLVMDisposeMessage(out_msg);
630 }
631
632 return Err(Error::LLVMError(msg));
633 }
634
635 if !out_msg.is_null() {
636 core::LLVMDisposeMessage(out_msg);
637 }
638
639 let machine = target_machine::LLVMCreateTargetMachine(
640 target,
641 target_triple.as_ptr(),
642 target_cpu.as_ptr(),
643 target_cpu_features.as_ptr(),
644 match options.opt_level {
645 0 => LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
646 1 => LLVMCodeGenOptLevel::LLVMCodeGenLevelLess,
647 2 => LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
648 _ => LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
649 },
650 match options.relocation_model {
651 RelocModel::Default => LLVMRelocMode::LLVMRelocDefault,
652 RelocModel::Static => LLVMRelocMode::LLVMRelocStatic,
653 RelocModel::Pic => LLVMRelocMode::LLVMRelocPIC,
654 RelocModel::DynamicNoPic => LLVMRelocMode::LLVMRelocDynamicNoPic,
655 RelocModel::Ropi => LLVMRelocMode::LLVMRelocROPI,
656 RelocModel::Rwpi => LLVMRelocMode::LLVMRelocRWPI,
657 RelocModel::RopiRwpi => LLVMRelocMode::LLVMRelocROPI_RWPI,
658 },
659 match options.code_model {
660 CodeModel::Default => LLVMCodeModel::LLVMCodeModelDefault,
661 CodeModel::JitDefault => LLVMCodeModel::LLVMCodeModelJITDefault,
662 CodeModel::Tiny => LLVMCodeModel::LLVMCodeModelTiny,
663 CodeModel::Small => LLVMCodeModel::LLVMCodeModelSmall,
664 CodeModel::Kernel => LLVMCodeModel::LLVMCodeModelKernel,
665 CodeModel::Medium => LLVMCodeModel::LLVMCodeModelMedium,
666 CodeModel::Large => LLVMCodeModel::LLVMCodeModelLarge,
667 },
668 );
669
670 let opts = LLVMCreatePassBuilderOptions();
671
672 let passes = CString::new(format!("default<O{}>", options.opt_level)).unwrap();
673
674 let error = LLVMRunPasses(compile_result.module, passes.as_ptr(), machine, opts);
675
676 if !error.is_null() {
677 let msg_ptr = LLVMGetErrorMessage(error);
678 let msg = {
679 let msg = CStr::from_ptr(msg_ptr);
680 msg.to_string_lossy().to_string()
681 };
682 LLVMDisposeMessage(msg_ptr);
683 LLVMDisposeTargetMachine(machine);
684 return Err(Error::LLVMError(msg));
685 }
686
687 LLVMDisposePassBuilderOptions(opts);
688
689 let mut out_msg: *mut i8 = null_mut();
690 let ok = llvm_sys::analysis::LLVMVerifyModule(
691 compile_result.module,
692 llvm_sys::analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction,
693 &raw mut out_msg,
694 );
695
696 if ok != 0 {
697 let msg = {
698 let msg = CStr::from_ptr(out_msg);
699 msg.to_string_lossy().to_string()
700 };
701
702 if !out_msg.is_null() {
703 core::LLVMDisposeMessage(out_msg);
704 }
705
706 LLVMDisposeTargetMachine(machine);
707
708 return Err(Error::LLVMError(msg));
709 }
710
711 let filename = CString::new(output_file.as_os_str().to_string_lossy().as_bytes()).unwrap();
712
713 let ok = LLVMTargetMachineEmitToFile(
714 machine,
715 compile_result.module,
716 filename.as_ptr().cast_mut(),
717 if output_assembly {
718 LLVMCodeGenFileType::LLVMAssemblyFile
719 } else {
720 LLVMCodeGenFileType::LLVMObjectFile
721 },
722 &raw mut out_msg,
723 );
724
725 LLVMDisposeTargetMachine(machine);
726
727 if ok != 0 {
728 let msg = {
729 let msg = CStr::from_ptr(out_msg);
730 msg.to_string_lossy().to_string()
731 };
732
733 if !out_msg.is_null() {
734 core::LLVMDisposeMessage(out_msg);
735 }
736
737 return Err(Error::LLVMError(msg));
738 }
739
740 Ok(())
741 }
742}
743
744pub fn output_to_file(compile_result: &CompileResult, output_ll: &Path) -> Result<(), Error> {
746 unsafe {
747 let file = CString::new(&*output_ll.to_string_lossy())?;
748
749 let mut out_msg: *mut i8 = null_mut();
750
751 let ok =
752 core::LLVMPrintModuleToFile(compile_result.module, file.as_ptr(), &raw mut out_msg);
753
754 if ok != 0 {
755 let msg = {
756 let msg = CStr::from_ptr(out_msg);
757 msg.to_string_lossy().to_string()
758 };
759
760 if !out_msg.is_null() {
761 core::LLVMDisposeMessage(out_msg);
762 }
763
764 return Err(Error::LLVMError(msg));
765 }
766
767 if !out_msg.is_null() {
768 core::LLVMDisposeMessage(out_msg);
769 }
770
771 Ok(())
772 }
773}
774
775pub fn create_jit_engine(result: CompileResult, optlevel: u32) -> Result<JitEngine, Error> {
777 unsafe {
778 let mut engine = null_mut();
779
780 let mut out_msg: *mut i8 = null_mut();
781
782 let result = ManuallyDrop::new(result);
783
784 static INITIALIZED: OnceLock<()> = OnceLock::new();
785 INITIALIZED.get_or_init(|| {
786 LLVM_InitializeNativeTarget();
787 LLVM_InitializeNativeAsmParser();
788 LLVM_InitializeNativeAsmPrinter();
789 LLVM_InitializeNativeDisassembler();
790 LLVMLinkInMCJIT();
791 });
792
793 let ok = execution_engine::LLVMCreateJITCompilerForModule(
794 &raw mut engine,
795 result.module,
796 optlevel,
797 &raw mut out_msg,
798 );
799
800 if ok != 0 {
801 let msg = {
802 let msg = CStr::from_ptr(out_msg);
803 msg.to_string_lossy().to_string()
804 };
805
806 if !out_msg.is_null() {
807 core::LLVMDisposeMessage(out_msg);
808 }
809
810 return Err(Error::LLVMError(msg));
811 }
812
813 let engine = JitEngine {
814 context: result.context,
815 engine,
816 };
817
818 Ok(engine)
819 }
820}
821
822#[derive(Debug)]
823struct FnCtx<'m> {
824 ctx: LLVMContextRef,
825 fn_ptr: LLVMValueRef,
826 func: Function,
827 storage: &'m TypeStorage,
828 builder: LLVMBuilderRef,
829 dibuilder: LLVMDIBuilderRef,
830 debug_scope: LLVMMetadataRef,
831 functions: Rc<HashMap<usize, (LLVMValueRef, LLVMTypeRef)>>,
832 blocks: HashMap<usize, LLVMBasicBlockRef>,
833 values: HashMap<(usize, usize), LLVMValueRef>,
835 block_args: HashMap<usize, Vec<LLVMValueRef>>,
836 datalayout: &'m DataLayout,
837}
838
839fn lower_block(ctx: &mut FnCtx, block_idx: BlockIdx) -> Result<(), Error> {
841 unsafe {
842 let null_name = c"";
843 let block_ptr = *ctx.blocks.get(&block_idx.to_idx()).unwrap();
844 core::LLVMPositionBuilderAtEnd(ctx.builder, block_ptr);
845 add_preds(ctx, block_idx);
846
847 for (inst_idx, (loc, inst)) in ctx.func.blocks[block_idx].instructions().iter() {
848 let loc = set_loc(ctx.ctx, ctx.builder, loc, ctx.debug_scope);
849
850 match inst {
851 Instruction::BinaryOp(binary_op) => match binary_op {
852 irvm::block::BinaryOp::Add { lhs, rhs, nsw, nuw } => {
853 let lhs_ptr = lower_operand(ctx, lhs);
854 let rhs_ptr = lower_operand(ctx, rhs);
855 let value =
856 core::LLVMBuildAdd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
857 if *nuw {
858 core::LLVMSetNUW(value, (*nuw) as i32);
859 }
860 if *nsw {
861 core::LLVMSetNSW(value, (*nsw) as i32);
862 }
863 ctx.values
864 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
865 }
866 irvm::block::BinaryOp::Sub { lhs, rhs, nsw, nuw } => {
867 let lhs_ptr = lower_operand(ctx, lhs);
868 let rhs_ptr = lower_operand(ctx, rhs);
869 let value =
870 core::LLVMBuildSub(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
871 if *nuw {
872 core::LLVMSetNUW(value, (*nuw) as i32);
873 }
874 if *nsw {
875 core::LLVMSetNSW(value, (*nsw) as i32);
876 }
877 ctx.values
878 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
879 }
880 irvm::block::BinaryOp::Mul { lhs, rhs, nsw, nuw } => {
881 let lhs_ptr = lower_operand(ctx, lhs);
882 let rhs_ptr = lower_operand(ctx, rhs);
883 let value =
884 core::LLVMBuildMul(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
885 if *nuw {
886 core::LLVMSetNUW(value, (*nuw) as i32);
887 }
888 if *nsw {
889 core::LLVMSetNSW(value, (*nsw) as i32);
890 }
891 ctx.values
892 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
893 }
894 irvm::block::BinaryOp::Div {
895 lhs,
896 rhs,
897 signed,
898 exact,
899 } => {
900 let lhs_ptr = lower_operand(ctx, lhs);
901 let rhs_ptr = lower_operand(ctx, rhs);
902 let value = if *signed {
903 if *exact {
904 core::LLVMBuildExactSDiv(
905 ctx.builder,
906 lhs_ptr,
907 rhs_ptr,
908 null_name.as_ptr(),
909 )
910 } else {
911 core::LLVMBuildSDiv(
912 ctx.builder,
913 lhs_ptr,
914 rhs_ptr,
915 null_name.as_ptr(),
916 )
917 }
918 } else if *exact {
919 core::LLVMBuildExactUDiv(
920 ctx.builder,
921 lhs_ptr,
922 rhs_ptr,
923 null_name.as_ptr(),
924 )
925 } else {
926 core::LLVMBuildUDiv(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
927 };
928 ctx.values
929 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
930 }
931 irvm::block::BinaryOp::Rem { lhs, rhs, signed } => {
932 let lhs_ptr = lower_operand(ctx, lhs);
933 let rhs_ptr = lower_operand(ctx, rhs);
934 let value = if *signed {
935 core::LLVMBuildSRem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
936 } else {
937 core::LLVMBuildURem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
938 };
939 ctx.values
940 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
941 }
942 irvm::block::BinaryOp::FAdd { lhs, rhs } => {
943 let lhs_ptr = lower_operand(ctx, lhs);
944 let rhs_ptr = lower_operand(ctx, rhs);
945 let value =
946 core::LLVMBuildFAdd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
947 ctx.values
948 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
949 }
950 irvm::block::BinaryOp::FSub { lhs, rhs } => {
951 let lhs_ptr = lower_operand(ctx, lhs);
952 let rhs_ptr = lower_operand(ctx, rhs);
953 let value =
954 core::LLVMBuildFSub(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
955 ctx.values
956 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
957 }
958 irvm::block::BinaryOp::FMul { lhs, rhs } => {
959 let lhs_ptr = lower_operand(ctx, lhs);
960 let rhs_ptr = lower_operand(ctx, rhs);
961 let value =
962 core::LLVMBuildFMul(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
963 ctx.values
964 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
965 }
966 irvm::block::BinaryOp::FDiv { lhs, rhs } => {
967 let lhs_ptr = lower_operand(ctx, lhs);
968 let rhs_ptr = lower_operand(ctx, rhs);
969 let value =
970 core::LLVMBuildFDiv(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
971 ctx.values
972 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
973 }
974 irvm::block::BinaryOp::FRem { lhs, rhs } => {
975 let lhs_ptr = lower_operand(ctx, lhs);
976 let rhs_ptr = lower_operand(ctx, rhs);
977 let value =
978 core::LLVMBuildFRem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
979 ctx.values
980 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
981 }
982 },
983 Instruction::BitwiseBinaryOp(bitwise_binary_op) => match bitwise_binary_op {
984 irvm::block::BitwiseBinaryOp::Shl { lhs, rhs } => {
985 let lhs_ptr = lower_operand(ctx, lhs);
986 let rhs_ptr = lower_operand(ctx, rhs);
987 let value =
988 core::LLVMBuildShl(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
989 ctx.values
990 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
991 }
992 irvm::block::BitwiseBinaryOp::Lshr { lhs, rhs, exact } => {
993 let lhs_ptr = lower_operand(ctx, lhs);
994 let rhs_ptr = lower_operand(ctx, rhs);
995 let value =
996 core::LLVMBuildLShr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
997 core::LLVMSetExact(value, (*exact) as i32);
998 ctx.values
999 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1000 }
1001 irvm::block::BitwiseBinaryOp::Ashr { lhs, rhs, exact } => {
1002 let lhs_ptr = lower_operand(ctx, lhs);
1003 let rhs_ptr = lower_operand(ctx, rhs);
1004 let value =
1005 core::LLVMBuildAShr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1006 core::LLVMSetExact(value, (*exact) as i32);
1007 ctx.values
1008 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1009 }
1010 irvm::block::BitwiseBinaryOp::And { lhs, rhs } => {
1011 let lhs_ptr = lower_operand(ctx, lhs);
1012 let rhs_ptr = lower_operand(ctx, rhs);
1013 let value =
1014 core::LLVMBuildAnd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1015 ctx.values
1016 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1017 }
1018 irvm::block::BitwiseBinaryOp::Or { lhs, rhs, disjoint } => {
1019 let lhs_ptr = lower_operand(ctx, lhs);
1020 let rhs_ptr = lower_operand(ctx, rhs);
1021 let value =
1022 core::LLVMBuildOr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1023 core::LLVMSetIsDisjoint(value, (*disjoint) as i32);
1024 ctx.values
1025 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1026 }
1027 irvm::block::BitwiseBinaryOp::Xor { lhs, rhs } => {
1028 let lhs_ptr = lower_operand(ctx, lhs);
1029 let rhs_ptr = lower_operand(ctx, rhs);
1030 let value =
1031 core::LLVMBuildXor(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1032 ctx.values
1033 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1034 }
1035 },
1036 Instruction::VectorOp(vector_op) => match vector_op {
1037 irvm::block::VectorOp::ExtractElement { vector, idx } => {
1038 let vector = lower_operand(ctx, vector);
1039 let idx = lower_operand(ctx, idx);
1040 let value = core::LLVMBuildExtractElement(
1041 ctx.builder,
1042 vector,
1043 idx,
1044 null_name.as_ptr(),
1045 );
1046 ctx.values
1047 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1048 }
1049 },
1050 Instruction::MemoryOp(memory_op) => match memory_op {
1051 irvm::block::MemoryOp::Alloca {
1052 ty, num_elements, ..
1053 } => {
1054 let ty_ptr = lower_type(ctx.ctx, ctx.storage, *ty);
1055 let value = if *num_elements > 1 {
1056 let const_val = core::LLVMConstInt(
1057 core::LLVMInt64TypeInContext(ctx.ctx),
1058 (*num_elements) as u64,
1059 0,
1060 );
1061 core::LLVMBuildArrayAlloca(
1062 ctx.builder,
1063 ty_ptr,
1064 const_val,
1065 null_name.as_ptr(),
1066 )
1067 } else {
1068 core::LLVMBuildAlloca(ctx.builder, ty_ptr, null_name.as_ptr())
1069 };
1070 ctx.values
1071 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1072 }
1073 irvm::block::MemoryOp::Load { ptr, align } => {
1074 let ptr_val = lower_operand(ctx, ptr);
1075 let ty_ptr =
1076 lower_type(ctx.ctx, ctx.storage, ptr.get_inner_type(ctx.storage)?);
1077
1078 let value =
1079 core::LLVMBuildLoad2(ctx.builder, ty_ptr, ptr_val, null_name.as_ptr());
1080 if let Some(align) = align {
1081 core::LLVMSetAlignment(value, *align / 8);
1082 }
1083
1084 ctx.values
1085 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1086 }
1087 irvm::block::MemoryOp::Store { value, ptr, align } => {
1088 let ptr_val = lower_operand(ctx, ptr);
1089 let value_val = lower_operand(ctx, value);
1090
1091 let value = core::LLVMBuildStore(ctx.builder, value_val, ptr_val);
1092 if let Some(align) = align {
1093 core::LLVMSetAlignment(value, *align / 8);
1094 }
1095
1096 ctx.values
1097 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1098 }
1099 irvm::block::MemoryOp::GetElementPtr { ptr, indices } => {
1100 let ptr_val = lower_operand(ctx, ptr);
1101 let pointee_ty =
1102 lower_type(ctx.ctx, ctx.storage, ptr.get_inner_type(ctx.storage)?);
1103
1104 let mut x = Vec::new();
1105
1106 for index in indices {
1107 let value = match index {
1108 irvm::block::GepIndex::Const(value) => core::LLVMConstInt(
1109 core::LLVMInt64TypeInContext(ctx.ctx),
1110 (*value) as u64,
1111 0,
1112 ),
1113 irvm::block::GepIndex::Value(operand) => {
1114 lower_operand(ctx, operand)
1115 }
1116 };
1117
1118 x.push(value);
1119 }
1120
1121 let value = core::LLVMBuildGEP2(
1122 ctx.builder,
1123 pointee_ty,
1124 ptr_val,
1125 x.as_mut_ptr(),
1126 x.len() as u32,
1127 null_name.as_ptr(),
1128 );
1129
1130 ctx.values
1131 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1132 }
1133 },
1134 Instruction::OtherOp(other_op) => match other_op {
1135 irvm::block::OtherOp::Call(call_op) => {
1136 let (target_fn_ptr, fn_ty) = match &call_op.fn_target {
1137 irvm::block::CallableValue::Symbol(id) => {
1138 *ctx.functions.get(&id.to_idx()).expect("function not found")
1139 }
1140 irvm::block::CallableValue::Pointer(operand, fn_ty) => {
1141 let ptr = lower_operand(ctx, operand);
1142
1143 let ret_ty = lower_type(ctx.ctx, ctx.storage, fn_ty.return_type);
1144 let mut params = fn_ty
1145 .parameters
1146 .iter()
1147 .map(|x| lower_type(ctx.ctx, ctx.storage, *x))
1148 .collect_vec();
1149 let fn_ty = core::LLVMFunctionType(
1150 ret_ty,
1151 params.as_mut_ptr(),
1152 params.len() as u32,
1153 0,
1154 );
1155 (ptr, fn_ty)
1156 }
1157 };
1158
1159 let mut args = call_op
1160 .params
1161 .iter()
1162 .map(|p| lower_operand(ctx, p))
1163 .collect_vec();
1164
1165 let value = core::LLVMBuildCall2(
1166 ctx.builder,
1167 fn_ty,
1168 target_fn_ptr,
1169 args.as_mut_ptr(),
1170 args.len() as u32,
1171 null_name.as_ptr(),
1172 );
1173
1174 ctx.values
1175 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1176 }
1177 irvm::block::OtherOp::Icmp { cond, lhs, rhs } => {
1178 let lhs_val = lower_operand(ctx, lhs);
1179 let rhs_val = lower_operand(ctx, rhs);
1180 let value = core::LLVMBuildICmp(
1181 ctx.builder,
1182 match cond {
1183 irvm::block::IcmpCond::Eq => LLVMIntPredicate::LLVMIntEQ,
1184 irvm::block::IcmpCond::Ne => LLVMIntPredicate::LLVMIntNE,
1185 irvm::block::IcmpCond::Ugt => LLVMIntPredicate::LLVMIntUGT,
1186 irvm::block::IcmpCond::Uge => LLVMIntPredicate::LLVMIntUGE,
1187 irvm::block::IcmpCond::Ult => LLVMIntPredicate::LLVMIntULT,
1188 irvm::block::IcmpCond::Ule => LLVMIntPredicate::LLVMIntULE,
1189 irvm::block::IcmpCond::Sgt => LLVMIntPredicate::LLVMIntSGT,
1190 irvm::block::IcmpCond::Sge => LLVMIntPredicate::LLVMIntSGE,
1191 irvm::block::IcmpCond::Slt => LLVMIntPredicate::LLVMIntSLT,
1192 irvm::block::IcmpCond::Sle => LLVMIntPredicate::LLVMIntSLE,
1193 },
1194 lhs_val,
1195 rhs_val,
1196 null_name.as_ptr(),
1197 );
1198 ctx.values
1199 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1200 }
1201 irvm::block::OtherOp::Fcmp { cond, lhs, rhs } => {
1202 let lhs_val = lower_operand(ctx, lhs);
1203 let rhs_val = lower_operand(ctx, rhs);
1204 let value = core::LLVMBuildFCmp(
1205 ctx.builder,
1206 match cond {
1207 irvm::block::FcmpCond::False => {
1208 LLVMRealPredicate::LLVMRealPredicateFalse
1209 }
1210 irvm::block::FcmpCond::Oeq => LLVMRealPredicate::LLVMRealOEQ,
1211 irvm::block::FcmpCond::Ogt => LLVMRealPredicate::LLVMRealOGT,
1212 irvm::block::FcmpCond::Oge => LLVMRealPredicate::LLVMRealOGE,
1213 irvm::block::FcmpCond::Olt => LLVMRealPredicate::LLVMRealOLT,
1214 irvm::block::FcmpCond::Ole => LLVMRealPredicate::LLVMRealOLE,
1215 irvm::block::FcmpCond::One => LLVMRealPredicate::LLVMRealONE,
1216 irvm::block::FcmpCond::Ord => LLVMRealPredicate::LLVMRealORD,
1217 irvm::block::FcmpCond::Ueq => LLVMRealPredicate::LLVMRealUEQ,
1218 irvm::block::FcmpCond::Ugt => LLVMRealPredicate::LLVMRealUGT,
1219 irvm::block::FcmpCond::Ult => LLVMRealPredicate::LLVMRealULT,
1220 irvm::block::FcmpCond::Ule => LLVMRealPredicate::LLVMRealULE,
1221 irvm::block::FcmpCond::Une => LLVMRealPredicate::LLVMRealUNE,
1222 irvm::block::FcmpCond::Uno => LLVMRealPredicate::LLVMRealUNO,
1223 irvm::block::FcmpCond::True => {
1224 LLVMRealPredicate::LLVMRealPredicateTrue
1225 }
1226 },
1227 lhs_val,
1228 rhs_val,
1229 null_name.as_ptr(),
1230 );
1231 ctx.values
1232 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1233 }
1234 },
1235 Instruction::DebugOp(debug_op) => match debug_op {
1236 DebugOp::Declare { address, variable } => {
1237 let var = ctx.func.debug_vars.get(*variable).unwrap();
1238 let address_ptr = lower_operand(ctx, address);
1239 let var_ptr = lower_debug_var(
1240 ctx.dibuilder,
1241 ctx.debug_scope,
1242 ctx.datalayout,
1243 var,
1244 ctx.storage,
1245 )?;
1246
1247 let diexpr =
1248 debuginfo::LLVMDIBuilderCreateExpression(ctx.dibuilder, null_mut(), 0);
1249 debuginfo::LLVMDIBuilderInsertDeclareRecordAtEnd(
1250 ctx.dibuilder,
1251 address_ptr,
1252 var_ptr,
1253 diexpr,
1254 loc,
1255 block_ptr,
1256 );
1257 }
1258 DebugOp::Value {
1259 new_value,
1260 variable,
1261 } => {
1262 let var = ctx.func.debug_vars.get(*variable).unwrap();
1263 let value_ptr = lower_operand(ctx, new_value);
1264 let var_ptr = lower_debug_var(
1265 ctx.dibuilder,
1266 ctx.debug_scope,
1267 ctx.datalayout,
1268 var,
1269 ctx.storage,
1270 )?;
1271
1272 let diexpr =
1273 debuginfo::LLVMDIBuilderCreateExpression(ctx.dibuilder, null_mut(), 0);
1274 debuginfo::LLVMDIBuilderInsertDbgValueRecordAtEnd(
1275 ctx.dibuilder,
1276 value_ptr,
1277 var_ptr,
1278 diexpr,
1279 loc,
1280 block_ptr,
1281 );
1282 }
1283 DebugOp::Assign { .. } => {
1284 todo!()
1286 }
1287 },
1288 }
1289 }
1290
1291 match ctx.func.blocks[block_idx].terminator().clone() {
1292 irvm::block::Terminator::Ret(op) => {
1293 set_loc(ctx.ctx, ctx.builder, &op.0, ctx.debug_scope);
1294 if let Some(op) = op.1 {
1295 let value = lower_operand(ctx, &op);
1296 core::LLVMBuildRet(ctx.builder, value);
1297 } else {
1298 core::LLVMBuildRetVoid(ctx.builder);
1299 }
1300 }
1301 irvm::block::Terminator::Br {
1302 block: jmp_block,
1303 location,
1304 ..
1305 } => {
1306 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1307 let target_block = *ctx.blocks.get(&jmp_block.to_idx()).unwrap();
1308
1309 core::LLVMBuildBr(ctx.builder, target_block);
1310 }
1311 irvm::block::Terminator::CondBr {
1312 then_block: if_block,
1313 else_block: then_block,
1314 cond,
1315 ..
1316 } => {
1317 let cond = lower_operand(ctx, &cond);
1318
1319 let if_block_value = *ctx.blocks.get(&if_block.to_idx()).unwrap();
1320 let then_block_value = *ctx.blocks.get(&then_block.to_idx()).unwrap();
1321
1322 core::LLVMBuildCondBr(ctx.builder, cond, if_block_value, then_block_value);
1323 }
1324 }
1325
1326 Ok(())
1327 }
1328}
1329
1330fn add_block(ctx: &mut FnCtx, block_idx: BlockIdx, name: Option<String>) -> LLVMBasicBlockRef {
1331 unsafe {
1332 let block_name = CString::new(if block_idx.to_idx() == 0 {
1333 "entry".to_string()
1334 } else if let Some(name) = name {
1335 format!("bb{}", name)
1336 } else {
1337 format!("bb{}", block_idx.to_idx())
1338 })
1339 .unwrap();
1340 let block_ptr = core::LLVMAppendBasicBlock(ctx.fn_ptr, block_name.as_ptr());
1341 ctx.blocks.insert(block_idx.to_idx(), block_ptr);
1342 block_ptr
1343 }
1344}
1345
1346fn lower_debug_var(
1347 dibuilder: LLVMDIBuilderRef,
1348 scope: LLVMMetadataRef,
1349 datalayout: &DataLayout,
1350 variable: &DebugVariable,
1351 storage: &TypeStorage,
1352) -> Result<LLVMMetadataRef, Error> {
1353 let name = CString::new(variable.name.clone())?;
1354 let difile = get_difile_location(dibuilder, &variable.location);
1355
1356 let (line, _col) = match &variable.location {
1357 Location::Unknown => (0, 0),
1358 Location::File(file_location) => (file_location.line, file_location.col),
1359 };
1360
1361 let ty_ptr = lower_debug_type(datalayout, dibuilder, storage, scope, variable.ty);
1362 let align = datalayout.get_type_align(storage, variable.ty);
1363
1364 Ok(unsafe {
1365 if let Some(param) = variable.parameter {
1366 debuginfo::LLVMDIBuilderCreateParameterVariable(
1367 dibuilder,
1368 scope,
1369 name.as_ptr(),
1370 name.count_bytes(),
1371 param,
1372 difile,
1373 line,
1374 ty_ptr,
1375 1,
1376 0,
1377 )
1378 } else {
1379 debuginfo::LLVMDIBuilderCreateAutoVariable(
1380 dibuilder,
1381 scope,
1382 name.as_ptr(),
1383 name.count_bytes(),
1384 difile,
1385 line,
1386 ty_ptr,
1387 1,
1388 0,
1389 align,
1390 )
1391 }
1392 })
1393}
1394
1395fn get_difile_location(dibuilder: LLVMDIBuilderRef, location: &Location) -> LLVMMetadataRef {
1396 match location {
1397 Location::Unknown => unsafe {
1398 debuginfo::LLVMDIBuilderCreateFile(
1399 dibuilder,
1400 c"/dev/stdin".as_ptr(),
1401 c"/dev/stdin".count_bytes(),
1402 c"".as_ptr(),
1403 0,
1404 )
1405 },
1406 Location::File(file_location) => get_difile(dibuilder, &file_location.file),
1407 }
1408}
1409
1410fn get_difile(dibuilder: LLVMDIBuilderRef, file: &Path) -> LLVMMetadataRef {
1411 let parent = if let Some(parent) = file.parent() {
1412 CString::new(parent.display().to_string()).unwrap()
1413 } else {
1414 CString::new("").unwrap()
1415 };
1416
1417 let filename = CString::new(file.display().to_string()).unwrap();
1418
1419 unsafe {
1420 debuginfo::LLVMDIBuilderCreateFile(
1421 dibuilder,
1422 filename.as_ptr(),
1423 filename.count_bytes(),
1424 parent.as_ptr(),
1425 parent.count_bytes(),
1426 )
1427 }
1428}
1429
1430fn set_loc(
1431 ctx: LLVMContextRef,
1432 builder: LLVMBuilderRef,
1433 location: &Location,
1434 scope: LLVMMetadataRef,
1435) -> *mut LLVMOpaqueMetadata {
1436 match location {
1437 Location::Unknown => unsafe {
1438 let loc = debuginfo::LLVMDIBuilderCreateDebugLocation(ctx, 0, 0, scope, null_mut());
1439 core::LLVMSetCurrentDebugLocation2(builder, loc);
1440 loc
1441 },
1442 Location::File(file_location) => unsafe {
1443 let loc = debuginfo::LLVMDIBuilderCreateDebugLocation(
1444 ctx,
1445 file_location.line,
1446 file_location.col,
1447 scope,
1448 null_mut(),
1449 );
1450 core::LLVMSetCurrentDebugLocation2(builder, loc);
1451 loc
1452 },
1453 }
1454}
1455
1456fn add_preds(ctx: &mut FnCtx, block_idx: BlockIdx) {
1457 unsafe {
1458 let block_ptr = *ctx.blocks.get(&block_idx.to_idx()).unwrap();
1459 core::LLVMPositionBuilderAtEnd(ctx.builder, block_ptr);
1460
1461 let preds = ctx.func.find_preds_for(block_idx);
1462 let mut block_args = Vec::new();
1463
1464 if !preds.is_empty() {
1465 let operand_len = preds.first().unwrap().1.len();
1466
1467 for i in 0..(operand_len) {
1468 let phy_ty =
1469 lower_type(ctx.ctx, ctx.storage, preds.first().unwrap().1[i].get_type());
1470 let phi_node = core::LLVMBuildPhi(ctx.builder, phy_ty, c"".as_ptr());
1471 let mut blocks = Vec::new();
1472 let mut values = Vec::new();
1473 for (pred_block_idx, operands) in &preds {
1474 let pred_ptr = ctx.blocks.get(&pred_block_idx.to_idx()).unwrap();
1475 let value = lower_operand(ctx, &operands[i]);
1476
1477 blocks.push(*pred_ptr);
1478 values.push(value);
1479 }
1480
1481 assert_eq!(values.len(), values.len());
1482
1483 core::LLVMAddIncoming(
1484 phi_node,
1485 values.as_mut_ptr().cast(),
1486 blocks.as_mut_ptr().cast(),
1487 blocks.len() as u32,
1488 );
1489 block_args.push(phi_node);
1490 }
1491 }
1492
1493 ctx.block_args.insert(block_idx.to_idx(), block_args);
1494 }
1495}
1496
1497fn lower_operand(ctx: &FnCtx, operand: &Operand) -> LLVMValueRef {
1498 unsafe {
1499 match operand {
1500 Operand::Parameter(idx, _ty) => core::LLVMGetParam(ctx.fn_ptr, (*idx) as u32),
1501 Operand::Value(block_idx, index, _) => *ctx
1502 .values
1503 .get(&(block_idx.to_idx(), index.to_idx()))
1504 .unwrap(),
1505 Operand::Constant(const_value, ty) => lower_constant(ctx, const_value, *ty),
1506 Operand::BlockArgument { block_idx, nth, .. } => {
1507 ctx.block_args.get(block_idx).unwrap()[*nth]
1508 }
1509 }
1510 }
1511}
1512
1513fn lower_constant(ctx: &FnCtx, value: &ConstValue, ty: TypeIdx) -> LLVMValueRef {
1514 unsafe {
1515 let ty_ptr = lower_type(ctx.ctx, ctx.storage, ty);
1516
1517 match value {
1518 irvm::value::ConstValue::Int(value) => core::LLVMConstInt(ty_ptr, *value, 0_i32),
1519 irvm::value::ConstValue::Float(value) => core::LLVMConstReal(ty_ptr, *value),
1520 irvm::value::ConstValue::Array(const_values) => {
1521 let mut values = Vec::new();
1522 let array_ty = if let Type::Array(array_ty) = &ctx.storage.get_type_info(ty).ty {
1523 array_ty
1524 } else {
1525 panic!("type mismatch")
1526 };
1527
1528 let typtr = lower_type(ctx.ctx, ctx.storage, array_ty.ty);
1529
1530 for value in const_values {
1531 let ptr = lower_constant(ctx, value, array_ty.ty);
1532 values.push(ptr);
1533 }
1534
1535 core::LLVMConstArray2(typtr, values.as_mut_ptr(), values.len() as u64)
1536 }
1537 irvm::value::ConstValue::Vector(const_values) => {
1538 let mut values = Vec::new();
1539 let vec_ty = if let Type::Vector(vec_ty) = &ctx.storage.get_type_info(ty).ty {
1540 vec_ty
1541 } else {
1542 panic!("type mismatch")
1543 };
1544
1545 for value in const_values {
1546 let ptr = lower_constant(ctx, value, vec_ty.ty);
1547 values.push(ptr);
1548 }
1549
1550 core::LLVMConstVector(values.as_mut_ptr(), values.len() as u32)
1551 }
1552 irvm::value::ConstValue::Struct(const_values) => {
1553 let mut const_fields = Vec::new();
1554 let struct_ty = if let Type::Struct(struct_ty) = &ctx.storage.get_type_info(ty).ty {
1555 &**struct_ty
1556 } else {
1557 panic!("type mismatch")
1558 };
1559 for (value, field) in const_values.iter().zip(struct_ty.fields.iter()) {
1560 let ptr = lower_constant(ctx, value, *field);
1561 const_fields.push(ptr);
1562 }
1563 core::LLVMConstStructInContext(
1564 ctx.ctx,
1565 const_fields.as_mut_ptr(),
1566 const_fields.len() as u32,
1567 struct_ty.packed as i32,
1568 )
1569 }
1570 irvm::value::ConstValue::NullPtr => core::LLVMConstPointerNull(ty_ptr),
1571 irvm::value::ConstValue::Undef => core::LLVMGetUndef(ty_ptr),
1572 irvm::value::ConstValue::Poison => core::LLVMGetPoison(ty_ptr),
1573 }
1574 }
1575}
1576
1577fn lower_type(ctx: LLVMContextRef, storage: &TypeStorage, ty: TypeIdx) -> LLVMTypeRef {
1578 let tyinfo = storage.get_type_info(ty);
1579 unsafe {
1580 match &tyinfo.ty {
1581 Type::Int(width) => core::LLVMIntTypeInContext(ctx, *width),
1582 Type::Half => core::LLVMHalfTypeInContext(ctx),
1583 Type::BFloat => core::LLVMBFloatTypeInContext(ctx),
1584 Type::Float => core::LLVMFloatTypeInContext(ctx),
1585 Type::Double => core::LLVMDoubleTypeInContext(ctx),
1586 Type::Fp128 => core::LLVMFP128TypeInContext(ctx),
1587 Type::X86Fp80 => core::LLVMX86FP80TypeInContext(ctx),
1588 Type::PpcFp128 => core::LLVMPPCFP128TypeInContext(ctx),
1589 Type::Ptr {
1590 pointee: _,
1591 address_space,
1592 } => core::LLVMPointerTypeInContext(ctx, address_space.unwrap_or(0)),
1593 Type::Vector(vector_type) => {
1594 let inner = lower_type(ctx, storage, vector_type.ty);
1595 core::LLVMVectorType(inner, vector_type.size)
1596 }
1597 Type::Array(array_type) => {
1598 let inner = lower_type(ctx, storage, array_type.ty);
1599 core::LLVMArrayType2(inner, array_type.size)
1600 }
1601 Type::Struct(struct_type) => {
1602 let mut fields = Vec::new();
1603
1604 for field in struct_type.fields.iter() {
1605 fields.push(lower_type(ctx, storage, *field));
1606 }
1607
1608 if let Some(ident) = &struct_type.ident {
1609 let name = CString::new(ident.as_str()).unwrap();
1610 let ptr = core::LLVMStructCreateNamed(ctx, name.as_ptr());
1611
1612 core::LLVMStructSetBody(
1613 ptr,
1614 fields.as_mut_ptr(),
1615 fields.len() as u32,
1616 struct_type.packed as i32,
1617 );
1618
1619 ptr
1620 } else {
1621 core::LLVMStructTypeInContext(
1622 ctx,
1623 fields.as_mut_ptr(),
1624 fields.len() as u32,
1625 struct_type.packed as i32,
1626 )
1627 }
1628 }
1629 }
1630 }
1631}
1632
1633fn lower_debug_type(
1634 datalayout: &DataLayout,
1635 builder: LLVMDIBuilderRef,
1636 storage: &TypeStorage,
1637 module_scope: LLVMMetadataRef,
1638 type_idx: TypeIdx,
1639) -> LLVMMetadataRef {
1640 let ty = storage.get_type_info(type_idx);
1641
1642 let size_in_bits = datalayout.get_type_size(storage, type_idx);
1650 let align_in_bits = datalayout.get_type_align(storage, type_idx);
1651
1652 if let Some(debug_info) = &ty.debug_info {
1653 let name = CString::new(debug_info.name.clone()).unwrap();
1654 unsafe {
1655 match &ty.ty {
1656 Type::Int(width) => {
1657 let mut encoding = DW_ATE_unsigned;
1658 if *width == 1 {
1659 encoding = DW_ATE_boolean;
1660 }
1661 debuginfo::LLVMDIBuilderCreateBasicType(
1662 builder,
1663 name.as_ptr(),
1664 name.count_bytes(),
1665 size_in_bits as u64,
1666 encoding.0 as u32,
1667 LLVMDIFlagPublic,
1668 )
1669 }
1670 Type::Half
1671 | Type::BFloat
1672 | Type::Float
1673 | Type::Double
1674 | Type::Fp128
1675 | Type::X86Fp80
1676 | Type::PpcFp128 => debuginfo::LLVMDIBuilderCreateBasicType(
1677 builder,
1678 name.as_ptr(),
1679 name.count_bytes(),
1680 size_in_bits as u64,
1681 0x4,
1682 LLVMDIFlagPublic,
1683 ),
1684 Type::Ptr {
1685 pointee,
1686 address_space,
1687 } => {
1688 let pointee_ptr =
1689 lower_debug_type(datalayout, builder, storage, module_scope, *pointee);
1690
1691 if debug_info.is_reference {
1692 debuginfo::LLVMDIBuilderCreateReferenceType(
1693 builder,
1694 DW_TAG_reference_type.0 as u32,
1695 pointee_ptr,
1696 )
1697 } else {
1698 debuginfo::LLVMDIBuilderCreatePointerType(
1699 builder,
1700 pointee_ptr,
1701 size_in_bits as u64,
1702 align_in_bits,
1703 address_space.unwrap_or(0),
1704 name.as_ptr(),
1705 name.count_bytes(),
1706 )
1707 }
1708 }
1709 Type::Vector(vector_type) => {
1710 let inner_ty_ptr = lower_debug_type(
1711 datalayout,
1712 builder,
1713 storage,
1714 module_scope,
1715 vector_type.ty,
1716 );
1717 let size = datalayout.get_type_size(storage, type_idx);
1718 let align = datalayout.get_type_align(storage, type_idx);
1719 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
1720 builder,
1721 0,
1722 vector_type.size as i64,
1723 );
1724 debuginfo::LLVMDIBuilderCreateVectorType(
1725 builder,
1726 size as u64,
1727 align,
1728 inner_ty_ptr,
1729 &raw mut subrange,
1730 1,
1731 )
1732 }
1733 Type::Array(array_type) => {
1734 let inner_ty_ptr =
1735 lower_debug_type(datalayout, builder, storage, module_scope, array_type.ty);
1736 let size = datalayout.get_type_size(storage, type_idx);
1737 let align = datalayout.get_type_align(storage, type_idx);
1738 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
1739 builder,
1740 0,
1741 array_type.size as i64,
1742 );
1743 debuginfo::LLVMDIBuilderCreateArrayType(
1744 builder,
1745 size as u64,
1746 align,
1747 inner_ty_ptr,
1748 &raw mut subrange,
1749 1,
1750 )
1751 }
1752 Type::Struct(struct_type) => {
1753 let mut fields = Vec::with_capacity(struct_type.fields.len());
1754
1755 let difile = get_difile_location(builder, &debug_info.location);
1756 let line = debug_info.location.get_line();
1757
1758 let mut offset = 0;
1759 let mut cur_align = 8;
1760
1761 for (i, field) in struct_type.fields.iter().enumerate() {
1762 let field_align = datalayout.get_type_align(storage, *field);
1763 cur_align = cur_align.max(field_align);
1764
1765 if offset % field_align != 0 {
1766 let padding = (field_align - (offset % field_align)) % field_align;
1767 offset += padding;
1768 }
1769
1770 let field_size = datalayout.get_type_size(storage, *field);
1771
1772 let mut ty =
1773 lower_debug_type(datalayout, builder, storage, module_scope, *field);
1774
1775 if let Some((field_name, location)) = struct_type.debug_field_names.get(i) {
1776 let name = CString::new(field_name.clone()).unwrap();
1777 let difile = get_difile_location(builder, location);
1778 let line = location.get_line().unwrap_or(0);
1779 let size = datalayout.get_type_size(storage, *field);
1780 let align = datalayout.get_type_align(storage, *field);
1781 ty = debuginfo::LLVMDIBuilderCreateMemberType(
1782 builder,
1783 module_scope,
1784 name.as_ptr(),
1785 name.count_bytes(),
1786 difile,
1787 line,
1788 size as u64,
1789 align,
1790 offset as u64,
1791 0,
1792 ty,
1793 );
1794 }
1795
1796 offset += field_size;
1797
1798 fields.push(ty);
1799 }
1800
1801 let size = datalayout.get_type_size(storage, type_idx);
1802 let align = datalayout.get_type_align(storage, type_idx);
1803
1804 debuginfo::LLVMDIBuilderCreateStructType(
1805 builder,
1806 module_scope,
1807 name.as_ptr(),
1808 name.count_bytes(),
1809 difile,
1810 line.unwrap_or(0),
1811 size as u64,
1812 align,
1813 0,
1814 null_mut(),
1815 fields.as_mut_ptr(),
1816 fields.len() as u32,
1817 0,
1818 null_mut(),
1819 name.as_ptr(),
1820 name.count_bytes(),
1821 )
1822 }
1823 }
1824 }
1825 } else {
1826 todo!()
1827 }
1828}