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_float, DW_ATE_unsigned, DW_TAG_reference_type};
37use irvm::{
38 block::{
39 AtomicOrdering, AtomicRMWOp, BlockIdx, DebugOp, DebugVariable, FastMathFlags, Instruction,
40 SyncScope,
41 },
42 common::{Linkage, Location},
43 datalayout::DataLayout,
44 function::Function,
45 module::Module,
46 target_lexicon::Triple,
47 types::{Type, TypeIdx, TypeStorage},
48 value::{ConstValue, Operand},
49};
50
51use itertools::Itertools;
52use llvm_sys::{
53 LLVMIntPredicate, LLVMModule, LLVMOpaqueMetadata, LLVMRealPredicate,
54 core::{self, LLVMDisposeMessage, LLVMDumpModule},
55 debuginfo::{self, LLVMDIFlagPublic, LLVMDWARFEmissionKind},
56 error::LLVMGetErrorMessage,
57 execution_engine::{self, LLVMExecutionEngineRef, LLVMLinkInMCJIT},
58 prelude::{
59 LLVMBasicBlockRef, LLVMBuilderRef, LLVMContextRef, LLVMDIBuilderRef, LLVMMetadataRef,
60 LLVMTypeRef, LLVMValueRef,
61 },
62 target::{
63 LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, LLVM_InitializeAllTargetMCs,
64 LLVM_InitializeAllTargets, LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter,
65 LLVM_InitializeNativeDisassembler, LLVM_InitializeNativeTarget,
66 },
67 target_machine::{
68 self, LLVMCodeGenFileType, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMDisposeTargetMachine,
69 LLVMGetHostCPUFeatures, LLVMGetHostCPUName, LLVMRelocMode, LLVMTargetMachineEmitToFile,
70 },
71 transforms::pass_builder::{
72 LLVMCreatePassBuilderOptions, LLVMDisposePassBuilderOptions, LLVMRunPasses,
73 },
74};
75
76#[derive(Debug)]
77pub enum OutputCompilation {
78 File(PathBuf),
79 Engine(*mut LLVMExecutionEngineRef),
80}
81
82#[derive(Debug, thiserror::Error, Clone)]
84pub enum Error {
85 #[error("llvm error: {:?}", 0)]
86 LLVMError(String),
87 #[error("jit error: {:?}", 0)]
88 JitError(String),
89 #[error(transparent)]
90 NulError(#[from] std::ffi::NulError),
91 #[error("irvm error: {:?}", 0)]
92 IRVMError(#[from] irvm::error::Error),
93}
94
95#[derive(Debug, Clone, Default)]
97pub enum TargetCpu {
98 #[default]
99 Host,
100 Name(String),
101}
102
103#[derive(Debug, Clone, Default)]
105pub enum TargetCpuFeatures {
106 #[default]
107 Host,
108 Features(String),
109}
110
111#[derive(Debug, Clone, Default)]
113pub enum OptLevel {
114 None,
115 Less,
116 #[default]
117 Default,
118 Aggressive,
119}
120
121#[derive(Debug, Clone, Default)]
123pub enum RelocModel {
124 #[default]
126 Default,
127 Static,
129 Pic,
131 DynamicNoPic,
133 Ropi,
138 Rwpi,
146 RopiRwpi,
150}
151
152#[derive(Debug, Clone, Default)]
154pub enum CodeModel {
155 #[default]
156 Default,
157 JitDefault,
158 Tiny,
159 Small,
160 Kernel,
161 Medium,
162 Large,
163}
164
165#[derive(Debug, Clone, Default)]
167pub struct CompileOptions {
168 pub target_cpu: TargetCpu,
169 pub target_cpu_features: TargetCpuFeatures,
170 pub relocation_model: RelocModel,
171 pub code_model: CodeModel,
172 pub opt_level: u8,
173}
174
175#[derive(Debug)]
177pub struct CompileResult {
178 context: LLVMContextRef,
179 module: *mut LLVMModule,
180}
181
182#[derive(Debug)]
184pub struct JitEngine {
185 context: LLVMContextRef,
186 engine: LLVMExecutionEngineRef,
187}
188
189impl Drop for CompileResult {
190 fn drop(&mut self) {
191 unsafe {
192 core::LLVMDisposeModule(self.module);
193 core::LLVMContextDispose(self.context);
194 }
195 }
196}
197
198impl Drop for JitEngine {
199 fn drop(&mut self) {
200 unsafe {
201 execution_engine::LLVMDisposeExecutionEngine(self.engine);
202 core::LLVMContextDispose(self.context);
203 }
204 }
205}
206
207#[derive(Debug, Clone, Copy, PartialEq)]
209pub enum JitValue {
210 U8(u8),
211 U16(u16),
212 U32(u32),
213 U64(u64),
214 I8(i8),
215 I16(i16),
216 I32(i32),
217 I64(i64),
218 F32(f32),
219 F64(f64),
220 Ptr(*mut c_void),
221 Void,
222}
223
224impl JitEngine {
225 pub unsafe fn execute(
231 &self,
232 symbol: &str,
233 args: &[JitValue],
234 return_ty: JitValue,
235 ) -> Result<JitValue, Error> {
236 unsafe {
237 let sym = CString::new(symbol)?;
238 let mut out_fn = null_mut();
239 let ok = execution_engine::LLVMFindFunction(self.engine, sym.as_ptr(), &raw mut out_fn);
240
241 if ok != 0 {
242 return Err(Error::LLVMError("Function not found".to_string()));
243 }
244
245 let mut value_args = Vec::new();
246
247 for arg in args {
248 let value = match arg {
249 JitValue::U8(value) => execution_engine::LLVMCreateGenericValueOfInt(
250 core::LLVMInt8Type(),
251 (*value) as _,
252 0,
253 ),
254 JitValue::U16(value) => execution_engine::LLVMCreateGenericValueOfInt(
255 core::LLVMInt16Type(),
256 (*value) as _,
257 0,
258 ),
259 JitValue::U32(value) => execution_engine::LLVMCreateGenericValueOfInt(
260 core::LLVMInt32Type(),
261 (*value) as _,
262 0,
263 ),
264 JitValue::U64(value) => execution_engine::LLVMCreateGenericValueOfInt(
265 core::LLVMInt64Type(),
266 (*value) as _,
267 0,
268 ),
269 JitValue::I8(value) => execution_engine::LLVMCreateGenericValueOfInt(
270 core::LLVMInt8Type(),
271 (*value) as _,
272 1,
273 ),
274 JitValue::I16(value) => execution_engine::LLVMCreateGenericValueOfInt(
275 core::LLVMInt16Type(),
276 (*value) as _,
277 1,
278 ),
279 JitValue::I32(value) => execution_engine::LLVMCreateGenericValueOfInt(
280 core::LLVMInt32Type(),
281 (*value) as _,
282 1,
283 ),
284 JitValue::I64(value) => execution_engine::LLVMCreateGenericValueOfInt(
285 core::LLVMInt64Type(),
286 (*value) as _,
287 1,
288 ),
289 JitValue::F32(value) => execution_engine::LLVMCreateGenericValueOfFloat(
290 core::LLVMFloatType(),
291 (*value) as _,
292 ),
293 JitValue::F64(value) => execution_engine::LLVMCreateGenericValueOfFloat(
294 core::LLVMDoubleType(),
295 (*value) as _,
296 ),
297 JitValue::Ptr(value) => {
298 execution_engine::LLVMCreateGenericValueOfPointer(*value)
299 }
300 JitValue::Void => {
301 return Err(Error::JitError(
302 "can't use void jit value as argument".to_string(),
303 ));
304 }
305 };
306 value_args.push(value);
307 }
308
309 let result = execution_engine::LLVMRunFunction(
310 self.engine,
311 out_fn,
312 value_args.len() as _,
313 value_args.as_mut_ptr(),
314 );
315
316 let res = match return_ty {
317 JitValue::U8(_) => {
318 JitValue::U8(execution_engine::LLVMGenericValueToInt(result, 0) as u8)
319 }
320 JitValue::U16(_) => {
321 JitValue::U16(execution_engine::LLVMGenericValueToInt(result, 0) as u16)
322 }
323 JitValue::U32(_) => {
324 JitValue::U32(execution_engine::LLVMGenericValueToInt(result, 0) as u32)
325 }
326 JitValue::U64(_) => {
327 JitValue::U64(execution_engine::LLVMGenericValueToInt(result, 0) as u64)
328 }
329 JitValue::I8(_) => {
330 JitValue::I8(execution_engine::LLVMGenericValueToInt(result, 1) as i8)
331 }
332 JitValue::I16(_) => {
333 JitValue::I16(execution_engine::LLVMGenericValueToInt(result, 1) as i16)
334 }
335 JitValue::I32(_) => {
336 JitValue::I32(execution_engine::LLVMGenericValueToInt(result, 1) as i32)
337 }
338 JitValue::I64(_) => {
339 JitValue::I64(execution_engine::LLVMGenericValueToInt(result, 1) as i64)
340 }
341 JitValue::F32(_) => JitValue::F32(execution_engine::LLVMGenericValueToFloat(
342 core::LLVMFloatType(),
343 result,
344 ) as f32),
345 JitValue::F64(_) => JitValue::F64(execution_engine::LLVMGenericValueToFloat(
346 core::LLVMDoubleType(),
347 result,
348 ) as f64),
349 JitValue::Ptr(_) => {
350 JitValue::Ptr(execution_engine::LLVMGenericValueToPointer(result))
351 }
352 JitValue::Void => JitValue::Void,
353 };
354
355 for arg in &value_args {
356 execution_engine::LLVMDisposeGenericValue(*arg);
357 }
358 execution_engine::LLVMDisposeGenericValue(result);
359
360 Ok(res)
361 }
362 }
363}
364
365impl CompileResult {
366 pub fn dump(&self) {
367 unsafe {
368 LLVMDumpModule(self.module);
369 }
370 }
371}
372
373pub fn lower_module_to_llvmir(
375 module: &Module,
376 storage: &TypeStorage,
377) -> Result<CompileResult, Error> {
378 unsafe {
379 let ctx = core::LLVMContextCreate();
380 let module_name = CString::new(module.name.clone())?;
381 let llvm_module = core::LLVMModuleCreateWithNameInContext(module_name.as_ptr(), ctx);
382
383 let datalayout_str = CString::new(module.data_layout.to_llvm_string()).unwrap();
384 core::LLVMSetDataLayout(llvm_module, datalayout_str.as_ptr());
385 let triple_str = CString::new(module.target_triple.to_string()).unwrap();
386 core::LLVMSetTarget(llvm_module, triple_str.as_ptr());
387
388 let mut functions: HashMap<_, _> = Default::default();
389 let mut dfunctions: HashMap<_, _> = Default::default();
390 let builder = core::LLVMCreateBuilderInContext(ctx);
392 let dibuilder = debuginfo::LLVMCreateDIBuilder(llvm_module);
393
394 let compile_unit_file = get_difile_location(dibuilder, &module.location);
395
396 let producer = c"IRVM version 0.1.0";
397 let flags = c"";
398 let splitname = c"";
399 let sysroot = c"";
400 let sdk = c"";
401
402 let compile_unit = debuginfo::LLVMDIBuilderCreateCompileUnit(
403 dibuilder,
404 debuginfo::LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageC17,
405 compile_unit_file,
406 producer.as_ptr(),
407 producer.count_bytes(),
408 0,
409 flags.as_ptr(),
410 flags.count_bytes(),
411 0,
412 splitname.as_ptr(),
413 splitname.count_bytes(),
414 LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull,
415 0,
416 0,
417 0,
418 sysroot.as_ptr(),
419 sysroot.count_bytes(),
420 sdk.as_ptr(),
421 sdk.count_bytes(),
422 );
423
424 let debug_module = debuginfo::LLVMDIBuilderCreateModule(
425 dibuilder,
426 compile_unit,
427 module_name.as_ptr(),
428 module.name.len(),
429 c"".as_ptr(),
430 0,
431 c"".as_ptr(),
432 0,
433 c"".as_ptr(),
434 0,
435 );
436
437 let mut globals: HashMap<usize, LLVMValueRef> = Default::default();
439 for (global_idx, global) in module.globals().iter() {
440 let name = CString::new(global.name.as_str()).unwrap();
441 let ty = lower_type(ctx, storage, global.ty);
442
443 let global_var = core::LLVMAddGlobal(llvm_module, ty, name.as_ptr());
444
445 if let Some(init) = &global.initializer {
447 let init_val = lower_global_constant(ctx, storage, init, global.ty);
448 core::LLVMSetInitializer(global_var, init_val);
449 }
450
451 core::LLVMSetGlobalConstant(global_var, global.is_constant as i32);
453
454 if let Some(linkage) = &global.linkage {
456 core::LLVMSetLinkage(global_var, lower_linkage(linkage));
457 }
458
459 if let Some(align) = global.align {
461 core::LLVMSetAlignment(global_var, align);
462 }
463
464 globals.insert(global_idx.to_idx(), global_var);
465 }
466 let globals = Rc::new(globals);
467
468 for (fun_idx, func) in module.functions().iter() {
469 let name = CString::new(func.name.as_str()).unwrap();
470
471 let ret_ty = if let Some(ret_ty) = func.result_type {
472 lower_type(ctx, storage, ret_ty)
473 } else {
474 core::LLVMVoidTypeInContext(ctx)
475 };
476 let mut params = func
477 .parameters
478 .iter()
479 .map(|x| lower_type(ctx, storage, x.ty))
480 .collect_vec();
481 let fn_ty = core::LLVMFunctionType(ret_ty, params.as_mut_ptr(), params.len() as u32, 0);
482 let fn_ptr = core::LLVMAddFunction(llvm_module, name.as_ptr(), fn_ty);
483 apply_function_attrs(ctx, fn_ptr, &func.attrs);
484 apply_parameter_attrs(ctx, fn_ptr, &func.parameters);
485 apply_return_attrs(ctx, fn_ptr, &func.return_attrs);
486
487 if let Some(gc_name) = &func.gc_name {
489 let gc_cstring = CString::new(gc_name.as_str()).unwrap();
490 core::LLVMSetGC(fn_ptr, gc_cstring.as_ptr());
491 }
492
493 if let Some((value, ty)) = &func.prefix_data {
495 let llvm_val = lower_global_constant(ctx, storage, value, *ty);
496 core::LLVMSetPrefixData(fn_ptr, llvm_val);
497 }
498
499 if let Some((value, ty)) = &func.prologue_data {
501 let llvm_val = lower_global_constant(ctx, storage, value, *ty);
502 core::LLVMSetPrologueData(fn_ptr, llvm_val);
503 }
504
505 functions.insert(fun_idx.to_idx(), (fn_ptr, fn_ty));
506
507 let mut file = compile_unit_file;
508
509 let mut line = 0;
510 match &func.location {
511 Location::Unknown => {}
512 Location::File(file_location) => {
513 file = get_difile(dibuilder, &file_location.file);
514 line = file_location.line;
515 }
516 }
517
518 let mut debug_param_types = Vec::new();
519
520 for param in func.parameters.iter() {
521 let ptr = lower_debug_type(
522 &module.data_layout,
523 dibuilder,
524 storage,
525 debug_module,
526 param.ty,
527 );
528 debug_param_types.push(ptr);
529 }
530
531 let debug_func_ty = debuginfo::LLVMDIBuilderCreateSubroutineType(
532 dibuilder,
533 file,
534 debug_param_types.as_mut_ptr(),
535 debug_param_types.len() as u32,
536 0,
537 );
538
539 let di_func = debuginfo::LLVMDIBuilderCreateFunction(
540 dibuilder,
541 debug_module,
542 name.as_ptr(),
543 name.count_bytes(),
544 name.as_ptr(),
545 name.count_bytes(),
546 file,
547 line,
548 debug_func_ty,
549 0,
550 1,
551 line,
552 0,
553 0,
554 );
555 dfunctions.insert(fun_idx.to_idx(), di_func);
556 debuginfo::LLVMSetSubprogram(fn_ptr, di_func);
557 }
558
559 let functions = Rc::new(functions);
560
561 for (fun_idx, func) in module.functions().iter() {
562 let fn_ptr = functions.get(&fun_idx.to_idx()).unwrap().0;
563 let dfunc = *dfunctions.get(&fun_idx.to_idx()).unwrap();
564
565 let mut fn_ctx = FnCtx {
566 ctx,
567 fn_ptr,
568 func: func.clone(),
569 builder,
570 dibuilder,
571 storage,
572 blocks: Default::default(),
573 values: Default::default(),
574 block_args: Default::default(),
575 functions: Rc::clone(&functions),
576 globals: Rc::clone(&globals),
577 debug_scope: dfunc,
578 datalayout: &module.data_layout,
579 };
580
581 for (id, _) in func.blocks.iter() {
582 add_block(&mut fn_ctx, id, None);
583 }
584
585 for (id, _) in func.blocks.iter() {
586 lower_block(&mut fn_ctx, id)?;
587 }
588
589 debuginfo::LLVMDIBuilderFinalizeSubprogram(dibuilder, dfunc);
590 }
591
592 debuginfo::LLVMDIBuilderFinalize(dibuilder);
593 debuginfo::LLVMDisposeDIBuilder(dibuilder);
594 core::LLVMDisposeBuilder(builder);
595
596 if std::env::var("IRVM_DUMP_IR").is_ok() {
597 core::LLVMDumpModule(llvm_module);
598 }
599
600 let mut out_msg: *mut i8 = null_mut();
601 let ok = llvm_sys::analysis::LLVMVerifyModule(
602 llvm_module,
603 llvm_sys::analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction,
604 &raw mut out_msg,
605 );
606
607 if ok != 0 {
608 let msg = {
609 let msg = CStr::from_ptr(out_msg);
610 msg.to_string_lossy().to_string()
611 };
612
613 if !out_msg.is_null() {
614 core::LLVMDisposeMessage(out_msg);
615 }
616
617 core::LLVMDisposeModule(llvm_module);
618 core::LLVMContextDispose(ctx);
619
620 return Err(Error::LLVMError(msg));
621 }
622
623 if !out_msg.is_null() {
624 core::LLVMDisposeMessage(out_msg);
625 }
626
627 Ok(CompileResult {
628 context: ctx,
629 module: llvm_module,
630 })
631 }
632}
633
634pub fn compile_object(
638 compile_result: &CompileResult,
639 target_triple: Triple,
640 options: CompileOptions,
641 output_file: &Path,
642 output_assembly: bool,
643) -> Result<(), Error> {
644 unsafe {
645 static INITIALIZED: OnceLock<()> = OnceLock::new();
646 INITIALIZED.get_or_init(|| {
647 LLVM_InitializeAllTargets();
648 LLVM_InitializeAllTargetInfos();
649 LLVM_InitializeAllTargetMCs();
650 LLVM_InitializeAllAsmPrinters();
651 });
652
653 let target_triple = CString::new(target_triple.to_string())?;
654
655 let target_cpu = match &options.target_cpu {
656 TargetCpu::Host => {
657 let cpu = LLVMGetHostCPUName();
658 CString::from(CStr::from_ptr(cpu))
659 }
660 TargetCpu::Name(name) => CString::new(name.as_bytes())?,
661 };
662
663 let target_cpu_features = match &options.target_cpu_features {
664 TargetCpuFeatures::Host => {
665 let cpu = LLVMGetHostCPUFeatures();
666 CString::from(CStr::from_ptr(cpu))
667 }
668 TargetCpuFeatures::Features(name) => CString::new(name.as_bytes())?,
669 };
670
671 let mut out_msg = null_mut();
672
673 let mut target = null_mut();
674
675 let ok = target_machine::LLVMGetTargetFromTriple(
676 target_triple.as_ptr(),
677 &raw mut target,
678 &raw mut out_msg,
679 );
680
681 if ok != 0 {
682 let msg = {
683 let msg = CStr::from_ptr(out_msg);
684 msg.to_string_lossy().to_string()
685 };
686
687 if !out_msg.is_null() {
688 core::LLVMDisposeMessage(out_msg);
689 }
690
691 return Err(Error::LLVMError(msg));
692 }
693
694 if !out_msg.is_null() {
695 core::LLVMDisposeMessage(out_msg);
696 }
697
698 let machine = target_machine::LLVMCreateTargetMachine(
699 target,
700 target_triple.as_ptr(),
701 target_cpu.as_ptr(),
702 target_cpu_features.as_ptr(),
703 match options.opt_level {
704 0 => LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
705 1 => LLVMCodeGenOptLevel::LLVMCodeGenLevelLess,
706 2 => LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
707 _ => LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
708 },
709 match options.relocation_model {
710 RelocModel::Default => LLVMRelocMode::LLVMRelocDefault,
711 RelocModel::Static => LLVMRelocMode::LLVMRelocStatic,
712 RelocModel::Pic => LLVMRelocMode::LLVMRelocPIC,
713 RelocModel::DynamicNoPic => LLVMRelocMode::LLVMRelocDynamicNoPic,
714 RelocModel::Ropi => LLVMRelocMode::LLVMRelocROPI,
715 RelocModel::Rwpi => LLVMRelocMode::LLVMRelocRWPI,
716 RelocModel::RopiRwpi => LLVMRelocMode::LLVMRelocROPI_RWPI,
717 },
718 match options.code_model {
719 CodeModel::Default => LLVMCodeModel::LLVMCodeModelDefault,
720 CodeModel::JitDefault => LLVMCodeModel::LLVMCodeModelJITDefault,
721 CodeModel::Tiny => LLVMCodeModel::LLVMCodeModelTiny,
722 CodeModel::Small => LLVMCodeModel::LLVMCodeModelSmall,
723 CodeModel::Kernel => LLVMCodeModel::LLVMCodeModelKernel,
724 CodeModel::Medium => LLVMCodeModel::LLVMCodeModelMedium,
725 CodeModel::Large => LLVMCodeModel::LLVMCodeModelLarge,
726 },
727 );
728
729 let opts = LLVMCreatePassBuilderOptions();
730
731 let passes = CString::new(format!("default<O{}>", options.opt_level)).unwrap();
732
733 let error = LLVMRunPasses(compile_result.module, passes.as_ptr(), machine, opts);
734
735 if !error.is_null() {
736 let msg_ptr = LLVMGetErrorMessage(error);
737 let msg = {
738 let msg = CStr::from_ptr(msg_ptr);
739 msg.to_string_lossy().to_string()
740 };
741 LLVMDisposeMessage(msg_ptr);
742 LLVMDisposeTargetMachine(machine);
743 return Err(Error::LLVMError(msg));
744 }
745
746 LLVMDisposePassBuilderOptions(opts);
747
748 let mut out_msg: *mut i8 = null_mut();
749 let ok = llvm_sys::analysis::LLVMVerifyModule(
750 compile_result.module,
751 llvm_sys::analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction,
752 &raw mut out_msg,
753 );
754
755 if ok != 0 {
756 let msg = {
757 let msg = CStr::from_ptr(out_msg);
758 msg.to_string_lossy().to_string()
759 };
760
761 if !out_msg.is_null() {
762 core::LLVMDisposeMessage(out_msg);
763 }
764
765 LLVMDisposeTargetMachine(machine);
766
767 return Err(Error::LLVMError(msg));
768 }
769
770 let filename = CString::new(output_file.as_os_str().to_string_lossy().as_bytes()).unwrap();
771
772 let ok = LLVMTargetMachineEmitToFile(
773 machine,
774 compile_result.module,
775 filename.as_ptr().cast_mut(),
776 if output_assembly {
777 LLVMCodeGenFileType::LLVMAssemblyFile
778 } else {
779 LLVMCodeGenFileType::LLVMObjectFile
780 },
781 &raw mut out_msg,
782 );
783
784 LLVMDisposeTargetMachine(machine);
785
786 if ok != 0 {
787 let msg = {
788 let msg = CStr::from_ptr(out_msg);
789 msg.to_string_lossy().to_string()
790 };
791
792 if !out_msg.is_null() {
793 core::LLVMDisposeMessage(out_msg);
794 }
795
796 return Err(Error::LLVMError(msg));
797 }
798
799 Ok(())
800 }
801}
802
803pub fn output_to_file(compile_result: &CompileResult, output_ll: &Path) -> Result<(), Error> {
805 unsafe {
806 let file = CString::new(&*output_ll.to_string_lossy())?;
807
808 let mut out_msg: *mut i8 = null_mut();
809
810 let ok =
811 core::LLVMPrintModuleToFile(compile_result.module, file.as_ptr(), &raw mut out_msg);
812
813 if ok != 0 {
814 let msg = {
815 let msg = CStr::from_ptr(out_msg);
816 msg.to_string_lossy().to_string()
817 };
818
819 if !out_msg.is_null() {
820 core::LLVMDisposeMessage(out_msg);
821 }
822
823 return Err(Error::LLVMError(msg));
824 }
825
826 if !out_msg.is_null() {
827 core::LLVMDisposeMessage(out_msg);
828 }
829
830 Ok(())
831 }
832}
833
834pub fn create_jit_engine(result: CompileResult, optlevel: u32) -> Result<JitEngine, Error> {
836 unsafe {
837 let mut engine = null_mut();
838
839 let mut out_msg: *mut i8 = null_mut();
840
841 let result = ManuallyDrop::new(result);
842
843 static INITIALIZED: OnceLock<()> = OnceLock::new();
844 INITIALIZED.get_or_init(|| {
845 LLVM_InitializeNativeTarget();
846 LLVM_InitializeNativeAsmParser();
847 LLVM_InitializeNativeAsmPrinter();
848 LLVM_InitializeNativeDisassembler();
849 LLVMLinkInMCJIT();
850 });
851
852 let ok = execution_engine::LLVMCreateJITCompilerForModule(
853 &raw mut engine,
854 result.module,
855 optlevel,
856 &raw mut out_msg,
857 );
858
859 if ok != 0 {
860 let msg = {
861 let msg = CStr::from_ptr(out_msg);
862 msg.to_string_lossy().to_string()
863 };
864
865 if !out_msg.is_null() {
866 core::LLVMDisposeMessage(out_msg);
867 }
868
869 return Err(Error::LLVMError(msg));
870 }
871
872 let engine = JitEngine {
873 context: result.context,
874 engine,
875 };
876
877 Ok(engine)
878 }
879}
880
881#[derive(Debug)]
882struct FnCtx<'m> {
883 ctx: LLVMContextRef,
884 fn_ptr: LLVMValueRef,
885 func: Function,
886 storage: &'m TypeStorage,
887 builder: LLVMBuilderRef,
888 dibuilder: LLVMDIBuilderRef,
889 debug_scope: LLVMMetadataRef,
890 functions: Rc<HashMap<usize, (LLVMValueRef, LLVMTypeRef)>>,
891 globals: Rc<HashMap<usize, LLVMValueRef>>,
892 blocks: HashMap<usize, LLVMBasicBlockRef>,
893 values: HashMap<(usize, usize), LLVMValueRef>,
895 block_args: HashMap<usize, Vec<LLVMValueRef>>,
896 datalayout: &'m DataLayout,
897}
898
899fn lower_block(ctx: &mut FnCtx, block_idx: BlockIdx) -> Result<(), Error> {
901 unsafe {
902 let null_name = c"";
903 let block_ptr = *ctx.blocks.get(&block_idx.to_idx()).unwrap();
904 core::LLVMPositionBuilderAtEnd(ctx.builder, block_ptr);
905 add_preds(ctx, block_idx);
906
907 for (inst_idx, (loc, inst)) in ctx.func.blocks[block_idx].instructions().iter() {
908 let loc = set_loc(ctx.ctx, ctx.builder, loc, ctx.debug_scope);
909
910 match inst {
911 Instruction::BinaryOp(binary_op) => match binary_op {
912 irvm::block::BinaryOp::Add { lhs, rhs, nsw, nuw } => {
913 let lhs_ptr = lower_operand(ctx, lhs);
914 let rhs_ptr = lower_operand(ctx, rhs);
915 let value =
916 core::LLVMBuildAdd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
917 if *nuw {
918 core::LLVMSetNUW(value, (*nuw) as i32);
919 }
920 if *nsw {
921 core::LLVMSetNSW(value, (*nsw) as i32);
922 }
923 ctx.values
924 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
925 }
926 irvm::block::BinaryOp::Sub { lhs, rhs, nsw, nuw } => {
927 let lhs_ptr = lower_operand(ctx, lhs);
928 let rhs_ptr = lower_operand(ctx, rhs);
929 let value =
930 core::LLVMBuildSub(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
931 if *nuw {
932 core::LLVMSetNUW(value, (*nuw) as i32);
933 }
934 if *nsw {
935 core::LLVMSetNSW(value, (*nsw) as i32);
936 }
937 ctx.values
938 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
939 }
940 irvm::block::BinaryOp::Mul { lhs, rhs, nsw, nuw } => {
941 let lhs_ptr = lower_operand(ctx, lhs);
942 let rhs_ptr = lower_operand(ctx, rhs);
943 let value =
944 core::LLVMBuildMul(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
945 if *nuw {
946 core::LLVMSetNUW(value, (*nuw) as i32);
947 }
948 if *nsw {
949 core::LLVMSetNSW(value, (*nsw) as i32);
950 }
951 ctx.values
952 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
953 }
954 irvm::block::BinaryOp::Div {
955 lhs,
956 rhs,
957 signed,
958 exact,
959 } => {
960 let lhs_ptr = lower_operand(ctx, lhs);
961 let rhs_ptr = lower_operand(ctx, rhs);
962 let value = if *signed {
963 if *exact {
964 core::LLVMBuildExactSDiv(
965 ctx.builder,
966 lhs_ptr,
967 rhs_ptr,
968 null_name.as_ptr(),
969 )
970 } else {
971 core::LLVMBuildSDiv(
972 ctx.builder,
973 lhs_ptr,
974 rhs_ptr,
975 null_name.as_ptr(),
976 )
977 }
978 } else if *exact {
979 core::LLVMBuildExactUDiv(
980 ctx.builder,
981 lhs_ptr,
982 rhs_ptr,
983 null_name.as_ptr(),
984 )
985 } else {
986 core::LLVMBuildUDiv(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
987 };
988 ctx.values
989 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
990 }
991 irvm::block::BinaryOp::Rem { lhs, rhs, signed } => {
992 let lhs_ptr = lower_operand(ctx, lhs);
993 let rhs_ptr = lower_operand(ctx, rhs);
994 let value = if *signed {
995 core::LLVMBuildSRem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
996 } else {
997 core::LLVMBuildURem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr())
998 };
999 ctx.values
1000 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1001 }
1002 irvm::block::BinaryOp::FAdd { lhs, rhs, flags } => {
1003 let lhs_ptr = lower_operand(ctx, lhs);
1004 let rhs_ptr = lower_operand(ctx, rhs);
1005 let value =
1006 core::LLVMBuildFAdd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1007 apply_fast_math_flags(value, flags);
1008 ctx.values
1009 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1010 }
1011 irvm::block::BinaryOp::FSub { lhs, rhs, flags } => {
1012 let lhs_ptr = lower_operand(ctx, lhs);
1013 let rhs_ptr = lower_operand(ctx, rhs);
1014 let value =
1015 core::LLVMBuildFSub(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1016 apply_fast_math_flags(value, flags);
1017 ctx.values
1018 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1019 }
1020 irvm::block::BinaryOp::FMul { lhs, rhs, flags } => {
1021 let lhs_ptr = lower_operand(ctx, lhs);
1022 let rhs_ptr = lower_operand(ctx, rhs);
1023 let value =
1024 core::LLVMBuildFMul(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1025 apply_fast_math_flags(value, flags);
1026 ctx.values
1027 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1028 }
1029 irvm::block::BinaryOp::FDiv { lhs, rhs, flags } => {
1030 let lhs_ptr = lower_operand(ctx, lhs);
1031 let rhs_ptr = lower_operand(ctx, rhs);
1032 let value =
1033 core::LLVMBuildFDiv(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1034 apply_fast_math_flags(value, flags);
1035 ctx.values
1036 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1037 }
1038 irvm::block::BinaryOp::FRem { lhs, rhs, flags } => {
1039 let lhs_ptr = lower_operand(ctx, lhs);
1040 let rhs_ptr = lower_operand(ctx, rhs);
1041 let value =
1042 core::LLVMBuildFRem(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1043 apply_fast_math_flags(value, flags);
1044 ctx.values
1045 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1046 }
1047 irvm::block::BinaryOp::FNeg { value, flags } => {
1048 let val_ptr = lower_operand(ctx, value);
1049 let result = core::LLVMBuildFNeg(ctx.builder, val_ptr, null_name.as_ptr());
1050 apply_fast_math_flags(result, flags);
1051 ctx.values
1052 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1053 }
1054 },
1055 Instruction::BitwiseBinaryOp(bitwise_binary_op) => match bitwise_binary_op {
1056 irvm::block::BitwiseBinaryOp::Shl { lhs, rhs } => {
1057 let lhs_ptr = lower_operand(ctx, lhs);
1058 let rhs_ptr = lower_operand(ctx, rhs);
1059 let value =
1060 core::LLVMBuildShl(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1061 ctx.values
1062 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1063 }
1064 irvm::block::BitwiseBinaryOp::Lshr { lhs, rhs, exact } => {
1065 let lhs_ptr = lower_operand(ctx, lhs);
1066 let rhs_ptr = lower_operand(ctx, rhs);
1067 let value =
1068 core::LLVMBuildLShr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1069 core::LLVMSetExact(value, (*exact) as i32);
1070 ctx.values
1071 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1072 }
1073 irvm::block::BitwiseBinaryOp::Ashr { lhs, rhs, exact } => {
1074 let lhs_ptr = lower_operand(ctx, lhs);
1075 let rhs_ptr = lower_operand(ctx, rhs);
1076 let value =
1077 core::LLVMBuildAShr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1078 core::LLVMSetExact(value, (*exact) as i32);
1079 ctx.values
1080 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1081 }
1082 irvm::block::BitwiseBinaryOp::And { lhs, rhs } => {
1083 let lhs_ptr = lower_operand(ctx, lhs);
1084 let rhs_ptr = lower_operand(ctx, rhs);
1085 let value =
1086 core::LLVMBuildAnd(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1087 ctx.values
1088 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1089 }
1090 irvm::block::BitwiseBinaryOp::Or { lhs, rhs, disjoint } => {
1091 let lhs_ptr = lower_operand(ctx, lhs);
1092 let rhs_ptr = lower_operand(ctx, rhs);
1093 let value =
1094 core::LLVMBuildOr(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1095 core::LLVMSetIsDisjoint(value, (*disjoint) as i32);
1096 ctx.values
1097 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1098 }
1099 irvm::block::BitwiseBinaryOp::Xor { lhs, rhs } => {
1100 let lhs_ptr = lower_operand(ctx, lhs);
1101 let rhs_ptr = lower_operand(ctx, rhs);
1102 let value =
1103 core::LLVMBuildXor(ctx.builder, lhs_ptr, rhs_ptr, null_name.as_ptr());
1104 ctx.values
1105 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1106 }
1107 },
1108 Instruction::VectorOp(vector_op) => match vector_op {
1109 irvm::block::VectorOp::ExtractElement { vector, idx } => {
1110 let vector = lower_operand(ctx, vector);
1111 let idx = lower_operand(ctx, idx);
1112 let value = core::LLVMBuildExtractElement(
1113 ctx.builder,
1114 vector,
1115 idx,
1116 null_name.as_ptr(),
1117 );
1118 ctx.values
1119 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1120 }
1121 irvm::block::VectorOp::InsertElement {
1122 vector,
1123 element,
1124 idx,
1125 } => {
1126 let vec_val = lower_operand(ctx, vector);
1127 let elem_val = lower_operand(ctx, element);
1128 let idx_val = lower_operand(ctx, idx);
1129 let value = core::LLVMBuildInsertElement(
1130 ctx.builder,
1131 vec_val,
1132 elem_val,
1133 idx_val,
1134 null_name.as_ptr(),
1135 );
1136 ctx.values
1137 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1138 }
1139 irvm::block::VectorOp::ShuffleVector { vec1, vec2, mask } => {
1140 let v1 = lower_operand(ctx, vec1);
1141 let v2 = lower_operand(ctx, vec2);
1142
1143 let i32_ty = core::LLVMInt32TypeInContext(ctx.ctx);
1145 let mut mask_vals: Vec<LLVMValueRef> = mask
1146 .iter()
1147 .map(|&m| {
1148 if m < 0 {
1149 core::LLVMGetUndef(i32_ty)
1150 } else {
1151 core::LLVMConstInt(i32_ty, m as u64, 0)
1152 }
1153 })
1154 .collect();
1155 let mask_val =
1156 core::LLVMConstVector(mask_vals.as_mut_ptr(), mask_vals.len() as u32);
1157
1158 let value = core::LLVMBuildShuffleVector(
1159 ctx.builder,
1160 v1,
1161 v2,
1162 mask_val,
1163 null_name.as_ptr(),
1164 );
1165 ctx.values
1166 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1167 }
1168 },
1169 Instruction::MemoryOp(memory_op) => match memory_op {
1170 irvm::block::MemoryOp::Alloca {
1171 ty, num_elements, ..
1172 } => {
1173 let ty_ptr = lower_type(ctx.ctx, ctx.storage, *ty);
1174 let value = if *num_elements > 1 {
1175 let const_val = core::LLVMConstInt(
1176 core::LLVMInt64TypeInContext(ctx.ctx),
1177 (*num_elements) as u64,
1178 0,
1179 );
1180 core::LLVMBuildArrayAlloca(
1181 ctx.builder,
1182 ty_ptr,
1183 const_val,
1184 null_name.as_ptr(),
1185 )
1186 } else {
1187 core::LLVMBuildAlloca(ctx.builder, ty_ptr, null_name.as_ptr())
1188 };
1189 ctx.values
1190 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1191 }
1192 irvm::block::MemoryOp::Load {
1193 ptr,
1194 align,
1195 volatile,
1196 } => {
1197 let ptr_val = lower_operand(ctx, ptr);
1198 let ty_ptr =
1199 lower_type(ctx.ctx, ctx.storage, ptr.get_inner_type(ctx.storage)?);
1200
1201 let value =
1202 core::LLVMBuildLoad2(ctx.builder, ty_ptr, ptr_val, null_name.as_ptr());
1203 if let Some(align) = align {
1204 core::LLVMSetAlignment(value, *align / 8);
1205 }
1206 if *volatile {
1207 core::LLVMSetVolatile(value, 1);
1208 }
1209
1210 ctx.values
1211 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1212 }
1213 irvm::block::MemoryOp::Store {
1214 value,
1215 ptr,
1216 align,
1217 volatile,
1218 } => {
1219 let ptr_val = lower_operand(ctx, ptr);
1220 let value_val = lower_operand(ctx, value);
1221
1222 let value = core::LLVMBuildStore(ctx.builder, value_val, ptr_val);
1223 if let Some(align) = align {
1224 core::LLVMSetAlignment(value, *align / 8);
1225 }
1226 if *volatile {
1227 core::LLVMSetVolatile(value, 1);
1228 }
1229
1230 ctx.values
1231 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1232 }
1233 irvm::block::MemoryOp::GetElementPtr { ptr, indices } => {
1234 let ptr_val = lower_operand(ctx, ptr);
1235 let pointee_ty =
1236 lower_type(ctx.ctx, ctx.storage, ptr.get_inner_type(ctx.storage)?);
1237
1238 let mut x = Vec::new();
1239
1240 for index in indices {
1241 let value = match index {
1242 irvm::block::GepIndex::Const(value) => core::LLVMConstInt(
1243 core::LLVMInt64TypeInContext(ctx.ctx),
1244 (*value) as u64,
1245 0,
1246 ),
1247 irvm::block::GepIndex::Value(operand) => {
1248 lower_operand(ctx, operand)
1249 }
1250 };
1251
1252 x.push(value);
1253 }
1254
1255 let value = core::LLVMBuildGEP2(
1256 ctx.builder,
1257 pointee_ty,
1258 ptr_val,
1259 x.as_mut_ptr(),
1260 x.len() as u32,
1261 null_name.as_ptr(),
1262 );
1263
1264 ctx.values
1265 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1266 }
1267 irvm::block::MemoryOp::AtomicLoad {
1268 ptr,
1269 ordering,
1270 align,
1271 sync_scope,
1272 } => {
1273 let ptr_val = lower_operand(ctx, ptr);
1274 let ty_ptr =
1275 lower_type(ctx.ctx, ctx.storage, ptr.get_inner_type(ctx.storage)?);
1276
1277 let value =
1278 core::LLVMBuildLoad2(ctx.builder, ty_ptr, ptr_val, null_name.as_ptr());
1279 core::LLVMSetOrdering(value, lower_atomic_ordering(ordering));
1280 core::LLVMSetVolatile(value, 0);
1281 if let Some(a) = align {
1282 core::LLVMSetAlignment(value, *a / 8);
1283 }
1284 let _ = sync_scope; ctx.values
1286 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1287 }
1288 irvm::block::MemoryOp::AtomicStore {
1289 value,
1290 ptr,
1291 ordering,
1292 align,
1293 sync_scope,
1294 } => {
1295 let ptr_val = lower_operand(ctx, ptr);
1296 let val = lower_operand(ctx, value);
1297 let store = core::LLVMBuildStore(ctx.builder, val, ptr_val);
1298 core::LLVMSetOrdering(store, lower_atomic_ordering(ordering));
1299 if let Some(a) = align {
1300 core::LLVMSetAlignment(store, *a / 8);
1301 }
1302 let _ = sync_scope; ctx.values
1304 .insert((block_idx.to_idx(), inst_idx.to_idx()), store);
1305 }
1306 irvm::block::MemoryOp::AtomicRMW {
1307 op,
1308 ptr,
1309 value,
1310 ordering,
1311 sync_scope,
1312 } => {
1313 let ptr_val = lower_operand(ctx, ptr);
1314 let val = lower_operand(ctx, value);
1315 let result = core::LLVMBuildAtomicRMW(
1316 ctx.builder,
1317 lower_atomic_rmw_op(op),
1318 ptr_val,
1319 val,
1320 lower_atomic_ordering(ordering),
1321 matches!(sync_scope, SyncScope::SingleThread) as i32,
1322 );
1323 ctx.values
1324 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1325 }
1326 irvm::block::MemoryOp::CmpXchg {
1327 ptr,
1328 cmp,
1329 new_val,
1330 success_ordering,
1331 failure_ordering,
1332 weak,
1333 sync_scope,
1334 } => {
1335 let ptr_val = lower_operand(ctx, ptr);
1336 let cmp_val = lower_operand(ctx, cmp);
1337 let new_val_ptr = lower_operand(ctx, new_val);
1338 let result = core::LLVMBuildAtomicCmpXchg(
1339 ctx.builder,
1340 ptr_val,
1341 cmp_val,
1342 new_val_ptr,
1343 lower_atomic_ordering(success_ordering),
1344 lower_atomic_ordering(failure_ordering),
1345 matches!(sync_scope, SyncScope::SingleThread) as i32,
1346 );
1347 core::LLVMSetWeak(result, *weak as i32);
1348 ctx.values
1349 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1350 }
1351 irvm::block::MemoryOp::Fence {
1352 ordering,
1353 sync_scope,
1354 } => {
1355 core::LLVMBuildFence(
1356 ctx.builder,
1357 lower_atomic_ordering(ordering),
1358 matches!(sync_scope, SyncScope::SingleThread) as i32,
1359 null_name.as_ptr(),
1360 );
1361 }
1362 },
1363 Instruction::OtherOp(other_op) => match other_op {
1364 irvm::block::OtherOp::Call(call_op) => {
1365 let (target_fn_ptr, fn_ty) = match &call_op.fn_target {
1366 irvm::block::CallableValue::Symbol(id) => {
1367 *ctx.functions.get(&id.to_idx()).expect("function not found")
1368 }
1369 irvm::block::CallableValue::Pointer(operand, fn_ty) => {
1370 let ptr = lower_operand(ctx, operand);
1371
1372 let ret_ty = lower_type(ctx.ctx, ctx.storage, fn_ty.return_type);
1373 let mut params = fn_ty
1374 .parameters
1375 .iter()
1376 .map(|x| lower_type(ctx.ctx, ctx.storage, *x))
1377 .collect_vec();
1378 let fn_ty = core::LLVMFunctionType(
1379 ret_ty,
1380 params.as_mut_ptr(),
1381 params.len() as u32,
1382 0,
1383 );
1384 (ptr, fn_ty)
1385 }
1386 };
1387
1388 let mut args = call_op
1389 .params
1390 .iter()
1391 .map(|p| lower_operand(ctx, p))
1392 .collect_vec();
1393
1394 let value = core::LLVMBuildCall2(
1395 ctx.builder,
1396 fn_ty,
1397 target_fn_ptr,
1398 args.as_mut_ptr(),
1399 args.len() as u32,
1400 null_name.as_ptr(),
1401 );
1402
1403 ctx.values
1404 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1405 }
1406 irvm::block::OtherOp::Icmp { cond, lhs, rhs } => {
1407 let lhs_val = lower_operand(ctx, lhs);
1408 let rhs_val = lower_operand(ctx, rhs);
1409 let value = core::LLVMBuildICmp(
1410 ctx.builder,
1411 match cond {
1412 irvm::block::IcmpCond::Eq => LLVMIntPredicate::LLVMIntEQ,
1413 irvm::block::IcmpCond::Ne => LLVMIntPredicate::LLVMIntNE,
1414 irvm::block::IcmpCond::Ugt => LLVMIntPredicate::LLVMIntUGT,
1415 irvm::block::IcmpCond::Uge => LLVMIntPredicate::LLVMIntUGE,
1416 irvm::block::IcmpCond::Ult => LLVMIntPredicate::LLVMIntULT,
1417 irvm::block::IcmpCond::Ule => LLVMIntPredicate::LLVMIntULE,
1418 irvm::block::IcmpCond::Sgt => LLVMIntPredicate::LLVMIntSGT,
1419 irvm::block::IcmpCond::Sge => LLVMIntPredicate::LLVMIntSGE,
1420 irvm::block::IcmpCond::Slt => LLVMIntPredicate::LLVMIntSLT,
1421 irvm::block::IcmpCond::Sle => LLVMIntPredicate::LLVMIntSLE,
1422 },
1423 lhs_val,
1424 rhs_val,
1425 null_name.as_ptr(),
1426 );
1427 ctx.values
1428 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1429 }
1430 irvm::block::OtherOp::Fcmp { cond, lhs, rhs } => {
1431 let lhs_val = lower_operand(ctx, lhs);
1432 let rhs_val = lower_operand(ctx, rhs);
1433 let value = core::LLVMBuildFCmp(
1434 ctx.builder,
1435 match cond {
1436 irvm::block::FcmpCond::False => {
1437 LLVMRealPredicate::LLVMRealPredicateFalse
1438 }
1439 irvm::block::FcmpCond::Oeq => LLVMRealPredicate::LLVMRealOEQ,
1440 irvm::block::FcmpCond::Ogt => LLVMRealPredicate::LLVMRealOGT,
1441 irvm::block::FcmpCond::Oge => LLVMRealPredicate::LLVMRealOGE,
1442 irvm::block::FcmpCond::Olt => LLVMRealPredicate::LLVMRealOLT,
1443 irvm::block::FcmpCond::Ole => LLVMRealPredicate::LLVMRealOLE,
1444 irvm::block::FcmpCond::One => LLVMRealPredicate::LLVMRealONE,
1445 irvm::block::FcmpCond::Ord => LLVMRealPredicate::LLVMRealORD,
1446 irvm::block::FcmpCond::Ueq => LLVMRealPredicate::LLVMRealUEQ,
1447 irvm::block::FcmpCond::Ugt => LLVMRealPredicate::LLVMRealUGT,
1448 irvm::block::FcmpCond::Ult => LLVMRealPredicate::LLVMRealULT,
1449 irvm::block::FcmpCond::Ule => LLVMRealPredicate::LLVMRealULE,
1450 irvm::block::FcmpCond::Une => LLVMRealPredicate::LLVMRealUNE,
1451 irvm::block::FcmpCond::Uno => LLVMRealPredicate::LLVMRealUNO,
1452 irvm::block::FcmpCond::True => {
1453 LLVMRealPredicate::LLVMRealPredicateTrue
1454 }
1455 },
1456 lhs_val,
1457 rhs_val,
1458 null_name.as_ptr(),
1459 );
1460 ctx.values
1461 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1462 }
1463 irvm::block::OtherOp::Select {
1464 cond,
1465 true_val,
1466 false_val,
1467 } => {
1468 let cond_val = lower_operand(ctx, cond);
1469 let true_ptr = lower_operand(ctx, true_val);
1470 let false_ptr = lower_operand(ctx, false_val);
1471 let value = core::LLVMBuildSelect(
1472 ctx.builder,
1473 cond_val,
1474 true_ptr,
1475 false_ptr,
1476 null_name.as_ptr(),
1477 );
1478 ctx.values
1479 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1480 }
1481 irvm::block::OtherOp::LandingPad {
1482 result_ty,
1483 cleanup,
1484 clauses,
1485 } => {
1486 let ty = lower_type(ctx.ctx, ctx.storage, *result_ty);
1487 let lp = core::LLVMBuildLandingPad(
1488 ctx.builder,
1489 ty,
1490 null_mut(), clauses.len() as u32,
1492 null_name.as_ptr(),
1493 );
1494
1495 if *cleanup {
1496 core::LLVMSetCleanup(lp, 1);
1497 }
1498
1499 for clause in clauses {
1500 match clause {
1501 irvm::block::LandingPadClause::Catch(operand) => {
1502 let catch_val = lower_operand(ctx, operand);
1503 core::LLVMAddClause(lp, catch_val);
1504 }
1505 irvm::block::LandingPadClause::Filter(operands) => {
1506 let i8_ptr_ty = core::LLVMPointerType(
1508 core::LLVMInt8TypeInContext(ctx.ctx),
1509 0,
1510 );
1511 let mut filter_vals: Vec<_> =
1512 operands.iter().map(|o| lower_operand(ctx, o)).collect();
1513 let filter_arr = core::LLVMConstArray2(
1514 i8_ptr_ty,
1515 filter_vals.as_mut_ptr(),
1516 filter_vals.len() as u64,
1517 );
1518 core::LLVMAddClause(lp, filter_arr);
1519 }
1520 }
1521 }
1522
1523 ctx.values
1524 .insert((block_idx.to_idx(), inst_idx.to_idx()), lp);
1525 }
1526 irvm::block::OtherOp::Intrinsic(intrinsic) => {
1527 let value = lower_intrinsic(ctx, intrinsic, block_idx, inst_idx)?;
1528 if !value.is_null() {
1529 ctx.values
1530 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1531 }
1532 }
1533 },
1534 Instruction::DebugOp(debug_op) => match debug_op {
1535 DebugOp::Declare { address, variable } => {
1536 let var = ctx.func.debug_vars.get(*variable).unwrap();
1537 let address_ptr = lower_operand(ctx, address);
1538 let var_ptr = lower_debug_var(
1539 ctx.dibuilder,
1540 ctx.debug_scope,
1541 ctx.datalayout,
1542 var,
1543 ctx.storage,
1544 )?;
1545
1546 let diexpr =
1547 debuginfo::LLVMDIBuilderCreateExpression(ctx.dibuilder, null_mut(), 0);
1548 debuginfo::LLVMDIBuilderInsertDeclareRecordAtEnd(
1549 ctx.dibuilder,
1550 address_ptr,
1551 var_ptr,
1552 diexpr,
1553 loc,
1554 block_ptr,
1555 );
1556 }
1557 DebugOp::Value {
1558 new_value,
1559 variable,
1560 } => {
1561 let var = ctx.func.debug_vars.get(*variable).unwrap();
1562 let value_ptr = lower_operand(ctx, new_value);
1563 let var_ptr = lower_debug_var(
1564 ctx.dibuilder,
1565 ctx.debug_scope,
1566 ctx.datalayout,
1567 var,
1568 ctx.storage,
1569 )?;
1570
1571 let diexpr =
1572 debuginfo::LLVMDIBuilderCreateExpression(ctx.dibuilder, null_mut(), 0);
1573 debuginfo::LLVMDIBuilderInsertDbgValueRecordAtEnd(
1574 ctx.dibuilder,
1575 value_ptr,
1576 var_ptr,
1577 diexpr,
1578 loc,
1579 block_ptr,
1580 );
1581 }
1582 DebugOp::Assign { .. } => {
1583 todo!()
1585 }
1586 },
1587 Instruction::ConversionOp(conv_op) => match conv_op {
1588 irvm::block::ConversionOp::Trunc { value, target_ty } => {
1589 let val = lower_operand(ctx, value);
1590 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1591 let result = core::LLVMBuildTrunc(ctx.builder, val, ty, null_name.as_ptr());
1592 ctx.values
1593 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1594 }
1595 irvm::block::ConversionOp::ZExt { value, target_ty } => {
1596 let val = lower_operand(ctx, value);
1597 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1598 let result = core::LLVMBuildZExt(ctx.builder, val, ty, null_name.as_ptr());
1599 ctx.values
1600 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1601 }
1602 irvm::block::ConversionOp::SExt { value, target_ty } => {
1603 let val = lower_operand(ctx, value);
1604 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1605 let result = core::LLVMBuildSExt(ctx.builder, val, ty, null_name.as_ptr());
1606 ctx.values
1607 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1608 }
1609 irvm::block::ConversionOp::FPTrunc { value, target_ty } => {
1610 let val = lower_operand(ctx, value);
1611 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1612 let result =
1613 core::LLVMBuildFPTrunc(ctx.builder, val, ty, null_name.as_ptr());
1614 ctx.values
1615 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1616 }
1617 irvm::block::ConversionOp::FPExt { value, target_ty } => {
1618 let val = lower_operand(ctx, value);
1619 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1620 let result = core::LLVMBuildFPExt(ctx.builder, val, ty, null_name.as_ptr());
1621 ctx.values
1622 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1623 }
1624 irvm::block::ConversionOp::FPToUI { value, target_ty } => {
1625 let val = lower_operand(ctx, value);
1626 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1627 let result =
1628 core::LLVMBuildFPToUI(ctx.builder, val, ty, null_name.as_ptr());
1629 ctx.values
1630 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1631 }
1632 irvm::block::ConversionOp::FPToSI { value, target_ty } => {
1633 let val = lower_operand(ctx, value);
1634 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1635 let result =
1636 core::LLVMBuildFPToSI(ctx.builder, val, ty, null_name.as_ptr());
1637 ctx.values
1638 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1639 }
1640 irvm::block::ConversionOp::UIToFP { value, target_ty } => {
1641 let val = lower_operand(ctx, value);
1642 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1643 let result =
1644 core::LLVMBuildUIToFP(ctx.builder, val, ty, null_name.as_ptr());
1645 ctx.values
1646 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1647 }
1648 irvm::block::ConversionOp::SIToFP { value, target_ty } => {
1649 let val = lower_operand(ctx, value);
1650 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1651 let result =
1652 core::LLVMBuildSIToFP(ctx.builder, val, ty, null_name.as_ptr());
1653 ctx.values
1654 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1655 }
1656 irvm::block::ConversionOp::PtrToInt { value, target_ty } => {
1657 let val = lower_operand(ctx, value);
1658 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1659 let result =
1660 core::LLVMBuildPtrToInt(ctx.builder, val, ty, null_name.as_ptr());
1661 ctx.values
1662 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1663 }
1664 irvm::block::ConversionOp::IntToPtr { value, target_ty } => {
1665 let val = lower_operand(ctx, value);
1666 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1667 let result =
1668 core::LLVMBuildIntToPtr(ctx.builder, val, ty, null_name.as_ptr());
1669 ctx.values
1670 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1671 }
1672 irvm::block::ConversionOp::Bitcast { value, target_ty } => {
1673 let val = lower_operand(ctx, value);
1674 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1675 let result =
1676 core::LLVMBuildBitCast(ctx.builder, val, ty, null_name.as_ptr());
1677 ctx.values
1678 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1679 }
1680 irvm::block::ConversionOp::AddrSpaceCast { value, target_ty } => {
1681 let val = lower_operand(ctx, value);
1682 let ty = lower_type(ctx.ctx, ctx.storage, *target_ty);
1683 let result =
1684 core::LLVMBuildAddrSpaceCast(ctx.builder, val, ty, null_name.as_ptr());
1685 ctx.values
1686 .insert((block_idx.to_idx(), inst_idx.to_idx()), result);
1687 }
1688 },
1689 Instruction::AggregateOp(agg_op) => match agg_op {
1690 irvm::block::AggregateOp::ExtractValue { aggregate, indices } => {
1691 let agg_val = lower_operand(ctx, aggregate);
1692 let value = if indices.len() == 1 {
1693 core::LLVMBuildExtractValue(
1694 ctx.builder,
1695 agg_val,
1696 indices[0],
1697 null_name.as_ptr(),
1698 )
1699 } else {
1700 let mut result = agg_val;
1702 for &idx in indices {
1703 result = core::LLVMBuildExtractValue(
1704 ctx.builder,
1705 result,
1706 idx,
1707 null_name.as_ptr(),
1708 );
1709 }
1710 result
1711 };
1712 ctx.values
1713 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1714 }
1715 irvm::block::AggregateOp::InsertValue {
1716 aggregate,
1717 element,
1718 indices,
1719 } => {
1720 let agg_val = lower_operand(ctx, aggregate);
1721 let elem_val = lower_operand(ctx, element);
1722 let value = if indices.len() == 1 {
1723 core::LLVMBuildInsertValue(
1724 ctx.builder,
1725 agg_val,
1726 elem_val,
1727 indices[0],
1728 null_name.as_ptr(),
1729 )
1730 } else {
1731 core::LLVMBuildInsertValue(
1736 ctx.builder,
1737 agg_val,
1738 elem_val,
1739 indices[0],
1740 null_name.as_ptr(),
1741 )
1742 };
1743 ctx.values
1744 .insert((block_idx.to_idx(), inst_idx.to_idx()), value);
1745 }
1746 },
1747 }
1748 }
1749
1750 match ctx.func.blocks[block_idx].terminator().clone() {
1751 irvm::block::Terminator::Ret(op) => {
1752 set_loc(ctx.ctx, ctx.builder, &op.0, ctx.debug_scope);
1753 if let Some(op) = op.1 {
1754 let value = lower_operand(ctx, &op);
1755 core::LLVMBuildRet(ctx.builder, value);
1756 } else {
1757 core::LLVMBuildRetVoid(ctx.builder);
1758 }
1759 }
1760 irvm::block::Terminator::Br {
1761 block: jmp_block,
1762 location,
1763 ..
1764 } => {
1765 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1766 let target_block = *ctx.blocks.get(&jmp_block.to_idx()).unwrap();
1767
1768 core::LLVMBuildBr(ctx.builder, target_block);
1769 }
1770 irvm::block::Terminator::CondBr {
1771 then_block: if_block,
1772 else_block: then_block,
1773 cond,
1774 ..
1775 } => {
1776 let cond = lower_operand(ctx, &cond);
1777
1778 let if_block_value = *ctx.blocks.get(&if_block.to_idx()).unwrap();
1779 let then_block_value = *ctx.blocks.get(&then_block.to_idx()).unwrap();
1780
1781 core::LLVMBuildCondBr(ctx.builder, cond, if_block_value, then_block_value);
1782 }
1783 irvm::block::Terminator::Switch {
1784 value,
1785 default_block,
1786 cases,
1787 location,
1788 ..
1789 } => {
1790 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1791 let switch_val = lower_operand(ctx, &value);
1792 let default_bb = *ctx.blocks.get(&default_block.to_idx()).unwrap();
1793
1794 let switch_instr =
1795 core::LLVMBuildSwitch(ctx.builder, switch_val, default_bb, cases.len() as u32);
1796
1797 let val_ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
1798
1799 for case in cases {
1800 let case_bb = *ctx.blocks.get(&case.block.to_idx()).unwrap();
1801 let case_val = core::LLVMConstInt(val_ty, case.value, 0);
1802 core::LLVMAddCase(switch_instr, case_val, case_bb);
1803 }
1804 }
1805 irvm::block::Terminator::Invoke {
1806 call,
1807 normal_dest,
1808 unwind_dest,
1809 location,
1810 ..
1811 } => {
1812 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1813
1814 let (target_fn_ptr, fn_ty) = match &call.fn_target {
1815 irvm::block::CallableValue::Symbol(id) => {
1816 *ctx.functions.get(&id.to_idx()).expect("function not found")
1817 }
1818 irvm::block::CallableValue::Pointer(operand, fn_ty) => {
1819 let ptr = lower_operand(ctx, operand);
1820
1821 let ret_ty = lower_type(ctx.ctx, ctx.storage, fn_ty.return_type);
1822 let mut params = fn_ty
1823 .parameters
1824 .iter()
1825 .map(|x| lower_type(ctx.ctx, ctx.storage, *x))
1826 .collect_vec();
1827 let fn_ty = core::LLVMFunctionType(
1828 ret_ty,
1829 params.as_mut_ptr(),
1830 params.len() as u32,
1831 0,
1832 );
1833 (ptr, fn_ty)
1834 }
1835 };
1836
1837 let mut args = call
1838 .params
1839 .iter()
1840 .map(|p| lower_operand(ctx, p))
1841 .collect_vec();
1842
1843 let normal_bb = *ctx.blocks.get(&normal_dest.to_idx()).unwrap();
1844 let unwind_bb = *ctx.blocks.get(&unwind_dest.to_idx()).unwrap();
1845
1846 core::LLVMBuildInvoke2(
1847 ctx.builder,
1848 fn_ty,
1849 target_fn_ptr,
1850 args.as_mut_ptr(),
1851 args.len() as u32,
1852 normal_bb,
1853 unwind_bb,
1854 c"".as_ptr(),
1855 );
1856 }
1857 irvm::block::Terminator::Resume { value, location } => {
1858 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1859 let val = lower_operand(ctx, &value);
1860 core::LLVMBuildResume(ctx.builder, val);
1861 }
1862 irvm::block::Terminator::Unreachable { location } => {
1863 set_loc(ctx.ctx, ctx.builder, &location, ctx.debug_scope);
1864 core::LLVMBuildUnreachable(ctx.builder);
1865 }
1866 }
1867
1868 Ok(())
1869 }
1870}
1871
1872fn add_block(ctx: &mut FnCtx, block_idx: BlockIdx, name: Option<String>) -> LLVMBasicBlockRef {
1873 unsafe {
1874 let block_name = CString::new(if block_idx.to_idx() == 0 {
1875 "entry".to_string()
1876 } else if let Some(name) = name {
1877 format!("bb{name}")
1878 } else {
1879 format!("bb{}", block_idx.to_idx())
1880 })
1881 .unwrap();
1882 let block_ptr = core::LLVMAppendBasicBlock(ctx.fn_ptr, block_name.as_ptr());
1883 ctx.blocks.insert(block_idx.to_idx(), block_ptr);
1884 block_ptr
1885 }
1886}
1887
1888fn lower_debug_var(
1889 dibuilder: LLVMDIBuilderRef,
1890 scope: LLVMMetadataRef,
1891 datalayout: &DataLayout,
1892 variable: &DebugVariable,
1893 storage: &TypeStorage,
1894) -> Result<LLVMMetadataRef, Error> {
1895 let name = CString::new(variable.name.clone())?;
1896 let difile = get_difile_location(dibuilder, &variable.location);
1897
1898 let (line, _col) = match &variable.location {
1899 Location::Unknown => (0, 0),
1900 Location::File(file_location) => (file_location.line, file_location.col),
1901 };
1902
1903 let ty_ptr = lower_debug_type(datalayout, dibuilder, storage, scope, variable.ty);
1904 let align = datalayout.get_type_align(storage, variable.ty);
1905
1906 Ok(unsafe {
1907 if let Some(param) = variable.parameter {
1908 debuginfo::LLVMDIBuilderCreateParameterVariable(
1909 dibuilder,
1910 scope,
1911 name.as_ptr(),
1912 name.count_bytes(),
1913 param,
1914 difile,
1915 line,
1916 ty_ptr,
1917 1,
1918 0,
1919 )
1920 } else {
1921 debuginfo::LLVMDIBuilderCreateAutoVariable(
1922 dibuilder,
1923 scope,
1924 name.as_ptr(),
1925 name.count_bytes(),
1926 difile,
1927 line,
1928 ty_ptr,
1929 1,
1930 0,
1931 align,
1932 )
1933 }
1934 })
1935}
1936
1937fn get_difile_location(dibuilder: LLVMDIBuilderRef, location: &Location) -> LLVMMetadataRef {
1938 match location {
1939 Location::Unknown => unsafe {
1940 debuginfo::LLVMDIBuilderCreateFile(
1941 dibuilder,
1942 c"/dev/stdin".as_ptr(),
1943 c"/dev/stdin".count_bytes(),
1944 c"".as_ptr(),
1945 0,
1946 )
1947 },
1948 Location::File(file_location) => get_difile(dibuilder, &file_location.file),
1949 }
1950}
1951
1952fn get_difile(dibuilder: LLVMDIBuilderRef, file: &Path) -> LLVMMetadataRef {
1953 let parent = if let Some(parent) = file.parent() {
1954 CString::new(parent.display().to_string()).unwrap()
1955 } else {
1956 CString::new("").unwrap()
1957 };
1958
1959 let filename = CString::new(file.display().to_string()).unwrap();
1960
1961 unsafe {
1962 debuginfo::LLVMDIBuilderCreateFile(
1963 dibuilder,
1964 filename.as_ptr(),
1965 filename.count_bytes(),
1966 parent.as_ptr(),
1967 parent.count_bytes(),
1968 )
1969 }
1970}
1971
1972fn set_loc(
1973 ctx: LLVMContextRef,
1974 builder: LLVMBuilderRef,
1975 location: &Location,
1976 scope: LLVMMetadataRef,
1977) -> *mut LLVMOpaqueMetadata {
1978 match location {
1979 Location::Unknown => unsafe {
1980 let loc = debuginfo::LLVMDIBuilderCreateDebugLocation(ctx, 0, 0, scope, null_mut());
1981 core::LLVMSetCurrentDebugLocation2(builder, loc);
1982 loc
1983 },
1984 Location::File(file_location) => unsafe {
1985 let loc = debuginfo::LLVMDIBuilderCreateDebugLocation(
1986 ctx,
1987 file_location.line,
1988 file_location.col,
1989 scope,
1990 null_mut(),
1991 );
1992 core::LLVMSetCurrentDebugLocation2(builder, loc);
1993 loc
1994 },
1995 }
1996}
1997
1998fn add_preds(ctx: &mut FnCtx, block_idx: BlockIdx) {
1999 unsafe {
2000 let block_ptr = *ctx.blocks.get(&block_idx.to_idx()).unwrap();
2001 core::LLVMPositionBuilderAtEnd(ctx.builder, block_ptr);
2002
2003 let preds = ctx.func.find_preds_for(block_idx);
2004 let mut block_args = Vec::new();
2005
2006 if !preds.is_empty() {
2007 let operand_len = preds.first().unwrap().1.len();
2008
2009 for i in 0..(operand_len) {
2010 let phy_ty =
2011 lower_type(ctx.ctx, ctx.storage, preds.first().unwrap().1[i].get_type());
2012 let phi_node = core::LLVMBuildPhi(ctx.builder, phy_ty, c"".as_ptr());
2013 let mut blocks = Vec::new();
2014 let mut values = Vec::new();
2015 for (pred_block_idx, operands) in &preds {
2016 let pred_ptr = ctx.blocks.get(&pred_block_idx.to_idx()).unwrap();
2017 let value = lower_operand(ctx, &operands[i]);
2018
2019 blocks.push(*pred_ptr);
2020 values.push(value);
2021 }
2022
2023 assert_eq!(values.len(), values.len());
2024
2025 core::LLVMAddIncoming(
2026 phi_node,
2027 values.as_mut_ptr().cast(),
2028 blocks.as_mut_ptr().cast(),
2029 blocks.len() as u32,
2030 );
2031 block_args.push(phi_node);
2032 }
2033 }
2034
2035 ctx.block_args.insert(block_idx.to_idx(), block_args);
2036 }
2037}
2038
2039fn lower_operand(ctx: &FnCtx, operand: &Operand) -> LLVMValueRef {
2040 unsafe {
2041 match operand {
2042 Operand::Parameter(idx, _ty) => core::LLVMGetParam(ctx.fn_ptr, (*idx) as u32),
2043 Operand::Value(block_idx, index, _) => *ctx
2044 .values
2045 .get(&(block_idx.to_idx(), index.to_idx()))
2046 .unwrap(),
2047 Operand::Constant(const_value, ty) => lower_constant(ctx, const_value, *ty),
2048 Operand::BlockArgument { block_idx, nth, .. } => {
2049 ctx.block_args.get(block_idx).unwrap()[*nth]
2050 }
2051 Operand::Global(global_idx, _ty) => *ctx
2052 .globals
2053 .get(&global_idx.to_idx())
2054 .expect("global not found"),
2055 }
2056 }
2057}
2058
2059fn lower_constant(ctx: &FnCtx, value: &ConstValue, ty: TypeIdx) -> LLVMValueRef {
2060 unsafe {
2061 let ty_ptr = lower_type(ctx.ctx, ctx.storage, ty);
2062
2063 match value {
2064 irvm::value::ConstValue::Int(value) => core::LLVMConstInt(ty_ptr, *value, 0_i32),
2065 irvm::value::ConstValue::Float(value) => core::LLVMConstReal(ty_ptr, *value),
2066 irvm::value::ConstValue::Array(const_values) => {
2067 let mut values = Vec::new();
2068 let array_ty = if let Type::Array(array_ty) = &ctx.storage.get_type_info(ty).ty {
2069 array_ty
2070 } else {
2071 panic!("type mismatch")
2072 };
2073
2074 let typtr = lower_type(ctx.ctx, ctx.storage, array_ty.ty);
2075
2076 for value in const_values {
2077 let ptr = lower_constant(ctx, value, array_ty.ty);
2078 values.push(ptr);
2079 }
2080
2081 core::LLVMConstArray2(typtr, values.as_mut_ptr(), values.len() as u64)
2082 }
2083 irvm::value::ConstValue::Vector(const_values) => {
2084 let mut values = Vec::new();
2085 let vec_ty = if let Type::Vector(vec_ty) = &ctx.storage.get_type_info(ty).ty {
2086 vec_ty
2087 } else {
2088 panic!("type mismatch")
2089 };
2090
2091 for value in const_values {
2092 let ptr = lower_constant(ctx, value, vec_ty.ty);
2093 values.push(ptr);
2094 }
2095
2096 core::LLVMConstVector(values.as_mut_ptr(), values.len() as u32)
2097 }
2098 irvm::value::ConstValue::Struct(const_values) => {
2099 let mut const_fields = Vec::new();
2100 let struct_ty = if let Type::Struct(struct_ty) = &ctx.storage.get_type_info(ty).ty {
2101 &**struct_ty
2102 } else {
2103 panic!("type mismatch")
2104 };
2105 for (value, field) in const_values.iter().zip(struct_ty.fields.iter()) {
2106 let ptr = lower_constant(ctx, value, *field);
2107 const_fields.push(ptr);
2108 }
2109 core::LLVMConstStructInContext(
2110 ctx.ctx,
2111 const_fields.as_mut_ptr(),
2112 const_fields.len() as u32,
2113 struct_ty.packed as i32,
2114 )
2115 }
2116 irvm::value::ConstValue::NullPtr => core::LLVMConstPointerNull(ty_ptr),
2117 irvm::value::ConstValue::Undef => core::LLVMGetUndef(ty_ptr),
2118 irvm::value::ConstValue::Poison => core::LLVMGetPoison(ty_ptr),
2119 }
2120 }
2121}
2122
2123fn lower_type(ctx: LLVMContextRef, storage: &TypeStorage, ty: TypeIdx) -> LLVMTypeRef {
2124 let tyinfo = storage.get_type_info(ty);
2125 unsafe {
2126 match &tyinfo.ty {
2127 Type::Int(width) => core::LLVMIntTypeInContext(ctx, *width),
2128 Type::Half => core::LLVMHalfTypeInContext(ctx),
2129 Type::BFloat => core::LLVMBFloatTypeInContext(ctx),
2130 Type::Float => core::LLVMFloatTypeInContext(ctx),
2131 Type::Double => core::LLVMDoubleTypeInContext(ctx),
2132 Type::Fp128 => core::LLVMFP128TypeInContext(ctx),
2133 Type::X86Fp80 => core::LLVMX86FP80TypeInContext(ctx),
2134 Type::PpcFp128 => core::LLVMPPCFP128TypeInContext(ctx),
2135 Type::Ptr {
2136 pointee: _,
2137 address_space,
2138 } => core::LLVMPointerTypeInContext(ctx, address_space.unwrap_or(0)),
2139 Type::Vector(vector_type) => {
2140 let inner = lower_type(ctx, storage, vector_type.ty);
2141 core::LLVMVectorType(inner, vector_type.size)
2142 }
2143 Type::Array(array_type) => {
2144 let inner = lower_type(ctx, storage, array_type.ty);
2145 core::LLVMArrayType2(inner, array_type.size)
2146 }
2147 Type::Struct(struct_type) => {
2148 let mut fields = Vec::new();
2149
2150 for field in struct_type.fields.iter() {
2151 fields.push(lower_type(ctx, storage, *field));
2152 }
2153
2154 if let Some(ident) = &struct_type.ident {
2155 let name = CString::new(ident.as_str()).unwrap();
2156 let ptr = core::LLVMStructCreateNamed(ctx, name.as_ptr());
2157
2158 core::LLVMStructSetBody(
2159 ptr,
2160 fields.as_mut_ptr(),
2161 fields.len() as u32,
2162 struct_type.packed as i32,
2163 );
2164
2165 ptr
2166 } else {
2167 core::LLVMStructTypeInContext(
2168 ctx,
2169 fields.as_mut_ptr(),
2170 fields.len() as u32,
2171 struct_type.packed as i32,
2172 )
2173 }
2174 }
2175 }
2176 }
2177}
2178
2179fn lower_debug_type(
2180 datalayout: &DataLayout,
2181 builder: LLVMDIBuilderRef,
2182 storage: &TypeStorage,
2183 module_scope: LLVMMetadataRef,
2184 type_idx: TypeIdx,
2185) -> LLVMMetadataRef {
2186 let ty = storage.get_type_info(type_idx);
2187
2188 let size_in_bits = datalayout.get_type_size(storage, type_idx);
2196 let align_in_bits = datalayout.get_type_align(storage, type_idx);
2197
2198 if let Some(debug_info) = &ty.debug_info {
2199 let name = CString::new(debug_info.name.clone()).unwrap();
2200 unsafe {
2201 match &ty.ty {
2202 Type::Int(width) => {
2203 let mut encoding = DW_ATE_unsigned;
2204 if *width == 1 {
2205 encoding = DW_ATE_boolean;
2206 }
2207 debuginfo::LLVMDIBuilderCreateBasicType(
2208 builder,
2209 name.as_ptr(),
2210 name.count_bytes(),
2211 size_in_bits as u64,
2212 encoding.0 as u32,
2213 LLVMDIFlagPublic,
2214 )
2215 }
2216 Type::Half
2217 | Type::BFloat
2218 | Type::Float
2219 | Type::Double
2220 | Type::Fp128
2221 | Type::X86Fp80
2222 | Type::PpcFp128 => debuginfo::LLVMDIBuilderCreateBasicType(
2223 builder,
2224 name.as_ptr(),
2225 name.count_bytes(),
2226 size_in_bits as u64,
2227 0x4,
2228 LLVMDIFlagPublic,
2229 ),
2230 Type::Ptr {
2231 pointee,
2232 address_space,
2233 } => {
2234 let pointee_ptr =
2235 lower_debug_type(datalayout, builder, storage, module_scope, *pointee);
2236
2237 if debug_info.is_reference {
2238 debuginfo::LLVMDIBuilderCreateReferenceType(
2239 builder,
2240 DW_TAG_reference_type.0 as u32,
2241 pointee_ptr,
2242 )
2243 } else {
2244 debuginfo::LLVMDIBuilderCreatePointerType(
2245 builder,
2246 pointee_ptr,
2247 size_in_bits as u64,
2248 align_in_bits,
2249 address_space.unwrap_or(0),
2250 name.as_ptr(),
2251 name.count_bytes(),
2252 )
2253 }
2254 }
2255 Type::Vector(vector_type) => {
2256 let inner_ty_ptr = lower_debug_type(
2257 datalayout,
2258 builder,
2259 storage,
2260 module_scope,
2261 vector_type.ty,
2262 );
2263 let size = datalayout.get_type_size(storage, type_idx);
2264 let align = datalayout.get_type_align(storage, type_idx);
2265 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
2266 builder,
2267 0,
2268 vector_type.size as i64,
2269 );
2270 debuginfo::LLVMDIBuilderCreateVectorType(
2271 builder,
2272 size as u64,
2273 align,
2274 inner_ty_ptr,
2275 &raw mut subrange,
2276 1,
2277 )
2278 }
2279 Type::Array(array_type) => {
2280 let inner_ty_ptr =
2281 lower_debug_type(datalayout, builder, storage, module_scope, array_type.ty);
2282 let size = datalayout.get_type_size(storage, type_idx);
2283 let align = datalayout.get_type_align(storage, type_idx);
2284 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
2285 builder,
2286 0,
2287 array_type.size as i64,
2288 );
2289 debuginfo::LLVMDIBuilderCreateArrayType(
2290 builder,
2291 size as u64,
2292 align,
2293 inner_ty_ptr,
2294 &raw mut subrange,
2295 1,
2296 )
2297 }
2298 Type::Struct(struct_type) => {
2299 let mut fields = Vec::with_capacity(struct_type.fields.len());
2300
2301 let difile = get_difile_location(builder, &debug_info.location);
2302 let line = debug_info.location.get_line();
2303
2304 let mut offset = 0;
2305 let mut cur_align = 8;
2306
2307 for (i, field) in struct_type.fields.iter().enumerate() {
2308 let field_align = datalayout.get_type_align(storage, *field);
2309 cur_align = cur_align.max(field_align);
2310
2311 if offset % field_align != 0 {
2312 let padding = (field_align - (offset % field_align)) % field_align;
2313 offset += padding;
2314 }
2315
2316 let field_size = datalayout.get_type_size(storage, *field);
2317
2318 let mut ty =
2319 lower_debug_type(datalayout, builder, storage, module_scope, *field);
2320
2321 if let Some((field_name, location)) = struct_type.debug_field_names.get(i) {
2322 let name = CString::new(field_name.clone()).unwrap();
2323 let difile = get_difile_location(builder, location);
2324 let line = location.get_line().unwrap_or(0);
2325 let size = datalayout.get_type_size(storage, *field);
2326 let align = datalayout.get_type_align(storage, *field);
2327 ty = debuginfo::LLVMDIBuilderCreateMemberType(
2328 builder,
2329 module_scope,
2330 name.as_ptr(),
2331 name.count_bytes(),
2332 difile,
2333 line,
2334 size as u64,
2335 align,
2336 offset as u64,
2337 0,
2338 ty,
2339 );
2340 }
2341
2342 offset += field_size;
2343
2344 fields.push(ty);
2345 }
2346
2347 let size = datalayout.get_type_size(storage, type_idx);
2348 let align = datalayout.get_type_align(storage, type_idx);
2349
2350 debuginfo::LLVMDIBuilderCreateStructType(
2351 builder,
2352 module_scope,
2353 name.as_ptr(),
2354 name.count_bytes(),
2355 difile,
2356 line.unwrap_or(0),
2357 size as u64,
2358 align,
2359 0,
2360 null_mut(),
2361 fields.as_mut_ptr(),
2362 fields.len() as u32,
2363 0,
2364 null_mut(),
2365 name.as_ptr(),
2366 name.count_bytes(),
2367 )
2368 }
2369 }
2370 }
2371 } else {
2372 unsafe {
2374 match &ty.ty {
2375 Type::Int(width) => {
2376 let name = CString::new(format!("i{}", width)).unwrap();
2377 let encoding = if *width == 1 {
2378 DW_ATE_boolean
2379 } else {
2380 DW_ATE_unsigned
2381 };
2382 debuginfo::LLVMDIBuilderCreateBasicType(
2383 builder,
2384 name.as_ptr(),
2385 name.count_bytes(),
2386 size_in_bits as u64,
2387 encoding.0 as u32,
2388 LLVMDIFlagPublic,
2389 )
2390 }
2391 Type::Half
2392 | Type::BFloat
2393 | Type::Float
2394 | Type::Double
2395 | Type::Fp128
2396 | Type::X86Fp80
2397 | Type::PpcFp128 => {
2398 let name = CString::new(format!("f{}", size_in_bits)).unwrap();
2399 debuginfo::LLVMDIBuilderCreateBasicType(
2400 builder,
2401 name.as_ptr(),
2402 name.count_bytes(),
2403 size_in_bits as u64,
2404 DW_ATE_float.0 as u32,
2405 LLVMDIFlagPublic,
2406 )
2407 }
2408 Type::Ptr {
2409 pointee,
2410 address_space,
2411 } => {
2412 let pointee_ptr =
2413 lower_debug_type(datalayout, builder, storage, module_scope, *pointee);
2414 let name = CString::new("ptr").unwrap();
2415 debuginfo::LLVMDIBuilderCreatePointerType(
2416 builder,
2417 pointee_ptr,
2418 size_in_bits as u64,
2419 align_in_bits,
2420 address_space.unwrap_or(0),
2421 name.as_ptr(),
2422 name.count_bytes(),
2423 )
2424 }
2425 Type::Vector(vector_type) => {
2426 let inner_ty_ptr = lower_debug_type(
2427 datalayout,
2428 builder,
2429 storage,
2430 module_scope,
2431 vector_type.ty,
2432 );
2433 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
2434 builder,
2435 0,
2436 vector_type.size as i64,
2437 );
2438 debuginfo::LLVMDIBuilderCreateVectorType(
2439 builder,
2440 size_in_bits as u64,
2441 align_in_bits,
2442 inner_ty_ptr,
2443 &raw mut subrange,
2444 1,
2445 )
2446 }
2447 Type::Array(array_type) => {
2448 let inner_ty_ptr =
2449 lower_debug_type(datalayout, builder, storage, module_scope, array_type.ty);
2450 let mut subrange = debuginfo::LLVMDIBuilderGetOrCreateSubrange(
2451 builder,
2452 0,
2453 array_type.size as i64,
2454 );
2455 debuginfo::LLVMDIBuilderCreateArrayType(
2456 builder,
2457 size_in_bits as u64,
2458 align_in_bits,
2459 inner_ty_ptr,
2460 &raw mut subrange,
2461 1,
2462 )
2463 }
2464 Type::Struct(struct_type) => {
2465 let mut fields = Vec::with_capacity(struct_type.fields.len());
2466 let mut offset = 0;
2467
2468 for field in struct_type.fields.iter() {
2469 let field_align = datalayout.get_type_align(storage, *field);
2470 if offset % field_align != 0 {
2471 offset += (field_align - (offset % field_align)) % field_align;
2472 }
2473 let ty =
2474 lower_debug_type(datalayout, builder, storage, module_scope, *field);
2475 let field_size = datalayout.get_type_size(storage, *field);
2476 offset += field_size;
2477 fields.push(ty);
2478 }
2479
2480 let name = CString::new("struct").unwrap();
2481 debuginfo::LLVMDIBuilderCreateStructType(
2482 builder,
2483 module_scope,
2484 name.as_ptr(),
2485 name.count_bytes(),
2486 null_mut(),
2487 0,
2488 size_in_bits as u64,
2489 align_in_bits,
2490 0,
2491 null_mut(),
2492 fields.as_mut_ptr(),
2493 fields.len() as u32,
2494 0,
2495 null_mut(),
2496 name.as_ptr(),
2497 name.count_bytes(),
2498 )
2499 }
2500 }
2501 }
2502 }
2503}
2504
2505fn lower_global_constant(
2507 ctx: LLVMContextRef,
2508 storage: &TypeStorage,
2509 value: &ConstValue,
2510 ty: TypeIdx,
2511) -> LLVMValueRef {
2512 unsafe {
2513 let ty_ptr = lower_type(ctx, storage, ty);
2514
2515 match value {
2516 ConstValue::Int(value) => core::LLVMConstInt(ty_ptr, *value, 0_i32),
2517 ConstValue::Float(value) => core::LLVMConstReal(ty_ptr, *value),
2518 ConstValue::Array(const_values) => {
2519 let array_ty = if let Type::Array(array_ty) = &storage.get_type_info(ty).ty {
2520 array_ty
2521 } else {
2522 panic!("type mismatch")
2523 };
2524
2525 let typtr = lower_type(ctx, storage, array_ty.ty);
2526 let mut values: Vec<_> = const_values
2527 .iter()
2528 .map(|v| lower_global_constant(ctx, storage, v, array_ty.ty))
2529 .collect();
2530
2531 core::LLVMConstArray2(typtr, values.as_mut_ptr(), values.len() as u64)
2532 }
2533 ConstValue::Vector(const_values) => {
2534 let vec_ty = if let Type::Vector(vec_ty) = &storage.get_type_info(ty).ty {
2535 vec_ty
2536 } else {
2537 panic!("type mismatch")
2538 };
2539
2540 let mut values: Vec<_> = const_values
2541 .iter()
2542 .map(|v| lower_global_constant(ctx, storage, v, vec_ty.ty))
2543 .collect();
2544
2545 core::LLVMConstVector(values.as_mut_ptr(), values.len() as u32)
2546 }
2547 ConstValue::Struct(const_values) => {
2548 let struct_ty = if let Type::Struct(struct_ty) = &storage.get_type_info(ty).ty {
2549 &**struct_ty
2550 } else {
2551 panic!("type mismatch")
2552 };
2553 let mut const_fields: Vec<_> = const_values
2554 .iter()
2555 .zip(struct_ty.fields.iter())
2556 .map(|(v, field)| lower_global_constant(ctx, storage, v, *field))
2557 .collect();
2558 core::LLVMConstStructInContext(
2559 ctx,
2560 const_fields.as_mut_ptr(),
2561 const_fields.len() as u32,
2562 struct_ty.packed as i32,
2563 )
2564 }
2565 ConstValue::NullPtr => core::LLVMConstPointerNull(ty_ptr),
2566 ConstValue::Undef => core::LLVMGetUndef(ty_ptr),
2567 ConstValue::Poison => core::LLVMGetPoison(ty_ptr),
2568 }
2569 }
2570}
2571
2572fn lower_linkage(linkage: &Linkage) -> llvm_sys::LLVMLinkage {
2573 match linkage {
2574 Linkage::Private => llvm_sys::LLVMLinkage::LLVMPrivateLinkage,
2575 Linkage::Internal => llvm_sys::LLVMLinkage::LLVMInternalLinkage,
2576 Linkage::AvailableExternally => llvm_sys::LLVMLinkage::LLVMAvailableExternallyLinkage,
2577 Linkage::LinkOnce => llvm_sys::LLVMLinkage::LLVMLinkOnceAnyLinkage,
2578 Linkage::Weak => llvm_sys::LLVMLinkage::LLVMWeakAnyLinkage,
2579 Linkage::Common => llvm_sys::LLVMLinkage::LLVMCommonLinkage,
2580 Linkage::Appending => llvm_sys::LLVMLinkage::LLVMAppendingLinkage,
2581 Linkage::ExternWeak => llvm_sys::LLVMLinkage::LLVMExternalWeakLinkage,
2582 Linkage::LinkOnceOdr => llvm_sys::LLVMLinkage::LLVMLinkOnceODRLinkage,
2583 Linkage::WeakOdr => llvm_sys::LLVMLinkage::LLVMWeakODRLinkage,
2584 Linkage::External => llvm_sys::LLVMLinkage::LLVMExternalLinkage,
2585 }
2586}
2587
2588fn lower_atomic_ordering(ordering: &AtomicOrdering) -> llvm_sys::LLVMAtomicOrdering {
2589 match ordering {
2590 AtomicOrdering::Unordered => llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingUnordered,
2591 AtomicOrdering::Monotonic => llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingMonotonic,
2592 AtomicOrdering::Acquire => llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingAcquire,
2593 AtomicOrdering::Release => llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingRelease,
2594 AtomicOrdering::AcqRel => llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingAcquireRelease,
2595 AtomicOrdering::SeqCst => {
2596 llvm_sys::LLVMAtomicOrdering::LLVMAtomicOrderingSequentiallyConsistent
2597 }
2598 }
2599}
2600
2601fn lower_atomic_rmw_op(op: &AtomicRMWOp) -> llvm_sys::LLVMAtomicRMWBinOp {
2602 match op {
2603 AtomicRMWOp::Xchg => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXchg,
2604 AtomicRMWOp::Add => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd,
2605 AtomicRMWOp::Sub => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub,
2606 AtomicRMWOp::And => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAnd,
2607 AtomicRMWOp::Nand => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpNand,
2608 AtomicRMWOp::Or => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpOr,
2609 AtomicRMWOp::Xor => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXor,
2610 AtomicRMWOp::Max => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMax,
2611 AtomicRMWOp::Min => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMin,
2612 AtomicRMWOp::UMax => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMax,
2613 AtomicRMWOp::UMin => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMin,
2614 AtomicRMWOp::FAdd => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFAdd,
2615 AtomicRMWOp::FSub => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFSub,
2616 AtomicRMWOp::FMax => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMax,
2617 AtomicRMWOp::FMin => llvm_sys::LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMin,
2618 }
2619}
2620
2621fn apply_fast_math_flags(value: LLVMValueRef, flags: &FastMathFlags) {
2622 if !flags.any() {
2623 return;
2624 }
2625
2626 let mut llvm_flags = llvm_sys::LLVMFastMathNone;
2627 if flags.reassoc {
2628 llvm_flags |= llvm_sys::LLVMFastMathAllowReassoc;
2629 }
2630 if flags.nnan {
2631 llvm_flags |= llvm_sys::LLVMFastMathNoNaNs;
2632 }
2633 if flags.ninf {
2634 llvm_flags |= llvm_sys::LLVMFastMathNoInfs;
2635 }
2636 if flags.nsz {
2637 llvm_flags |= llvm_sys::LLVMFastMathNoSignedZeros;
2638 }
2639 if flags.arcp {
2640 llvm_flags |= llvm_sys::LLVMFastMathAllowReciprocal;
2641 }
2642 if flags.contract {
2643 llvm_flags |= llvm_sys::LLVMFastMathAllowContract;
2644 }
2645 if flags.afn {
2646 llvm_flags |= llvm_sys::LLVMFastMathApproxFunc;
2647 }
2648
2649 unsafe {
2650 core::LLVMSetFastMathFlags(value, llvm_flags);
2651 }
2652}
2653
2654fn apply_function_attrs(
2656 ctx: LLVMContextRef,
2657 fn_ptr: LLVMValueRef,
2658 attrs: &irvm::function::FunctionAttrs,
2659) {
2660 const FUNCTION_INDEX: u32 = !0;
2662
2663 unsafe {
2664 let add_attr = |name: &[u8]| {
2666 let kind = core::LLVMGetEnumAttributeKindForName(name.as_ptr().cast(), name.len());
2667 if kind != 0 {
2668 let attr = core::LLVMCreateEnumAttribute(ctx, kind, 0);
2669 core::LLVMAddAttributeAtIndex(fn_ptr, FUNCTION_INDEX, attr);
2670 }
2671 };
2672
2673 if attrs.nounwind {
2674 add_attr(b"nounwind");
2675 }
2676 if attrs.noreturn {
2677 add_attr(b"noreturn");
2678 }
2679 if attrs.cold {
2680 add_attr(b"cold");
2681 }
2682 if attrs.hot {
2683 add_attr(b"hot");
2684 }
2685 if attrs.willreturn {
2686 add_attr(b"willreturn");
2687 }
2688 if attrs.nosync {
2689 add_attr(b"nosync");
2690 }
2691 if attrs.nofree {
2692 add_attr(b"nofree");
2693 }
2694 if attrs.norecurse {
2695 add_attr(b"norecurse");
2696 }
2697 if attrs.readnone {
2698 add_attr(b"readnone");
2699 }
2700 if attrs.readonly {
2701 add_attr(b"readonly");
2702 }
2703 if attrs.writeonly {
2704 add_attr(b"writeonly");
2705 }
2706 if attrs.inlinehint {
2707 add_attr(b"inlinehint");
2708 }
2709 if attrs.alwaysinline {
2710 add_attr(b"alwaysinline");
2711 }
2712 if attrs.noinline {
2713 add_attr(b"noinline");
2714 }
2715 if attrs.minsize {
2716 add_attr(b"minsize");
2717 }
2718 if attrs.optsize {
2719 add_attr(b"optsize");
2720 }
2721 }
2722}
2723
2724fn apply_parameter_attrs(
2726 ctx: LLVMContextRef,
2727 fn_ptr: LLVMValueRef,
2728 params: &[irvm::function::Parameter],
2729) {
2730 unsafe {
2731 for (idx, param) in params.iter().enumerate() {
2732 let param_index = (idx + 1) as u32;
2734
2735 let add_attr = |name: &[u8]| {
2737 let kind = core::LLVMGetEnumAttributeKindForName(name.as_ptr().cast(), name.len());
2738 if kind != 0 {
2739 let attr = core::LLVMCreateEnumAttribute(ctx, kind, 0);
2740 core::LLVMAddAttributeAtIndex(fn_ptr, param_index, attr);
2741 }
2742 };
2743
2744 if param.nocapture {
2745 add_attr(b"nocapture");
2746 }
2747 if param.readonly {
2748 add_attr(b"readonly");
2749 }
2750 if param.writeonly {
2751 add_attr(b"writeonly");
2752 }
2753 if param.noalias {
2754 add_attr(b"noalias");
2755 }
2756 if param.noundef {
2757 add_attr(b"noundef");
2758 }
2759 if param.nonnull {
2760 add_attr(b"nonnull");
2761 }
2762 if param.nofree {
2763 add_attr(b"nofree");
2764 }
2765 if param.nest {
2766 add_attr(b"nest");
2767 }
2768 if param.returned {
2769 add_attr(b"returned");
2770 }
2771 if param.inreg {
2772 add_attr(b"inreg");
2773 }
2774 if param.zeroext {
2775 add_attr(b"zeroext");
2776 }
2777 if param.signext {
2778 add_attr(b"signext");
2779 }
2780
2781 if let Some(deref) = param.dereferenceable {
2783 let kind = core::LLVMGetEnumAttributeKindForName(
2784 b"dereferenceable".as_ptr().cast(),
2785 b"dereferenceable".len(),
2786 );
2787 if kind != 0 {
2788 let attr = core::LLVMCreateEnumAttribute(ctx, kind, deref as u64);
2789 core::LLVMAddAttributeAtIndex(fn_ptr, param_index, attr);
2790 }
2791 }
2792
2793 if let Some(align) = param.align {
2795 let kind =
2796 core::LLVMGetEnumAttributeKindForName(b"align".as_ptr().cast(), b"align".len());
2797 if kind != 0 {
2798 let attr = core::LLVMCreateEnumAttribute(ctx, kind, align as u64);
2799 core::LLVMAddAttributeAtIndex(fn_ptr, param_index, attr);
2800 }
2801 }
2802 }
2803 }
2804}
2805
2806fn apply_return_attrs(
2808 ctx: LLVMContextRef,
2809 fn_ptr: LLVMValueRef,
2810 attrs: &irvm::function::ReturnAttrs,
2811) {
2812 const RETURN_INDEX: u32 = 0;
2814
2815 unsafe {
2816 let add_attr = |name: &[u8]| {
2817 let kind = core::LLVMGetEnumAttributeKindForName(name.as_ptr().cast(), name.len());
2818 if kind != 0 {
2819 let attr = core::LLVMCreateEnumAttribute(ctx, kind, 0);
2820 core::LLVMAddAttributeAtIndex(fn_ptr, RETURN_INDEX, attr);
2821 }
2822 };
2823
2824 if attrs.noalias {
2825 add_attr(b"noalias");
2826 }
2827 if attrs.noundef {
2828 add_attr(b"noundef");
2829 }
2830 if attrs.nonnull {
2831 add_attr(b"nonnull");
2832 }
2833
2834 if let Some(deref) = attrs.dereferenceable {
2836 let kind = core::LLVMGetEnumAttributeKindForName(
2837 b"dereferenceable".as_ptr().cast(),
2838 b"dereferenceable".len(),
2839 );
2840 if kind != 0 {
2841 let attr = core::LLVMCreateEnumAttribute(ctx, kind, deref as u64);
2842 core::LLVMAddAttributeAtIndex(fn_ptr, RETURN_INDEX, attr);
2843 }
2844 }
2845 }
2846}
2847
2848unsafe fn lower_intrinsic(
2850 ctx: &FnCtx,
2851 intrinsic: &irvm::block::Intrinsic,
2852 _block_idx: BlockIdx,
2853 _inst_idx: irvm::block::InstIdx,
2854) -> Result<LLVMValueRef, Error> {
2855 use irvm::block::Intrinsic;
2856
2857 unsafe {
2858 let null_name = c"";
2859 let module = core::LLVMGetGlobalParent(ctx.fn_ptr);
2860
2861 match intrinsic {
2862 Intrinsic::Memcpy {
2864 dest,
2865 src,
2866 len,
2867 is_volatile: _,
2868 } => {
2869 let dest_val = lower_operand(ctx, dest);
2870 let src_val = lower_operand(ctx, src);
2871 let len_val = lower_operand(ctx, len);
2872 core::LLVMBuildMemCpy(
2873 ctx.builder,
2874 dest_val,
2875 1, src_val,
2877 1, len_val,
2879 );
2880 Ok(null_mut())
2881 }
2882 Intrinsic::Memset {
2883 dest,
2884 val,
2885 len,
2886 is_volatile: _,
2887 } => {
2888 let dest_val = lower_operand(ctx, dest);
2889 let val_val = lower_operand(ctx, val);
2890 let len_val = lower_operand(ctx, len);
2891 core::LLVMBuildMemSet(
2892 ctx.builder,
2893 dest_val,
2894 val_val,
2895 len_val,
2896 1, );
2898 Ok(null_mut())
2899 }
2900 Intrinsic::Memmove {
2901 dest,
2902 src,
2903 len,
2904 is_volatile: _,
2905 } => {
2906 let dest_val = lower_operand(ctx, dest);
2907 let src_val = lower_operand(ctx, src);
2908 let len_val = lower_operand(ctx, len);
2909 core::LLVMBuildMemMove(
2910 ctx.builder,
2911 dest_val,
2912 1, src_val,
2914 1, len_val,
2916 );
2917 Ok(null_mut())
2918 }
2919
2920 Intrinsic::SaddWithOverflow {
2922 lhs,
2923 rhs,
2924 result_ty: _,
2925 } => {
2926 let lhs_val = lower_operand(ctx, lhs);
2927 let rhs_val = lower_operand(ctx, rhs);
2928 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
2929 let intrinsic_name = CString::new(format!(
2930 "llvm.sadd.with.overflow.i{}",
2931 core::LLVMGetIntTypeWidth(lhs_ty)
2932 ))
2933 .unwrap();
2934 let intrinsic_id = core::LLVMLookupIntrinsicID(
2935 intrinsic_name.as_ptr(),
2936 intrinsic_name.to_bytes().len(),
2937 );
2938 let mut param_types = [lhs_ty];
2939 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
2940 module,
2941 intrinsic_id,
2942 param_types.as_mut_ptr(),
2943 param_types.len(),
2944 );
2945 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
2946 let mut args = [lhs_val, rhs_val];
2947 let value = core::LLVMBuildCall2(
2948 ctx.builder,
2949 fn_ty,
2950 intrinsic_fn,
2951 args.as_mut_ptr(),
2952 args.len() as u32,
2953 null_name.as_ptr(),
2954 );
2955 Ok(value)
2956 }
2957 Intrinsic::UaddWithOverflow {
2958 lhs,
2959 rhs,
2960 result_ty: _,
2961 } => {
2962 let lhs_val = lower_operand(ctx, lhs);
2963 let rhs_val = lower_operand(ctx, rhs);
2964 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
2965 let intrinsic_name = CString::new(format!(
2966 "llvm.uadd.with.overflow.i{}",
2967 core::LLVMGetIntTypeWidth(lhs_ty)
2968 ))
2969 .unwrap();
2970 let intrinsic_id = core::LLVMLookupIntrinsicID(
2971 intrinsic_name.as_ptr(),
2972 intrinsic_name.to_bytes().len(),
2973 );
2974 let mut param_types = [lhs_ty];
2975 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
2976 module,
2977 intrinsic_id,
2978 param_types.as_mut_ptr(),
2979 param_types.len(),
2980 );
2981 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
2982 let mut args = [lhs_val, rhs_val];
2983 let value = core::LLVMBuildCall2(
2984 ctx.builder,
2985 fn_ty,
2986 intrinsic_fn,
2987 args.as_mut_ptr(),
2988 args.len() as u32,
2989 null_name.as_ptr(),
2990 );
2991 Ok(value)
2992 }
2993 Intrinsic::SsubWithOverflow {
2994 lhs,
2995 rhs,
2996 result_ty: _,
2997 } => {
2998 let lhs_val = lower_operand(ctx, lhs);
2999 let rhs_val = lower_operand(ctx, rhs);
3000 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
3001 let intrinsic_name = CString::new(format!(
3002 "llvm.ssub.with.overflow.i{}",
3003 core::LLVMGetIntTypeWidth(lhs_ty)
3004 ))
3005 .unwrap();
3006 let intrinsic_id = core::LLVMLookupIntrinsicID(
3007 intrinsic_name.as_ptr(),
3008 intrinsic_name.to_bytes().len(),
3009 );
3010 let mut param_types = [lhs_ty];
3011 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3012 module,
3013 intrinsic_id,
3014 param_types.as_mut_ptr(),
3015 param_types.len(),
3016 );
3017 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3018 let mut args = [lhs_val, rhs_val];
3019 let value = core::LLVMBuildCall2(
3020 ctx.builder,
3021 fn_ty,
3022 intrinsic_fn,
3023 args.as_mut_ptr(),
3024 args.len() as u32,
3025 null_name.as_ptr(),
3026 );
3027 Ok(value)
3028 }
3029 Intrinsic::UsubWithOverflow {
3030 lhs,
3031 rhs,
3032 result_ty: _,
3033 } => {
3034 let lhs_val = lower_operand(ctx, lhs);
3035 let rhs_val = lower_operand(ctx, rhs);
3036 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
3037 let intrinsic_name = CString::new(format!(
3038 "llvm.usub.with.overflow.i{}",
3039 core::LLVMGetIntTypeWidth(lhs_ty)
3040 ))
3041 .unwrap();
3042 let intrinsic_id = core::LLVMLookupIntrinsicID(
3043 intrinsic_name.as_ptr(),
3044 intrinsic_name.to_bytes().len(),
3045 );
3046 let mut param_types = [lhs_ty];
3047 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3048 module,
3049 intrinsic_id,
3050 param_types.as_mut_ptr(),
3051 param_types.len(),
3052 );
3053 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3054 let mut args = [lhs_val, rhs_val];
3055 let value = core::LLVMBuildCall2(
3056 ctx.builder,
3057 fn_ty,
3058 intrinsic_fn,
3059 args.as_mut_ptr(),
3060 args.len() as u32,
3061 null_name.as_ptr(),
3062 );
3063 Ok(value)
3064 }
3065 Intrinsic::SmulWithOverflow {
3066 lhs,
3067 rhs,
3068 result_ty: _,
3069 } => {
3070 let lhs_val = lower_operand(ctx, lhs);
3071 let rhs_val = lower_operand(ctx, rhs);
3072 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
3073 let intrinsic_name = CString::new(format!(
3074 "llvm.smul.with.overflow.i{}",
3075 core::LLVMGetIntTypeWidth(lhs_ty)
3076 ))
3077 .unwrap();
3078 let intrinsic_id = core::LLVMLookupIntrinsicID(
3079 intrinsic_name.as_ptr(),
3080 intrinsic_name.to_bytes().len(),
3081 );
3082 let mut param_types = [lhs_ty];
3083 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3084 module,
3085 intrinsic_id,
3086 param_types.as_mut_ptr(),
3087 param_types.len(),
3088 );
3089 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3090 let mut args = [lhs_val, rhs_val];
3091 let value = core::LLVMBuildCall2(
3092 ctx.builder,
3093 fn_ty,
3094 intrinsic_fn,
3095 args.as_mut_ptr(),
3096 args.len() as u32,
3097 null_name.as_ptr(),
3098 );
3099 Ok(value)
3100 }
3101 Intrinsic::UmulWithOverflow {
3102 lhs,
3103 rhs,
3104 result_ty: _,
3105 } => {
3106 let lhs_val = lower_operand(ctx, lhs);
3107 let rhs_val = lower_operand(ctx, rhs);
3108 let lhs_ty = lower_type(ctx.ctx, ctx.storage, lhs.get_type());
3109 let intrinsic_name = CString::new(format!(
3110 "llvm.umul.with.overflow.i{}",
3111 core::LLVMGetIntTypeWidth(lhs_ty)
3112 ))
3113 .unwrap();
3114 let intrinsic_id = core::LLVMLookupIntrinsicID(
3115 intrinsic_name.as_ptr(),
3116 intrinsic_name.to_bytes().len(),
3117 );
3118 let mut param_types = [lhs_ty];
3119 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3120 module,
3121 intrinsic_id,
3122 param_types.as_mut_ptr(),
3123 param_types.len(),
3124 );
3125 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3126 let mut args = [lhs_val, rhs_val];
3127 let value = core::LLVMBuildCall2(
3128 ctx.builder,
3129 fn_ty,
3130 intrinsic_fn,
3131 args.as_mut_ptr(),
3132 args.len() as u32,
3133 null_name.as_ptr(),
3134 );
3135 Ok(value)
3136 }
3137
3138 Intrinsic::Sqrt { value } => {
3140 lower_unary_float_intrinsic(ctx, module, "llvm.sqrt", value)
3141 }
3142 Intrinsic::Sin { value } => lower_unary_float_intrinsic(ctx, module, "llvm.sin", value),
3143 Intrinsic::Cos { value } => lower_unary_float_intrinsic(ctx, module, "llvm.cos", value),
3144 Intrinsic::Exp { value } => lower_unary_float_intrinsic(ctx, module, "llvm.exp", value),
3145 Intrinsic::Exp2 { value } => {
3146 lower_unary_float_intrinsic(ctx, module, "llvm.exp2", value)
3147 }
3148 Intrinsic::Log { value } => lower_unary_float_intrinsic(ctx, module, "llvm.log", value),
3149 Intrinsic::Log2 { value } => {
3150 lower_unary_float_intrinsic(ctx, module, "llvm.log2", value)
3151 }
3152 Intrinsic::Log10 { value } => {
3153 lower_unary_float_intrinsic(ctx, module, "llvm.log10", value)
3154 }
3155 Intrinsic::Fabs { value } => {
3156 lower_unary_float_intrinsic(ctx, module, "llvm.fabs", value)
3157 }
3158 Intrinsic::Floor { value } => {
3159 lower_unary_float_intrinsic(ctx, module, "llvm.floor", value)
3160 }
3161 Intrinsic::Ceil { value } => {
3162 lower_unary_float_intrinsic(ctx, module, "llvm.ceil", value)
3163 }
3164 Intrinsic::Trunc { value } => {
3165 lower_unary_float_intrinsic(ctx, module, "llvm.trunc", value)
3166 }
3167 Intrinsic::Round { value } => {
3168 lower_unary_float_intrinsic(ctx, module, "llvm.round", value)
3169 }
3170
3171 Intrinsic::Pow { base, exp } => {
3173 lower_binary_float_intrinsic(ctx, module, "llvm.pow", base, exp)
3174 }
3175 Intrinsic::Powi { base, exp } => {
3176 let base_val = lower_operand(ctx, base);
3178 let exp_val = lower_operand(ctx, exp);
3179 let base_ty = lower_type(ctx.ctx, ctx.storage, base.get_type());
3180 let ty_name = get_float_type_suffix(base_ty);
3181 let intrinsic_name = CString::new(format!("llvm.powi.{}.i32", ty_name)).unwrap();
3182 let intrinsic_id = core::LLVMLookupIntrinsicID(
3183 intrinsic_name.as_ptr(),
3184 intrinsic_name.to_bytes().len(),
3185 );
3186 let mut param_types = [base_ty];
3187 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3188 module,
3189 intrinsic_id,
3190 param_types.as_mut_ptr(),
3191 param_types.len(),
3192 );
3193 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3194 let mut args = [base_val, exp_val];
3195 let value = core::LLVMBuildCall2(
3196 ctx.builder,
3197 fn_ty,
3198 intrinsic_fn,
3199 args.as_mut_ptr(),
3200 args.len() as u32,
3201 c"".as_ptr(),
3202 );
3203 Ok(value)
3204 }
3205 Intrinsic::Copysign { mag, sign } => {
3206 lower_binary_float_intrinsic(ctx, module, "llvm.copysign", mag, sign)
3207 }
3208 Intrinsic::Minnum { a, b } => {
3209 lower_binary_float_intrinsic(ctx, module, "llvm.minnum", a, b)
3210 }
3211 Intrinsic::Maxnum { a, b } => {
3212 lower_binary_float_intrinsic(ctx, module, "llvm.maxnum", a, b)
3213 }
3214
3215 Intrinsic::Fma { a, b, c } => {
3217 let a_val = lower_operand(ctx, a);
3218 let b_val = lower_operand(ctx, b);
3219 let c_val = lower_operand(ctx, c);
3220 let ty = lower_type(ctx.ctx, ctx.storage, a.get_type());
3221 let ty_name = get_float_type_suffix(ty);
3222 let intrinsic_name = CString::new(format!("llvm.fma.{}", ty_name)).unwrap();
3223 let intrinsic_id = core::LLVMLookupIntrinsicID(
3224 intrinsic_name.as_ptr(),
3225 intrinsic_name.to_bytes().len(),
3226 );
3227 let mut param_types = [ty];
3228 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3229 module,
3230 intrinsic_id,
3231 param_types.as_mut_ptr(),
3232 param_types.len(),
3233 );
3234 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3235 let mut args = [a_val, b_val, c_val];
3236 let value = core::LLVMBuildCall2(
3237 ctx.builder,
3238 fn_ty,
3239 intrinsic_fn,
3240 args.as_mut_ptr(),
3241 args.len() as u32,
3242 c"".as_ptr(),
3243 );
3244 Ok(value)
3245 }
3246
3247 Intrinsic::Ctpop { value } => {
3249 lower_unary_int_intrinsic(ctx, module, "llvm.ctpop", value)
3250 }
3251 Intrinsic::Ctlz {
3252 value,
3253 is_zero_poison,
3254 } => {
3255 let val = lower_operand(ctx, value);
3256 let ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
3257 let intrinsic_name =
3258 CString::new(format!("llvm.ctlz.i{}", core::LLVMGetIntTypeWidth(ty))).unwrap();
3259 let intrinsic_id = core::LLVMLookupIntrinsicID(
3260 intrinsic_name.as_ptr(),
3261 intrinsic_name.to_bytes().len(),
3262 );
3263 let mut param_types = [ty];
3264 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3265 module,
3266 intrinsic_id,
3267 param_types.as_mut_ptr(),
3268 param_types.len(),
3269 );
3270 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3271 let poison_val = core::LLVMConstInt(
3272 core::LLVMInt1TypeInContext(ctx.ctx),
3273 *is_zero_poison as u64,
3274 0,
3275 );
3276 let mut args = [val, poison_val];
3277 let result = core::LLVMBuildCall2(
3278 ctx.builder,
3279 fn_ty,
3280 intrinsic_fn,
3281 args.as_mut_ptr(),
3282 args.len() as u32,
3283 c"".as_ptr(),
3284 );
3285 Ok(result)
3286 }
3287 Intrinsic::Cttz {
3288 value,
3289 is_zero_poison,
3290 } => {
3291 let val = lower_operand(ctx, value);
3292 let ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
3293 let intrinsic_name =
3294 CString::new(format!("llvm.cttz.i{}", core::LLVMGetIntTypeWidth(ty))).unwrap();
3295 let intrinsic_id = core::LLVMLookupIntrinsicID(
3296 intrinsic_name.as_ptr(),
3297 intrinsic_name.to_bytes().len(),
3298 );
3299 let mut param_types = [ty];
3300 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3301 module,
3302 intrinsic_id,
3303 param_types.as_mut_ptr(),
3304 param_types.len(),
3305 );
3306 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3307 let poison_val = core::LLVMConstInt(
3308 core::LLVMInt1TypeInContext(ctx.ctx),
3309 *is_zero_poison as u64,
3310 0,
3311 );
3312 let mut args = [val, poison_val];
3313 let result = core::LLVMBuildCall2(
3314 ctx.builder,
3315 fn_ty,
3316 intrinsic_fn,
3317 args.as_mut_ptr(),
3318 args.len() as u32,
3319 c"".as_ptr(),
3320 );
3321 Ok(result)
3322 }
3323 Intrinsic::Bitreverse { value } => {
3324 lower_unary_int_intrinsic(ctx, module, "llvm.bitreverse", value)
3325 }
3326 Intrinsic::Bswap { value } => {
3327 lower_unary_int_intrinsic(ctx, module, "llvm.bswap", value)
3328 }
3329 Intrinsic::Fshl { a, b, shift } => {
3330 let a_val = lower_operand(ctx, a);
3331 let b_val = lower_operand(ctx, b);
3332 let shift_val = lower_operand(ctx, shift);
3333 let ty = lower_type(ctx.ctx, ctx.storage, a.get_type());
3334 let intrinsic_name =
3335 CString::new(format!("llvm.fshl.i{}", core::LLVMGetIntTypeWidth(ty))).unwrap();
3336 let intrinsic_id = core::LLVMLookupIntrinsicID(
3337 intrinsic_name.as_ptr(),
3338 intrinsic_name.to_bytes().len(),
3339 );
3340 let mut param_types = [ty];
3341 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3342 module,
3343 intrinsic_id,
3344 param_types.as_mut_ptr(),
3345 param_types.len(),
3346 );
3347 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3348 let mut args = [a_val, b_val, shift_val];
3349 let result = core::LLVMBuildCall2(
3350 ctx.builder,
3351 fn_ty,
3352 intrinsic_fn,
3353 args.as_mut_ptr(),
3354 args.len() as u32,
3355 c"".as_ptr(),
3356 );
3357 Ok(result)
3358 }
3359 Intrinsic::Fshr { a, b, shift } => {
3360 let a_val = lower_operand(ctx, a);
3361 let b_val = lower_operand(ctx, b);
3362 let shift_val = lower_operand(ctx, shift);
3363 let ty = lower_type(ctx.ctx, ctx.storage, a.get_type());
3364 let intrinsic_name =
3365 CString::new(format!("llvm.fshr.i{}", core::LLVMGetIntTypeWidth(ty))).unwrap();
3366 let intrinsic_id = core::LLVMLookupIntrinsicID(
3367 intrinsic_name.as_ptr(),
3368 intrinsic_name.to_bytes().len(),
3369 );
3370 let mut param_types = [ty];
3371 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3372 module,
3373 intrinsic_id,
3374 param_types.as_mut_ptr(),
3375 param_types.len(),
3376 );
3377 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3378 let mut args = [a_val, b_val, shift_val];
3379 let result = core::LLVMBuildCall2(
3380 ctx.builder,
3381 fn_ty,
3382 intrinsic_fn,
3383 args.as_mut_ptr(),
3384 args.len() as u32,
3385 c"".as_ptr(),
3386 );
3387 Ok(result)
3388 }
3389
3390 Intrinsic::Expect { value, expected } => {
3392 let val = lower_operand(ctx, value);
3393 let exp = lower_operand(ctx, expected);
3394 let ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
3395 let intrinsic_name =
3396 CString::new(format!("llvm.expect.i{}", core::LLVMGetIntTypeWidth(ty)))
3397 .unwrap();
3398 let intrinsic_id = core::LLVMLookupIntrinsicID(
3399 intrinsic_name.as_ptr(),
3400 intrinsic_name.to_bytes().len(),
3401 );
3402 let mut param_types = [ty];
3403 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3404 module,
3405 intrinsic_id,
3406 param_types.as_mut_ptr(),
3407 param_types.len(),
3408 );
3409 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3410 let mut args = [val, exp];
3411 let result = core::LLVMBuildCall2(
3412 ctx.builder,
3413 fn_ty,
3414 intrinsic_fn,
3415 args.as_mut_ptr(),
3416 args.len() as u32,
3417 c"".as_ptr(),
3418 );
3419 Ok(result)
3420 }
3421 Intrinsic::Assume { cond } => {
3422 let cond_val = lower_operand(ctx, cond);
3423 let intrinsic_name = c"llvm.assume";
3424 let intrinsic_id = core::LLVMLookupIntrinsicID(
3425 intrinsic_name.as_ptr(),
3426 intrinsic_name.count_bytes(),
3427 );
3428 let intrinsic_fn =
3429 core::LLVMGetIntrinsicDeclaration(module, intrinsic_id, null_mut(), 0);
3430 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3431 let mut args = [cond_val];
3432 core::LLVMBuildCall2(
3433 ctx.builder,
3434 fn_ty,
3435 intrinsic_fn,
3436 args.as_mut_ptr(),
3437 args.len() as u32,
3438 c"".as_ptr(),
3439 );
3440 Ok(null_mut())
3441 }
3442 Intrinsic::Trap => {
3443 let intrinsic_name = c"llvm.trap";
3444 let intrinsic_id = core::LLVMLookupIntrinsicID(
3445 intrinsic_name.as_ptr(),
3446 intrinsic_name.count_bytes(),
3447 );
3448 let intrinsic_fn =
3449 core::LLVMGetIntrinsicDeclaration(module, intrinsic_id, null_mut(), 0);
3450 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3451 core::LLVMBuildCall2(
3452 ctx.builder,
3453 fn_ty,
3454 intrinsic_fn,
3455 null_mut(),
3456 0,
3457 c"".as_ptr(),
3458 );
3459 Ok(null_mut())
3460 }
3461 Intrinsic::Debugtrap => {
3462 let intrinsic_name = c"llvm.debugtrap";
3463 let intrinsic_id = core::LLVMLookupIntrinsicID(
3464 intrinsic_name.as_ptr(),
3465 intrinsic_name.count_bytes(),
3466 );
3467 let intrinsic_fn =
3468 core::LLVMGetIntrinsicDeclaration(module, intrinsic_id, null_mut(), 0);
3469 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3470 core::LLVMBuildCall2(
3471 ctx.builder,
3472 fn_ty,
3473 intrinsic_fn,
3474 null_mut(),
3475 0,
3476 c"".as_ptr(),
3477 );
3478 Ok(null_mut())
3479 }
3480 }
3481 } }
3483
3484unsafe fn lower_unary_float_intrinsic(
3486 ctx: &FnCtx,
3487 module: *mut LLVMModule,
3488 name: &str,
3489 value: &Operand,
3490) -> Result<LLVMValueRef, Error> {
3491 unsafe {
3492 let val = lower_operand(ctx, value);
3493 let ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
3494 let ty_name = get_float_type_suffix(ty);
3495 let intrinsic_name = CString::new(format!("{}.{}", name, ty_name)).unwrap();
3496 let intrinsic_id =
3497 core::LLVMLookupIntrinsicID(intrinsic_name.as_ptr(), intrinsic_name.to_bytes().len());
3498 let mut param_types = [ty];
3499 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3500 module,
3501 intrinsic_id,
3502 param_types.as_mut_ptr(),
3503 param_types.len(),
3504 );
3505 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3506 let mut args = [val];
3507 let result = core::LLVMBuildCall2(
3508 ctx.builder,
3509 fn_ty,
3510 intrinsic_fn,
3511 args.as_mut_ptr(),
3512 args.len() as u32,
3513 c"".as_ptr(),
3514 );
3515 Ok(result)
3516 } }
3518
3519unsafe fn lower_binary_float_intrinsic(
3521 ctx: &FnCtx,
3522 module: *mut LLVMModule,
3523 name: &str,
3524 a: &Operand,
3525 b: &Operand,
3526) -> Result<LLVMValueRef, Error> {
3527 unsafe {
3528 let a_val = lower_operand(ctx, a);
3529 let b_val = lower_operand(ctx, b);
3530 let ty = lower_type(ctx.ctx, ctx.storage, a.get_type());
3531 let ty_name = get_float_type_suffix(ty);
3532 let intrinsic_name = CString::new(format!("{}.{}", name, ty_name)).unwrap();
3533 let intrinsic_id =
3534 core::LLVMLookupIntrinsicID(intrinsic_name.as_ptr(), intrinsic_name.to_bytes().len());
3535 let mut param_types = [ty];
3536 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3537 module,
3538 intrinsic_id,
3539 param_types.as_mut_ptr(),
3540 param_types.len(),
3541 );
3542 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3543 let mut args = [a_val, b_val];
3544 let result = core::LLVMBuildCall2(
3545 ctx.builder,
3546 fn_ty,
3547 intrinsic_fn,
3548 args.as_mut_ptr(),
3549 args.len() as u32,
3550 c"".as_ptr(),
3551 );
3552 Ok(result)
3553 } }
3555
3556unsafe fn lower_unary_int_intrinsic(
3558 ctx: &FnCtx,
3559 module: *mut LLVMModule,
3560 name: &str,
3561 value: &Operand,
3562) -> Result<LLVMValueRef, Error> {
3563 unsafe {
3564 let val = lower_operand(ctx, value);
3565 let ty = lower_type(ctx.ctx, ctx.storage, value.get_type());
3566 let intrinsic_name =
3567 CString::new(format!("{}.i{}", name, core::LLVMGetIntTypeWidth(ty))).unwrap();
3568 let intrinsic_id =
3569 core::LLVMLookupIntrinsicID(intrinsic_name.as_ptr(), intrinsic_name.to_bytes().len());
3570 let mut param_types = [ty];
3571 let intrinsic_fn = core::LLVMGetIntrinsicDeclaration(
3572 module,
3573 intrinsic_id,
3574 param_types.as_mut_ptr(),
3575 param_types.len(),
3576 );
3577 let fn_ty = core::LLVMGlobalGetValueType(intrinsic_fn);
3578 let mut args = [val];
3579 let result = core::LLVMBuildCall2(
3580 ctx.builder,
3581 fn_ty,
3582 intrinsic_fn,
3583 args.as_mut_ptr(),
3584 args.len() as u32,
3585 c"".as_ptr(),
3586 );
3587 Ok(result)
3588 } }
3590
3591unsafe fn get_float_type_suffix(ty: LLVMTypeRef) -> &'static str {
3593 unsafe {
3594 match core::LLVMGetTypeKind(ty) {
3595 llvm_sys::LLVMTypeKind::LLVMHalfTypeKind => "f16",
3596 llvm_sys::LLVMTypeKind::LLVMBFloatTypeKind => "bf16",
3597 llvm_sys::LLVMTypeKind::LLVMFloatTypeKind => "f32",
3598 llvm_sys::LLVMTypeKind::LLVMDoubleTypeKind => "f64",
3599 llvm_sys::LLVMTypeKind::LLVMFP128TypeKind => "f128",
3600 _ => "f64", }
3602 } }