Skip to main content

pliron_llvm/
to_llvm_ir.rs

1//! Translate from pliron's LLVM dialect to LLVM-IR
2
3use std::collections::hash_map;
4
5use llvm_sys::{LLVMIntPredicate, LLVMLinkage, LLVMRealPredicate};
6use pliron::{
7    attribute::{Attribute, attr_cast},
8    basic_block::BasicBlock,
9    builtin::{
10        attr_interfaces::FloatAttr,
11        attributes::{FPDoubleAttr, FPSingleAttr, IntegerAttr, StringAttr},
12        op_interfaces::{
13            AtMostOneRegionInterface, BranchOpInterface, CallOpCallable, CallOpInterface,
14            OneOpdInterface, OneResultInterface, SingleBlockRegionInterface, SymbolOpInterface,
15        },
16        ops::ModuleOp,
17        type_interfaces::FunctionTypeInterface,
18        types::{FP32Type, FP64Type, IntegerType},
19    },
20    common_traits::Named,
21    context::{Context, Ptr},
22    derive::{attr_interface, attr_interface_impl},
23    graph::traversals::region::topological_order,
24    identifier::Identifier,
25    input_err, input_err_noloc, input_error, input_error_noloc,
26    linked_list::{ContainsLinkedList, LinkedList},
27    location::Located,
28    op::{Op, op_cast},
29    operation::Operation,
30    printable::Printable,
31    result::Result,
32    r#type::{Type, TypeObj, Typed, type_cast},
33    utils::apint::APInt,
34    value::{DefiningEntity, Value},
35};
36
37use pliron::derive::{op_interface, op_interface_impl, type_interface, type_interface_impl};
38use rustc_hash::FxHashMap;
39use thiserror::Error;
40
41use crate::{
42    attributes::{FCmpPredicateAttr, ICmpPredicateAttr, LinkageAttr},
43    llvm_sys::core::{
44        LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue,
45        instruction_iter, llvm_add_case, llvm_add_function, llvm_add_global, llvm_add_incoming,
46        llvm_append_basic_block_in_context, llvm_array_type2, llvm_build_add, llvm_build_and,
47        llvm_build_array_alloca, llvm_build_ashr, llvm_build_bitcast, llvm_build_br,
48        llvm_build_call2, llvm_build_cond_br, llvm_build_extract_element, llvm_build_extract_value,
49        llvm_build_fadd, llvm_build_fcmp, llvm_build_fdiv, llvm_build_fmul, llvm_build_fpext,
50        llvm_build_fptosi, llvm_build_fptoui, llvm_build_fptrunc, llvm_build_freeze,
51        llvm_build_frem, llvm_build_fsub, llvm_build_gep2, llvm_build_icmp,
52        llvm_build_insert_element, llvm_build_insert_value, llvm_build_int_to_ptr,
53        llvm_build_load2, llvm_build_lshr, llvm_build_mul, llvm_build_or, llvm_build_phi,
54        llvm_build_ptr_to_int, llvm_build_ret, llvm_build_ret_void, llvm_build_sdiv,
55        llvm_build_select, llvm_build_sext, llvm_build_shl, llvm_build_shuffle_vector,
56        llvm_build_sitofp, llvm_build_srem, llvm_build_store, llvm_build_sub, llvm_build_switch,
57        llvm_build_trunc, llvm_build_udiv, llvm_build_uitofp, llvm_build_unreachable,
58        llvm_build_urem, llvm_build_va_arg, llvm_build_xor, llvm_build_zext,
59        llvm_can_value_use_fast_math_flags, llvm_clear_insertion_position, llvm_const_int,
60        llvm_const_null, llvm_const_real, llvm_const_vector, llvm_double_type_in_context,
61        llvm_float_type_in_context, llvm_function_type, llvm_get_named_function, llvm_get_param,
62        llvm_get_poison, llvm_get_undef, llvm_int_type_in_context, llvm_is_a,
63        llvm_lookup_intrinsic_id, llvm_pointer_type_in_context, llvm_position_builder_at_end,
64        llvm_scalable_vector_type, llvm_set_alignment, llvm_set_fast_math_flags,
65        llvm_set_initializer, llvm_set_linkage, llvm_set_nneg, llvm_struct_create_named,
66        llvm_struct_set_body, llvm_struct_type_in_context, llvm_vector_type,
67        llvm_void_type_in_context,
68    },
69    op_interfaces::{
70        AlignableOpInterface, FastMathFlags, IsDeclaration, LlvmSymbolName, NNegFlag,
71        PointerTypeResult,
72    },
73    ops::{
74        AShrOp, AddOp, AddressOfOp, AllocaOp, AndOp, BitcastOp, BrOp, CallIntrinsicOp, CallOp,
75        CondBrOp, ConstantOp, ExtractElementOp, ExtractValueOp, FAddOp, FCmpOp, FDivOp, FMulOp,
76        FPExtOp, FPToSIOp, FPToUIOp, FPTruncOp, FRemOp, FSubOp, FreezeOp, FuncOp, GetElementPtrOp,
77        GlobalOp, ICmpOp, InsertElementOp, InsertValueOp, IntToPtrOp, LShrOp, LoadOp, MulOp, OrOp,
78        PoisonOp, PtrToIntOp, ReturnOp, SDivOp, SExtOp, SIToFPOp, SRemOp, SelectOp, ShlOp,
79        ShuffleVectorOp, StoreOp, SubOp, SwitchOp, TruncOp, UDivOp, UIToFPOp, URemOp, UndefOp,
80        UnreachableOp, VAArgOp, XorOp, ZExtOp, ZeroOp,
81    },
82    types::{ArrayType, FuncType, PointerType, StructType, VectorType, VoidType},
83};
84
85/// Mapping from pliron entities to LLVM entities.
86pub struct ConversionContext<'a> {
87    // The current LLVMModule being converted to.
88    cur_llvm_module: &'a LLVMModule,
89    // A map from pliron Values to LLVM Values.
90    value_map: FxHashMap<Value, LLVMValue>,
91    // A map from pliron basic blocks to LLVM.
92    block_map: FxHashMap<Ptr<BasicBlock>, LLVMBasicBlock>,
93    // A map from pliron functions to LLVM functions.
94    function_map: FxHashMap<Identifier, LLVMValue>,
95    // A map from pliron globals to LLVM globals.
96    globals_map: FxHashMap<Identifier, LLVMValue>,
97    // A map from pliron StructTypes to LLVM StructTypes.
98    structs_map: FxHashMap<Identifier, LLVMType>,
99    // Type cache to avoid redundant conversions.
100    type_cache: FxHashMap<Ptr<TypeObj>, LLVMType>,
101    // The active LLVM builder.
102    builder: LLVMBuilder,
103    // Scratch builder in a scratch function for attempting to evaluate constants.
104    scratch_builder: LLVMBuilder,
105}
106
107impl<'a> ConversionContext<'a> {
108    pub fn new(llvm_ctx: &'a LLVMContext, cur_llvm_module: &'a LLVMModule) -> Self {
109        Self {
110            cur_llvm_module,
111            value_map: FxHashMap::default(),
112            block_map: FxHashMap::default(),
113            function_map: FxHashMap::default(),
114            globals_map: FxHashMap::default(),
115            structs_map: FxHashMap::default(),
116            type_cache: FxHashMap::default(),
117            builder: LLVMBuilder::new(llvm_ctx),
118            scratch_builder: LLVMBuilder::new(llvm_ctx),
119        }
120    }
121
122    pub fn clear_per_function_data(&mut self) {
123        self.value_map.clear();
124        self.block_map.clear();
125        llvm_clear_insertion_position(&self.builder);
126    }
127}
128
129#[derive(Error, Debug)]
130pub enum ToLLVMErr {
131    #[error("Type {0} does not have a conversion to LLVM type implemented")]
132    MissingTypeConversion(String),
133    #[error("Operation {0} does not have a conversion to LLVM instruction implemented")]
134    MissingOpConversion(String),
135    #[error("Definition for value {0} not seen yet")]
136    UndefinedValue(String),
137    #[error("Block definition {0} not seen yet")]
138    UndefinedBlock(String),
139    #[error("Number of block args in the source dialect equal the number of PHIs in target IR")]
140    NumBlockArgsNumPhisMismatch,
141    #[error("ConstantOp must have integer or float value")]
142    ConstOpNotIntOrFloat,
143    #[error(
144        "Insert/Extract value instructions must specify exactly one index, an LLVM-C API limitation"
145    )]
146    InsertExtractValueIndices,
147    #[error("GlobalOp Initializer region does not terminate with a return with value")]
148    GlobalOpInitializerRegionBadReturn,
149    #[error("Cannot evaluate value to a constant")]
150    CannotEvaluateToConst,
151}
152
153pub fn convert_ipredicate(pred: ICmpPredicateAttr) -> LLVMIntPredicate {
154    match pred {
155        ICmpPredicateAttr::EQ => LLVMIntPredicate::LLVMIntEQ,
156        ICmpPredicateAttr::NE => LLVMIntPredicate::LLVMIntNE,
157        ICmpPredicateAttr::UGT => LLVMIntPredicate::LLVMIntUGT,
158        ICmpPredicateAttr::UGE => LLVMIntPredicate::LLVMIntUGE,
159        ICmpPredicateAttr::ULT => LLVMIntPredicate::LLVMIntULT,
160        ICmpPredicateAttr::ULE => LLVMIntPredicate::LLVMIntULE,
161        ICmpPredicateAttr::SGT => LLVMIntPredicate::LLVMIntSGT,
162        ICmpPredicateAttr::SGE => LLVMIntPredicate::LLVMIntSGE,
163        ICmpPredicateAttr::SLT => LLVMIntPredicate::LLVMIntSLT,
164        ICmpPredicateAttr::SLE => LLVMIntPredicate::LLVMIntSLE,
165    }
166}
167
168pub fn convert_fpredicate(pred: FCmpPredicateAttr) -> LLVMRealPredicate {
169    match pred {
170        FCmpPredicateAttr::False => LLVMRealPredicate::LLVMRealPredicateFalse,
171        FCmpPredicateAttr::OEQ => LLVMRealPredicate::LLVMRealOEQ,
172        FCmpPredicateAttr::OGT => LLVMRealPredicate::LLVMRealOGT,
173        FCmpPredicateAttr::OGE => LLVMRealPredicate::LLVMRealOGE,
174        FCmpPredicateAttr::OLT => LLVMRealPredicate::LLVMRealOLT,
175        FCmpPredicateAttr::OLE => LLVMRealPredicate::LLVMRealOLE,
176        FCmpPredicateAttr::ONE => LLVMRealPredicate::LLVMRealONE,
177        FCmpPredicateAttr::ORD => LLVMRealPredicate::LLVMRealORD,
178        FCmpPredicateAttr::UNO => LLVMRealPredicate::LLVMRealUNO,
179        FCmpPredicateAttr::UEQ => LLVMRealPredicate::LLVMRealUEQ,
180        FCmpPredicateAttr::UGT => LLVMRealPredicate::LLVMRealUGT,
181        FCmpPredicateAttr::UGE => LLVMRealPredicate::LLVMRealUGE,
182        FCmpPredicateAttr::ULT => LLVMRealPredicate::LLVMRealULT,
183        FCmpPredicateAttr::ULE => LLVMRealPredicate::LLVMRealULE,
184        FCmpPredicateAttr::UNE => LLVMRealPredicate::LLVMRealUNE,
185        FCmpPredicateAttr::True => LLVMRealPredicate::LLVMRealPredicateTrue,
186    }
187}
188
189pub fn convert_linkage(linkage: LinkageAttr) -> LLVMLinkage {
190    match linkage {
191        LinkageAttr::ExternalLinkage => LLVMLinkage::LLVMExternalLinkage,
192        LinkageAttr::AvailableExternallyLinkage => LLVMLinkage::LLVMAvailableExternallyLinkage,
193        LinkageAttr::LinkOnceAnyLinkage => LLVMLinkage::LLVMLinkOnceAnyLinkage,
194        LinkageAttr::LinkOnceODRLinkage => LLVMLinkage::LLVMLinkOnceODRLinkage,
195        LinkageAttr::WeakAnyLinkage => LLVMLinkage::LLVMWeakAnyLinkage,
196        LinkageAttr::WeakODRLinkage => LLVMLinkage::LLVMWeakODRLinkage,
197        LinkageAttr::AppendingLinkage => LLVMLinkage::LLVMAppendingLinkage,
198        LinkageAttr::InternalLinkage => LLVMLinkage::LLVMInternalLinkage,
199        LinkageAttr::PrivateLinkage => LLVMLinkage::LLVMPrivateLinkage,
200        LinkageAttr::DLLImportLinkage => LLVMLinkage::LLVMDLLImportLinkage,
201        LinkageAttr::DLLExportLinkage => LLVMLinkage::LLVMDLLExportLinkage,
202        LinkageAttr::ExternalWeakLinkage => LLVMLinkage::LLVMExternalWeakLinkage,
203        LinkageAttr::GhostLinkage => LLVMLinkage::LLVMGhostLinkage,
204        LinkageAttr::CommonLinkage => LLVMLinkage::LLVMCommonLinkage,
205        LinkageAttr::LinkOnceODRAutoHideLinkage => LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage,
206        LinkageAttr::LinkerPrivateLinkage => LLVMLinkage::LLVMLinkerPrivateLinkage,
207        LinkageAttr::LinkerPrivateWeakLinkage => LLVMLinkage::LLVMLinkerPrivateWeakLinkage,
208    }
209}
210
211#[::pliron::linkme::distributed_slice]
212#[linkme(crate = pliron::linkme)]
213pub static TEST: [u64];
214
215/// Convert a float attribute to fp64 (since LLVM's C-API pretty much restricts us to that).
216#[attr_interface]
217trait FloatAttrToFP64: FloatAttr {
218    fn to_fp64(&self) -> f64;
219    fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
220    where
221        Self: Sized,
222    {
223        Ok(())
224    }
225}
226
227#[attr_interface_impl]
228impl FloatAttrToFP64 for FPSingleAttr {
229    fn to_fp64(&self) -> f64 {
230        Into::<f32>::into(self.clone()) as f64
231    }
232}
233
234#[attr_interface_impl]
235impl FloatAttrToFP64 for FPDoubleAttr {
236    fn to_fp64(&self) -> f64 {
237        Into::<f64>::into(self.clone())
238    }
239}
240
241/// A type that implements this is convertible to an [LLVMType].
242#[type_interface]
243trait ToLLVMType {
244    /// Convert from pliron [Type] to [LLVMType].
245    fn convert(
246        &self,
247        ctx: &Context,
248        llvm_ctx: &LLVMContext,
249        cctx: &mut ConversionContext,
250    ) -> Result<LLVMType>;
251
252    fn verify(_type: &dyn Type, _ctx: &Context) -> Result<()>
253    where
254        Self: Sized,
255    {
256        Ok(())
257    }
258}
259
260/// An [Op] that implements this is convertible to an [LLVMValue].
261#[op_interface]
262trait ToLLVMValue {
263    /// Convert from pliron [Op] to [LLVMValue].
264    fn convert(
265        &self,
266        ctx: &Context,
267        llvm_ctx: &LLVMContext,
268        cctx: &mut ConversionContext,
269    ) -> Result<LLVMValue>;
270
271    fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
272    where
273        Self: Sized,
274    {
275        Ok(())
276    }
277}
278
279#[type_interface_impl]
280impl ToLLVMType for IntegerType {
281    fn convert(
282        &self,
283        _ctx: &Context,
284        llvm_ctx: &LLVMContext,
285        _cctx: &mut ConversionContext,
286    ) -> Result<LLVMType> {
287        Ok(llvm_int_type_in_context(llvm_ctx, self.width()))
288    }
289}
290
291#[type_interface_impl]
292impl ToLLVMType for ArrayType {
293    fn convert(
294        &self,
295        ctx: &Context,
296        llvm_ctx: &LLVMContext,
297        cctx: &mut ConversionContext,
298    ) -> Result<LLVMType> {
299        let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
300        Ok(llvm_array_type2(elem_ty, self.size()))
301    }
302}
303
304#[type_interface_impl]
305impl ToLLVMType for FuncType {
306    fn convert(
307        &self,
308        ctx: &Context,
309        llvm_ctx: &LLVMContext,
310        cctx: &mut ConversionContext,
311    ) -> Result<LLVMType> {
312        let args_tys: Vec<_> = self
313            .arg_types()
314            .iter()
315            .map(|ty| convert_type(ctx, llvm_ctx, cctx, *ty))
316            .collect::<Result<_>>()?;
317        let ret_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type())?;
318        Ok(llvm_function_type(ret_ty, &args_tys, self.is_var_arg()))
319    }
320}
321
322#[type_interface_impl]
323impl ToLLVMType for VoidType {
324    fn convert(
325        &self,
326        _ctx: &Context,
327        llvm_ctx: &LLVMContext,
328        _cctx: &mut ConversionContext,
329    ) -> Result<LLVMType> {
330        Ok(llvm_void_type_in_context(llvm_ctx))
331    }
332}
333
334#[type_interface_impl]
335impl ToLLVMType for PointerType {
336    fn convert(
337        &self,
338        _ctx: &Context,
339        llvm_ctx: &LLVMContext,
340        _cctx: &mut ConversionContext,
341    ) -> Result<LLVMType> {
342        Ok(llvm_pointer_type_in_context(llvm_ctx, 0))
343    }
344}
345
346#[type_interface_impl]
347impl ToLLVMType for StructType {
348    fn convert(
349        &self,
350        ctx: &Context,
351        llvm_ctx: &LLVMContext,
352        cctx: &mut ConversionContext,
353    ) -> Result<LLVMType> {
354        if self.is_opaque() {
355            let name = self.name().expect("Opaqaue struct must have a name");
356            Ok(llvm_struct_create_named(llvm_ctx, name.as_str()))
357        } else {
358            let field_types = self
359                .fields()
360                .map(|fty| convert_type(ctx, llvm_ctx, cctx, fty))
361                .collect::<Result<Vec<_>>>()?;
362            if let Some(name) = self.name() {
363                match cctx.structs_map.entry(name) {
364                    hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
365                    hash_map::Entry::Vacant(entry) => {
366                        let str_ty = llvm_struct_create_named(llvm_ctx, entry.key());
367                        llvm_struct_set_body(str_ty, &field_types, false);
368                        entry.insert(str_ty);
369                        Ok(str_ty)
370                    }
371                }
372            } else {
373                Ok(llvm_struct_type_in_context(llvm_ctx, &field_types, false))
374            }
375        }
376    }
377}
378
379#[type_interface_impl]
380impl ToLLVMType for VectorType {
381    fn convert(
382        &self,
383        ctx: &Context,
384        llvm_ctx: &LLVMContext,
385        cctx: &mut ConversionContext,
386    ) -> Result<LLVMType> {
387        let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
388        let num_elems = self.num_elements();
389        if self.is_scalable() {
390            Ok(llvm_scalable_vector_type(elem_ty, num_elems))
391        } else {
392            Ok(llvm_vector_type(elem_ty, num_elems))
393        }
394    }
395}
396
397#[type_interface_impl]
398impl ToLLVMType for FP32Type {
399    fn convert(
400        &self,
401        _ctx: &Context,
402        llvm_ctx: &LLVMContext,
403        _cctx: &mut ConversionContext,
404    ) -> Result<LLVMType> {
405        Ok(llvm_float_type_in_context(llvm_ctx))
406    }
407}
408
409#[type_interface_impl]
410impl ToLLVMType for FP64Type {
411    fn convert(
412        &self,
413        _ctx: &Context,
414        llvm_ctx: &LLVMContext,
415        _cctx: &mut ConversionContext,
416    ) -> Result<LLVMType> {
417        Ok(llvm_double_type_in_context(llvm_ctx))
418    }
419}
420
421/// Convert a pliron [Type] to [LLVMType].
422pub fn convert_type(
423    ctx: &Context,
424    llvm_ctx: &LLVMContext,
425    cctx: &mut ConversionContext,
426    ty: Ptr<TypeObj>,
427) -> Result<LLVMType> {
428    if let Some(cached) = cctx.type_cache.get(&ty) {
429        return Ok(*cached);
430    }
431    if let Some(converter) = type_cast::<dyn ToLLVMType>(&**ty.deref(ctx)) {
432        let llvm_ty = converter.convert(ctx, llvm_ctx, cctx)?;
433        cctx.type_cache.insert(ty, llvm_ty);
434        return Ok(llvm_ty);
435    }
436
437    input_err_noloc!(ToLLVMErr::MissingTypeConversion(
438        ty.deref(ctx).get_type_id().to_string()
439    ))
440}
441
442fn convert_value_operand(
443    cctx: &mut ConversionContext,
444    ctx: &Context,
445    value: &Value,
446) -> Result<LLVMValue> {
447    match cctx.value_map.get(value) {
448        Some(v) => Ok(*v),
449        None => {
450            input_err_noloc!(ToLLVMErr::UndefinedValue(value.unique_name(ctx).into()))
451        }
452    }
453}
454
455fn convert_block_operand(
456    cctx: &mut ConversionContext,
457    ctx: &Context,
458    block: Ptr<BasicBlock>,
459) -> Result<LLVMBasicBlock> {
460    match cctx.block_map.get(&block) {
461        Some(v) => Ok(*v),
462        None => {
463            input_err_noloc!(ToLLVMErr::UndefinedBlock(block.unique_name(ctx).into()))
464        }
465    }
466}
467
468macro_rules! to_llvm_value_int_bin_op {
469    (
470        $op_name:ident, $builder_function:ident
471    ) => {
472        #[pliron::derive::op_interface_impl]
473        impl ToLLVMValue for $op_name {
474            fn convert(
475                &self,
476                ctx: &Context,
477                _llvm_ctx: &LLVMContext,
478                cctx: &mut ConversionContext,
479            ) -> Result<LLVMValue> {
480                let op = self.get_operation().deref(ctx);
481                let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
482                let lhs = convert_value_operand(cctx, ctx, &lhs)?;
483                let rhs = convert_value_operand(cctx, ctx, &rhs)?;
484                Ok($builder_function(
485                    &cctx.builder,
486                    lhs,
487                    rhs,
488                    &self.get_result(ctx).unique_name(ctx),
489                ))
490            }
491        }
492    };
493}
494
495to_llvm_value_int_bin_op!(AddOp, llvm_build_add);
496to_llvm_value_int_bin_op!(SubOp, llvm_build_sub);
497to_llvm_value_int_bin_op!(MulOp, llvm_build_mul);
498to_llvm_value_int_bin_op!(SDivOp, llvm_build_sdiv);
499to_llvm_value_int_bin_op!(UDivOp, llvm_build_udiv);
500to_llvm_value_int_bin_op!(URemOp, llvm_build_urem);
501to_llvm_value_int_bin_op!(SRemOp, llvm_build_srem);
502to_llvm_value_int_bin_op!(AndOp, llvm_build_and);
503to_llvm_value_int_bin_op!(OrOp, llvm_build_or);
504to_llvm_value_int_bin_op!(XorOp, llvm_build_xor);
505to_llvm_value_int_bin_op!(ShlOp, llvm_build_shl);
506to_llvm_value_int_bin_op!(LShrOp, llvm_build_lshr);
507to_llvm_value_int_bin_op!(AShrOp, llvm_build_ashr);
508
509#[op_interface_impl]
510impl ToLLVMValue for AllocaOp {
511    fn convert(
512        &self,
513        ctx: &Context,
514        llvm_ctx: &LLVMContext,
515        cctx: &mut ConversionContext,
516    ) -> Result<LLVMValue> {
517        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_pointee_type(ctx))?;
518        let size = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
519        let alloca_op = llvm_build_array_alloca(
520            &cctx.builder,
521            ty,
522            size,
523            &self.get_result(ctx).unique_name(ctx),
524        );
525        if let Some(alignment) = self.alignment(ctx) {
526            llvm_set_alignment(alloca_op, alignment);
527        }
528        Ok(alloca_op)
529    }
530}
531
532#[op_interface_impl]
533impl ToLLVMValue for BitcastOp {
534    fn convert(
535        &self,
536        ctx: &Context,
537        llvm_ctx: &LLVMContext,
538        cctx: &mut ConversionContext,
539    ) -> Result<LLVMValue> {
540        let arg = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
541        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
542        let bitcast_op = llvm_build_bitcast(
543            &cctx.builder,
544            arg,
545            ty,
546            &self.get_result(ctx).unique_name(ctx),
547        );
548        Ok(bitcast_op)
549    }
550}
551
552fn link_succ_operands_with_phis(
553    ctx: &Context,
554    cctx: &mut ConversionContext,
555    source_block: Ptr<BasicBlock>,
556    target_block: LLVMBasicBlock,
557    opds: Vec<Value>,
558) -> Result<()> {
559    let mut phis = vec![];
560    for inst in instruction_iter(target_block) {
561        if !llvm_is_a::phi_node(inst) {
562            break;
563        };
564        phis.push(inst);
565    }
566
567    if phis.len() != opds.len() {
568        return input_err!(
569            source_block.deref(ctx).loc(),
570            ToLLVMErr::NumBlockArgsNumPhisMismatch
571        );
572    }
573
574    let source_block = convert_block_operand(cctx, ctx, source_block)?;
575
576    for (idx, arg) in opds.iter().enumerate() {
577        let arg = convert_value_operand(cctx, ctx, arg)?;
578        llvm_add_incoming(phis[idx], &[arg], &[source_block]);
579    }
580    Ok(())
581}
582
583#[op_interface_impl]
584impl ToLLVMValue for BrOp {
585    fn convert(
586        &self,
587        ctx: &Context,
588        _llvm_ctx: &LLVMContext,
589        cctx: &mut ConversionContext,
590    ) -> Result<LLVMValue> {
591        let op = self.get_operation().deref(ctx);
592        let succ = op.get_successor(0);
593        let succ_llvm = convert_block_operand(cctx, ctx, succ)?;
594        let branch_op = llvm_build_br(&cctx.builder, succ_llvm);
595
596        // Link the arguments we pass to the block with the PHIs there.
597        link_succ_operands_with_phis(
598            ctx,
599            cctx,
600            op.get_container().expect("Unlinked operation"),
601            succ_llvm,
602            self.successor_operands(ctx, 0),
603        )?;
604
605        Ok(branch_op)
606    }
607}
608
609#[op_interface_impl]
610impl ToLLVMValue for CondBrOp {
611    fn convert(
612        &self,
613        ctx: &Context,
614        _llvm_ctx: &LLVMContext,
615        cctx: &mut ConversionContext,
616    ) -> Result<LLVMValue> {
617        let op = self.get_operation().deref(ctx);
618        let (true_succ, false_succ) = (op.get_successor(0), op.get_successor(1));
619        let true_succ_llvm = convert_block_operand(cctx, ctx, true_succ)?;
620        let false_succ_llvm = convert_block_operand(cctx, ctx, false_succ)?;
621        let cond = convert_value_operand(cctx, ctx, &self.condition(ctx))?;
622
623        let branch_op = llvm_build_cond_br(&cctx.builder, cond, true_succ_llvm, false_succ_llvm);
624
625        // Link the arguments we pass to the block with the PHIs there.
626        link_succ_operands_with_phis(
627            ctx,
628            cctx,
629            op.get_container().expect("Unlinked operation"),
630            true_succ_llvm,
631            self.successor_operands(ctx, 0),
632        )?;
633        link_succ_operands_with_phis(
634            ctx,
635            cctx,
636            op.get_container().expect("Unlinked operation"),
637            false_succ_llvm,
638            self.successor_operands(ctx, 1),
639        )?;
640
641        Ok(branch_op)
642    }
643}
644
645#[op_interface_impl]
646impl ToLLVMValue for SwitchOp {
647    fn convert(
648        &self,
649        ctx: &Context,
650        llvm_ctx: &LLVMContext,
651        cctx: &mut ConversionContext,
652    ) -> Result<LLVMValue> {
653        let op = self.get_operation().deref(ctx);
654        let cond = convert_value_operand(cctx, ctx, &self.condition(ctx))?;
655        let default_succ = convert_block_operand(cctx, ctx, self.default_dest(ctx))?;
656        let switch_op = llvm_build_switch(
657            &cctx.builder,
658            cond,
659            default_succ,
660            self.cases(ctx).len() as u32,
661        );
662
663        // Link the arguments we pass to the block with the PHIs there.
664        link_succ_operands_with_phis(
665            ctx,
666            cctx,
667            op.get_container().expect("Unlinked operation"),
668            default_succ,
669            self.default_dest_operands(ctx),
670        )?;
671        for case in self.cases(ctx) {
672            let succ_llvm = convert_block_operand(cctx, ctx, case.dest)?;
673            link_succ_operands_with_phis(
674                ctx,
675                cctx,
676                op.get_container().expect("Unlinked operation"),
677                succ_llvm,
678                case.dest_opds,
679            )?;
680
681            let int_ty = case.value.get_type();
682            let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
683            let ap_int_val: APInt = case.value.clone().into();
684            let case_const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
685
686            llvm_add_case(switch_op, case_const_val, succ_llvm);
687        }
688
689        Ok(switch_op)
690    }
691}
692
693#[op_interface_impl]
694impl ToLLVMValue for LoadOp {
695    fn convert(
696        &self,
697        ctx: &Context,
698        llvm_ctx: &LLVMContext,
699        cctx: &mut ConversionContext,
700    ) -> Result<LLVMValue> {
701        let pointee_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
702        let ptr = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
703        let load_op = llvm_build_load2(
704            &cctx.builder,
705            pointee_ty,
706            ptr,
707            &self.get_result(ctx).unique_name(ctx),
708        );
709        if let Some(alignment) = self.alignment(ctx) {
710            llvm_set_alignment(load_op, alignment);
711        }
712        Ok(load_op)
713    }
714}
715
716#[op_interface_impl]
717impl ToLLVMValue for StoreOp {
718    fn convert(
719        &self,
720        ctx: &Context,
721        _llvm_ctx: &LLVMContext,
722        cctx: &mut ConversionContext,
723    ) -> Result<LLVMValue> {
724        let value = convert_value_operand(cctx, ctx, &self.value_opd(ctx))?;
725        let ptr = convert_value_operand(cctx, ctx, &self.address_opd(ctx))?;
726        let store_op = llvm_build_store(&cctx.builder, value, ptr);
727        if let Some(alignment) = self.alignment(ctx) {
728            llvm_set_alignment(store_op, alignment);
729        }
730        Ok(store_op)
731    }
732}
733
734#[op_interface_impl]
735impl ToLLVMValue for ICmpOp {
736    fn convert(
737        &self,
738        ctx: &Context,
739        _llvm_ctx: &LLVMContext,
740        cctx: &mut ConversionContext,
741    ) -> Result<LLVMValue> {
742        let op = self.get_operation().deref(ctx);
743        let predicate = convert_ipredicate(self.predicate(ctx));
744        let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
745        let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
746        let icmp_op = llvm_build_icmp(
747            &cctx.builder,
748            predicate,
749            lhs,
750            rhs,
751            &self.get_result(ctx).unique_name(ctx),
752        );
753        Ok(icmp_op)
754    }
755}
756
757#[op_interface_impl]
758impl ToLLVMValue for ReturnOp {
759    fn convert(
760        &self,
761        ctx: &Context,
762        _llvm_ctx: &LLVMContext,
763        cctx: &mut ConversionContext,
764    ) -> Result<LLVMValue> {
765        let ret_op = if let Some(retval) = self.retval(ctx) {
766            let retval = convert_value_operand(cctx, ctx, &retval)?;
767            llvm_build_ret(&cctx.builder, retval)
768        } else {
769            llvm_build_ret_void(&cctx.builder)
770        };
771        Ok(ret_op)
772    }
773}
774
775#[op_interface_impl]
776impl ToLLVMValue for UnreachableOp {
777    fn convert(
778        &self,
779        _ctx: &Context,
780        _llvm_ctx: &LLVMContext,
781        cctx: &mut ConversionContext,
782    ) -> Result<LLVMValue> {
783        Ok(llvm_build_unreachable(&cctx.builder))
784    }
785}
786
787#[op_interface_impl]
788impl ToLLVMValue for ConstantOp {
789    fn convert(
790        &self,
791        ctx: &Context,
792        llvm_ctx: &LLVMContext,
793        cctx: &mut ConversionContext,
794    ) -> Result<LLVMValue> {
795        <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
796    }
797}
798
799#[op_interface_impl]
800impl ToLLVMValue for ZeroOp {
801    fn convert(
802        &self,
803        ctx: &Context,
804        llvm_ctx: &LLVMContext,
805        cctx: &mut ConversionContext,
806    ) -> Result<LLVMValue> {
807        <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
808    }
809}
810
811#[op_interface_impl]
812impl ToLLVMValue for IntToPtrOp {
813    fn convert(
814        &self,
815        ctx: &Context,
816        llvm_ctx: &LLVMContext,
817        cctx: &mut ConversionContext,
818    ) -> Result<LLVMValue> {
819        let op = self.get_operation().deref(ctx);
820        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
821        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
822        let inttoptr_op = llvm_build_int_to_ptr(
823            &cctx.builder,
824            arg,
825            ty,
826            &self.get_result(ctx).unique_name(ctx),
827        );
828        Ok(inttoptr_op)
829    }
830}
831
832#[op_interface_impl]
833impl ToLLVMValue for PtrToIntOp {
834    fn convert(
835        &self,
836        ctx: &Context,
837        llvm_ctx: &LLVMContext,
838        cctx: &mut ConversionContext,
839    ) -> Result<LLVMValue> {
840        let op = self.get_operation().deref(ctx);
841        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
842        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
843        let ptrtoint_op = llvm_build_ptr_to_int(
844            &cctx.builder,
845            arg,
846            ty,
847            &self.get_result(ctx).unique_name(ctx),
848        );
849        Ok(ptrtoint_op)
850    }
851}
852
853#[op_interface_impl]
854impl ToLLVMValue for UndefOp {
855    fn convert(
856        &self,
857        ctx: &Context,
858        llvm_ctx: &LLVMContext,
859        cctx: &mut ConversionContext,
860    ) -> Result<LLVMValue> {
861        <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
862    }
863}
864
865#[op_interface_impl]
866impl ToLLVMValue for PoisonOp {
867    fn convert(
868        &self,
869        ctx: &Context,
870        llvm_ctx: &LLVMContext,
871        cctx: &mut ConversionContext,
872    ) -> Result<LLVMValue> {
873        <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
874    }
875}
876
877#[op_interface_impl]
878impl ToLLVMValue for AddressOfOp {
879    fn convert(
880        &self,
881        ctx: &Context,
882        llvm_ctx: &LLVMContext,
883        cctx: &mut ConversionContext,
884    ) -> Result<LLVMValue> {
885        <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
886    }
887}
888
889#[op_interface_impl]
890impl ToLLVMValue for FreezeOp {
891    fn convert(
892        &self,
893        ctx: &Context,
894        _llvm_ctx: &LLVMContext,
895        cctx: &mut ConversionContext,
896    ) -> Result<LLVMValue> {
897        let op = self.get_operation().deref(ctx);
898        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
899        let freeze_op =
900            llvm_build_freeze(&cctx.builder, arg, &self.get_result(ctx).unique_name(ctx));
901        Ok(freeze_op)
902    }
903}
904
905#[op_interface_impl]
906impl ToLLVMValue for CallOp {
907    fn convert(
908        &self,
909        ctx: &Context,
910        llvm_ctx: &LLVMContext,
911        cctx: &mut ConversionContext,
912    ) -> Result<LLVMValue> {
913        let args: Vec<_> = self
914            .args(ctx)
915            .into_iter()
916            .map(|v| convert_value_operand(cctx, ctx, &v))
917            .collect::<Result<_>>()?;
918        let ty = convert_type(ctx, llvm_ctx, cctx, self.callee_type(ctx))?;
919        let res = self.get_result(ctx);
920        let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
921            ""
922        } else {
923            &res.unique_name(ctx)
924        };
925        let callee = match self.callee(ctx) {
926            CallOpCallable::Direct(callee_sym) => {
927                *cctx.function_map.get(&callee_sym).ok_or_else(|| {
928                    input_error_noloc!(ToLLVMErr::UndefinedValue(callee_sym.to_string()))
929                })?
930            }
931            CallOpCallable::Indirect(callee) => convert_value_operand(cctx, ctx, &callee)?,
932        };
933        let call_val = llvm_build_call2(&cctx.builder, ty, callee, &args, name);
934        if let Some(fmf) = self.get_attr_llvm_call_fastmath_flags(ctx)
935            && llvm_can_value_use_fast_math_flags(call_val)
936        {
937            llvm_set_fast_math_flags(call_val, (*fmf).into());
938        }
939        Ok(call_val)
940    }
941}
942
943#[op_interface_impl]
944impl ToLLVMValue for CallIntrinsicOp {
945    fn convert(
946        &self,
947        ctx: &Context,
948        llvm_ctx: &LLVMContext,
949        cctx: &mut ConversionContext,
950    ) -> Result<LLVMValue> {
951        let op = self.get_operation().deref(ctx);
952        let args: Vec<_> = (0..op.get_num_operands())
953            .map(|i| convert_value_operand(cctx, ctx, &op.get_operand(i)))
954            .collect::<Result<_>>()?;
955        let fn_ty = convert_type(
956            ctx,
957            llvm_ctx,
958            cctx,
959            self.get_attr_llvm_intrinsic_type(ctx)
960                .unwrap()
961                .get_type(ctx),
962        )?;
963
964        let intrinsic_name = <StringAttr as Into<String>>::into(
965            self.get_attr_llvm_intrinsic_name(ctx)
966                .expect("Intrinsic call does not name the intrinsic to be called")
967                .clone(),
968        );
969
970        let _intrinsic_id = llvm_lookup_intrinsic_id(&intrinsic_name).ok_or_else(|| {
971            input_error_noloc!(ToLLVMErr::UndefinedValue(intrinsic_name.to_string()))
972        })?;
973
974        // We just use llvm_add_function instead of llvm_get_intrinsic_declaration here
975        // because the latter requires that (and I quote from Intrinsics.h::getOrInsertDeclaration):
976        //   "For a declaration of an overloaded intrinsic, Tys must provide exactly one
977        //    type for each overloaded type in the intrinsic."
978        // I don't know how to determine that from just the name and argument types.
979        let intrinsic_fn = llvm_get_named_function(cctx.cur_llvm_module, &intrinsic_name)
980            .unwrap_or_else(|| llvm_add_function(cctx.cur_llvm_module, &intrinsic_name, fn_ty));
981
982        let res = self.get_result(ctx);
983        let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
984            ""
985        } else {
986            &res.unique_name(ctx)
987        };
988
989        let intrinsic_op = llvm_build_call2(&cctx.builder, fn_ty, intrinsic_fn, &args, name);
990
991        if let Some(fmf) = self.get_attr_llvm_intrinsic_fastmath_flags(ctx)
992            && llvm_can_value_use_fast_math_flags(intrinsic_op)
993        {
994            llvm_set_fast_math_flags(intrinsic_op, (*fmf).into());
995        }
996
997        Ok(intrinsic_op)
998    }
999}
1000
1001#[op_interface_impl]
1002impl ToLLVMValue for SExtOp {
1003    fn convert(
1004        &self,
1005        ctx: &Context,
1006        llvm_ctx: &LLVMContext,
1007        cctx: &mut ConversionContext,
1008    ) -> Result<LLVMValue> {
1009        let op = self.get_operation().deref(ctx);
1010        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1011        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1012        let sext_op = llvm_build_sext(
1013            &cctx.builder,
1014            arg,
1015            ty,
1016            &self.get_result(ctx).unique_name(ctx),
1017        );
1018        Ok(sext_op)
1019    }
1020}
1021
1022#[op_interface_impl]
1023impl ToLLVMValue for ZExtOp {
1024    fn convert(
1025        &self,
1026        ctx: &Context,
1027        llvm_ctx: &LLVMContext,
1028        cctx: &mut ConversionContext,
1029    ) -> Result<LLVMValue> {
1030        let op = self.get_operation().deref(ctx);
1031        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1032        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1033        let zext_op = llvm_build_zext(
1034            &cctx.builder,
1035            arg,
1036            ty,
1037            &self.get_result(ctx).unique_name(ctx),
1038        );
1039        // The built value may not even be an instruction, but a folded constant.
1040        if llvm_is_a::instruction(zext_op) {
1041            let nneg = self.nneg(ctx);
1042            llvm_set_nneg(zext_op, nneg);
1043        }
1044        Ok(zext_op)
1045    }
1046}
1047
1048#[op_interface_impl]
1049impl ToLLVMValue for TruncOp {
1050    fn convert(
1051        &self,
1052        ctx: &Context,
1053        llvm_ctx: &LLVMContext,
1054        cctx: &mut ConversionContext,
1055    ) -> Result<LLVMValue> {
1056        let op = self.get_operation().deref(ctx);
1057        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1058        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1059        let trunc_op = llvm_build_trunc(
1060            &cctx.builder,
1061            arg,
1062            ty,
1063            &self.get_result(ctx).unique_name(ctx),
1064        );
1065        Ok(trunc_op)
1066    }
1067}
1068
1069#[op_interface_impl]
1070impl ToLLVMValue for GetElementPtrOp {
1071    fn convert(
1072        &self,
1073        ctx: &Context,
1074        llvm_ctx: &LLVMContext,
1075        cctx: &mut ConversionContext,
1076    ) -> Result<LLVMValue> {
1077        let indices = self
1078            .indices(ctx)
1079            .iter()
1080            .map(|v| match v {
1081                crate::ops::GepIndex::Constant(c) => Ok(llvm_const_int(
1082                    llvm_int_type_in_context(llvm_ctx, 32),
1083                    Into::<u64>::into(*c),
1084                    false,
1085                )),
1086                crate::ops::GepIndex::Value(value) => convert_value_operand(cctx, ctx, value),
1087            })
1088            .collect::<Result<Vec<_>>>()?;
1089
1090        let base = convert_value_operand(cctx, ctx, &self.src_ptr(ctx))?;
1091
1092        let src_elem_type = convert_type(ctx, llvm_ctx, cctx, self.src_elem_type(ctx))?;
1093        let gep_op = llvm_build_gep2(
1094            &cctx.builder,
1095            src_elem_type,
1096            base,
1097            &indices,
1098            &self.get_result(ctx).unique_name(ctx),
1099        );
1100        Ok(gep_op)
1101    }
1102}
1103
1104#[op_interface_impl]
1105impl ToLLVMValue for InsertValueOp {
1106    fn convert(
1107        &self,
1108        ctx: &Context,
1109        _llvm_ctx: &LLVMContext,
1110        cctx: &mut ConversionContext,
1111    ) -> Result<LLVMValue> {
1112        let op = self.get_operation().deref(ctx);
1113        let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1114        let value = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1115        let indices = self.indices(ctx);
1116        if indices.len() != 1 {
1117            return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1118        }
1119        let insert_op = llvm_build_insert_value(
1120            &cctx.builder,
1121            base,
1122            value,
1123            indices[0],
1124            &self.get_result(ctx).unique_name(ctx),
1125        );
1126        Ok(insert_op)
1127    }
1128}
1129
1130#[op_interface_impl]
1131impl ToLLVMValue for ExtractValueOp {
1132    fn convert(
1133        &self,
1134        ctx: &Context,
1135        _llvm_ctx: &LLVMContext,
1136        cctx: &mut ConversionContext,
1137    ) -> Result<LLVMValue> {
1138        let op = self.get_operation().deref(ctx);
1139        let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1140        let indices = self.indices(ctx);
1141        if indices.len() != 1 {
1142            return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1143        }
1144        let extract_op = llvm_build_extract_value(
1145            &cctx.builder,
1146            base,
1147            indices[0],
1148            &self.get_result(ctx).unique_name(ctx),
1149        );
1150        Ok(extract_op)
1151    }
1152}
1153
1154#[op_interface_impl]
1155impl ToLLVMValue for InsertElementOp {
1156    fn convert(
1157        &self,
1158        ctx: &Context,
1159        _llvm_ctx: &LLVMContext,
1160        cctx: &mut ConversionContext,
1161    ) -> Result<LLVMValue> {
1162        let base = convert_value_operand(cctx, ctx, &self.vector_operand(ctx))?;
1163        let value = convert_value_operand(cctx, ctx, &self.element_operand(ctx))?;
1164        let index = convert_value_operand(cctx, ctx, &self.index_operand(ctx))?;
1165        let insert_op = llvm_build_insert_element(
1166            &cctx.builder,
1167            base,
1168            value,
1169            index,
1170            &self.get_result(ctx).unique_name(ctx),
1171        );
1172        Ok(insert_op)
1173    }
1174}
1175
1176#[op_interface_impl]
1177impl ToLLVMValue for ExtractElementOp {
1178    fn convert(
1179        &self,
1180        ctx: &Context,
1181        _llvm_ctx: &LLVMContext,
1182        cctx: &mut ConversionContext,
1183    ) -> Result<LLVMValue> {
1184        let base = convert_value_operand(cctx, ctx, &self.vector_operand(ctx))?;
1185        let index = convert_value_operand(cctx, ctx, &self.index_operand(ctx))?;
1186        let extract_op = llvm_build_extract_element(
1187            &cctx.builder,
1188            base,
1189            index,
1190            &self.get_result(ctx).unique_name(ctx),
1191        );
1192        Ok(extract_op)
1193    }
1194}
1195
1196#[op_interface_impl]
1197impl ToLLVMValue for ShuffleVectorOp {
1198    fn convert(
1199        &self,
1200        ctx: &Context,
1201        llvm_ctx: &LLVMContext,
1202        cctx: &mut ConversionContext,
1203    ) -> Result<LLVMValue> {
1204        let mask = &self
1205            .get_attr_llvm_shuffle_vector_mask(ctx)
1206            .expect("ShuffleVectorOp missing mask attribute")
1207            .0;
1208        let op = self.get_operation().deref(ctx);
1209        let vec1 = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1210        let vec2 = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1211        let int_ty = llvm_int_type_in_context(llvm_ctx, 32);
1212
1213        let mask = mask
1214            .iter()
1215            .map(|&i| llvm_const_int(int_ty, i as u64, true))
1216            .collect::<Vec<LLVMValue>>();
1217        let mask = llvm_const_vector(&mask);
1218
1219        let shuffle_op = llvm_build_shuffle_vector(
1220            &cctx.builder,
1221            vec1,
1222            vec2,
1223            mask,
1224            &self.get_result(ctx).unique_name(ctx),
1225        );
1226        Ok(shuffle_op)
1227    }
1228}
1229
1230#[op_interface_impl]
1231impl ToLLVMValue for SelectOp {
1232    fn convert(
1233        &self,
1234        ctx: &Context,
1235        _llvm_ctx: &LLVMContext,
1236        cctx: &mut ConversionContext,
1237    ) -> Result<LLVMValue> {
1238        let op = self.get_operation().deref(ctx);
1239        let cond = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1240        let true_val = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1241        let false_val = convert_value_operand(cctx, ctx, &op.get_operand(2))?;
1242        let select_op = llvm_build_select(
1243            &cctx.builder,
1244            cond,
1245            true_val,
1246            false_val,
1247            &self.get_result(ctx).unique_name(ctx),
1248        );
1249        Ok(select_op)
1250    }
1251}
1252
1253#[op_interface_impl]
1254impl ToLLVMValue for FAddOp {
1255    fn convert(
1256        &self,
1257        ctx: &Context,
1258        _llvm_ctx: &LLVMContext,
1259        cctx: &mut ConversionContext,
1260    ) -> Result<LLVMValue> {
1261        let op = self.get_operation().deref(ctx);
1262        let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1263        let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1264        let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1265        let inst = llvm_build_fadd(
1266            &cctx.builder,
1267            lhs,
1268            rhs,
1269            &self.get_result(ctx).unique_name(ctx),
1270        );
1271        // The built value may not even be an instruction, but a folded constant.
1272        if llvm_can_value_use_fast_math_flags(inst) {
1273            let fastmath = self.fast_math_flags(ctx);
1274            llvm_set_fast_math_flags(inst, fastmath.into());
1275        }
1276        Ok(inst)
1277    }
1278}
1279
1280#[op_interface_impl]
1281impl ToLLVMValue for FSubOp {
1282    fn convert(
1283        &self,
1284        ctx: &Context,
1285        _llvm_ctx: &LLVMContext,
1286        cctx: &mut ConversionContext,
1287    ) -> Result<LLVMValue> {
1288        let op = self.get_operation().deref(ctx);
1289        let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1290        let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1291        let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1292        let inst = llvm_build_fsub(
1293            &cctx.builder,
1294            lhs,
1295            rhs,
1296            &self.get_result(ctx).unique_name(ctx),
1297        );
1298        // The built value may not even be an instruction, but a folded constant.
1299        if llvm_can_value_use_fast_math_flags(inst) {
1300            let fastmath = self.fast_math_flags(ctx);
1301            llvm_set_fast_math_flags(inst, fastmath.into());
1302        }
1303        Ok(inst)
1304    }
1305}
1306
1307#[op_interface_impl]
1308impl ToLLVMValue for FMulOp {
1309    fn convert(
1310        &self,
1311        ctx: &Context,
1312        _llvm_ctx: &LLVMContext,
1313        cctx: &mut ConversionContext,
1314    ) -> Result<LLVMValue> {
1315        let op = self.get_operation().deref(ctx);
1316        let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1317        let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1318        let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1319        let inst = llvm_build_fmul(
1320            &cctx.builder,
1321            lhs,
1322            rhs,
1323            &self.get_result(ctx).unique_name(ctx),
1324        );
1325        // The built value may not even be an instruction, but a folded constant.
1326        if llvm_can_value_use_fast_math_flags(inst) {
1327            let fastmath = self.fast_math_flags(ctx);
1328            llvm_set_fast_math_flags(inst, fastmath.into());
1329        }
1330        Ok(inst)
1331    }
1332}
1333
1334#[op_interface_impl]
1335impl ToLLVMValue for FDivOp {
1336    fn convert(
1337        &self,
1338        ctx: &Context,
1339        _llvm_ctx: &LLVMContext,
1340        cctx: &mut ConversionContext,
1341    ) -> Result<LLVMValue> {
1342        let op = self.get_operation().deref(ctx);
1343        let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1344        let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1345        let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1346        let inst = llvm_build_fdiv(
1347            &cctx.builder,
1348            lhs,
1349            rhs,
1350            &self.get_result(ctx).unique_name(ctx),
1351        );
1352        // The built value may not even be an instruction, but a folded constant.
1353        if llvm_can_value_use_fast_math_flags(inst) {
1354            let fastmath = self.fast_math_flags(ctx);
1355            llvm_set_fast_math_flags(inst, fastmath.into());
1356        }
1357        Ok(inst)
1358    }
1359}
1360
1361#[op_interface_impl]
1362impl ToLLVMValue for FRemOp {
1363    fn convert(
1364        &self,
1365        ctx: &Context,
1366        _llvm_ctx: &LLVMContext,
1367        cctx: &mut ConversionContext,
1368    ) -> Result<LLVMValue> {
1369        let op = self.get_operation().deref(ctx);
1370        let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1371        let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1372        let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1373        let inst = llvm_build_frem(
1374            &cctx.builder,
1375            lhs,
1376            rhs,
1377            &self.get_result(ctx).unique_name(ctx),
1378        );
1379        // The built value may not even be an instruction, but a folded constant.
1380        if llvm_can_value_use_fast_math_flags(inst) {
1381            let fastmath = self.fast_math_flags(ctx);
1382            llvm_set_fast_math_flags(inst, fastmath.into());
1383        }
1384        Ok(inst)
1385    }
1386}
1387
1388#[op_interface_impl]
1389impl ToLLVMValue for FCmpOp {
1390    fn convert(
1391        &self,
1392        ctx: &Context,
1393        _llvm_ctx: &LLVMContext,
1394        cctx: &mut ConversionContext,
1395    ) -> Result<LLVMValue> {
1396        let op = self.get_operation().deref(ctx);
1397        let predicate = convert_fpredicate(self.predicate(ctx));
1398        let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1399        let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1400        let fcmp_op = llvm_build_fcmp(
1401            &cctx.builder,
1402            predicate,
1403            lhs,
1404            rhs,
1405            &self.get_result(ctx).unique_name(ctx),
1406        );
1407        // The built value may not even be an instruction, but a folded constant.
1408        if llvm_can_value_use_fast_math_flags(fcmp_op) {
1409            let fastmath = self.fast_math_flags(ctx);
1410            llvm_set_fast_math_flags(fcmp_op, fastmath.into());
1411        }
1412        Ok(fcmp_op)
1413    }
1414}
1415
1416#[op_interface_impl]
1417impl ToLLVMValue for FPExtOp {
1418    fn convert(
1419        &self,
1420        ctx: &Context,
1421        llvm_ctx: &LLVMContext,
1422        cctx: &mut ConversionContext,
1423    ) -> Result<LLVMValue> {
1424        let op = self.get_operation().deref(ctx);
1425        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1426        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1427        let fpext_op = llvm_build_fpext(
1428            &cctx.builder,
1429            arg,
1430            ty,
1431            &self.get_result(ctx).unique_name(ctx),
1432        );
1433        // The built value may not even be an instruction, but a folded constant.
1434        if llvm_can_value_use_fast_math_flags(fpext_op) {
1435            let fastmath = self.fast_math_flags(ctx);
1436            llvm_set_fast_math_flags(fpext_op, fastmath.into());
1437        }
1438        Ok(fpext_op)
1439    }
1440}
1441
1442#[op_interface_impl]
1443impl ToLLVMValue for FPTruncOp {
1444    fn convert(
1445        &self,
1446        ctx: &Context,
1447        llvm_ctx: &LLVMContext,
1448        cctx: &mut ConversionContext,
1449    ) -> Result<LLVMValue> {
1450        let op = self.get_operation().deref(ctx);
1451        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1452        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1453        let fptrunc_op = llvm_build_fptrunc(
1454            &cctx.builder,
1455            arg,
1456            ty,
1457            &self.get_result(ctx).unique_name(ctx),
1458        );
1459        // The built value may not even be an instruction, but a folded constant.
1460        if llvm_can_value_use_fast_math_flags(fptrunc_op) {
1461            llvm_set_fast_math_flags(fptrunc_op, self.fast_math_flags(ctx).into());
1462        }
1463        Ok(fptrunc_op)
1464    }
1465}
1466
1467#[op_interface_impl]
1468impl ToLLVMValue for FPToSIOp {
1469    fn convert(
1470        &self,
1471        ctx: &Context,
1472        llvm_ctx: &LLVMContext,
1473        cctx: &mut ConversionContext,
1474    ) -> Result<LLVMValue> {
1475        let op = self.get_operation().deref(ctx);
1476        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1477        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1478        let fptosi_op = llvm_build_fptosi(
1479            &cctx.builder,
1480            arg,
1481            ty,
1482            &self.get_result(ctx).unique_name(ctx),
1483        );
1484        Ok(fptosi_op)
1485    }
1486}
1487
1488#[op_interface_impl]
1489impl ToLLVMValue for SIToFPOp {
1490    fn convert(
1491        &self,
1492        ctx: &Context,
1493        llvm_ctx: &LLVMContext,
1494        cctx: &mut ConversionContext,
1495    ) -> Result<LLVMValue> {
1496        let op = self.get_operation().deref(ctx);
1497        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1498        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1499        let sitofp_op = llvm_build_sitofp(
1500            &cctx.builder,
1501            arg,
1502            ty,
1503            &self.get_result(ctx).unique_name(ctx),
1504        );
1505        Ok(sitofp_op)
1506    }
1507}
1508
1509#[op_interface_impl]
1510impl ToLLVMValue for FPToUIOp {
1511    fn convert(
1512        &self,
1513        ctx: &Context,
1514        llvm_ctx: &LLVMContext,
1515        cctx: &mut ConversionContext,
1516    ) -> Result<LLVMValue> {
1517        let op = self.get_operation().deref(ctx);
1518        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1519        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1520        let fptoui_op = llvm_build_fptoui(
1521            &cctx.builder,
1522            arg,
1523            ty,
1524            &self.get_result(ctx).unique_name(ctx),
1525        );
1526        Ok(fptoui_op)
1527    }
1528}
1529
1530#[op_interface_impl]
1531impl ToLLVMValue for UIToFPOp {
1532    fn convert(
1533        &self,
1534        ctx: &Context,
1535        llvm_ctx: &LLVMContext,
1536        cctx: &mut ConversionContext,
1537    ) -> Result<LLVMValue> {
1538        let op = self.get_operation().deref(ctx);
1539        let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1540        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1541        let uitofp_op = llvm_build_uitofp(
1542            &cctx.builder,
1543            arg,
1544            ty,
1545            &self.get_result(ctx).unique_name(ctx),
1546        );
1547        // The built value may not even be an instruction, but a folded constant.
1548        if llvm_is_a::instruction(uitofp_op) {
1549            let nneg = self.nneg(ctx);
1550            llvm_set_nneg(uitofp_op, nneg);
1551        }
1552        Ok(uitofp_op)
1553    }
1554}
1555
1556#[op_interface_impl]
1557impl ToLLVMValue for VAArgOp {
1558    fn convert(
1559        &self,
1560        ctx: &Context,
1561        llvm_ctx: &LLVMContext,
1562        cctx: &mut ConversionContext,
1563    ) -> Result<LLVMValue> {
1564        let op = self.get_operation().deref(ctx);
1565        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1566        let opd = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1567        log::warn!("Generating va_arg instruction: It is poorly supported by LLVM");
1568        let vaarg_op = llvm_build_va_arg(
1569            &cctx.builder,
1570            opd,
1571            ty,
1572            &self.get_result(ctx).unique_name(ctx),
1573        );
1574        Ok(vaarg_op)
1575    }
1576}
1577
1578/// Convert a pliron [BasicBlock] to [LLVMBasicBlock].
1579fn convert_block(
1580    ctx: &Context,
1581    llvm_ctx: &LLVMContext,
1582    cctx: &mut ConversionContext,
1583    block: Ptr<BasicBlock>,
1584) -> Result<()> {
1585    let block_llvm = cctx.block_map[&block];
1586    llvm_position_builder_at_end(&cctx.builder, block_llvm);
1587
1588    for opr in block.deref(ctx).iter(ctx) {
1589        let op = Operation::get_op_dyn(opr, ctx);
1590        let op = op.as_ref();
1591        let Some(op_conv) = op_cast::<dyn ToLLVMValue>(op) else {
1592            let loc = op.loc(ctx);
1593            return input_err!(
1594                loc,
1595                ToLLVMErr::MissingOpConversion(op.get_opid().to_string())
1596            );
1597        };
1598        let op_llvm = op_conv.convert(ctx, llvm_ctx, cctx)?;
1599        let opr_ref = opr.deref(ctx);
1600        // LLVM instructions have at most one result.
1601        if opr_ref.get_num_results() == 1 {
1602            cctx.value_map.insert(opr_ref.get_result(0), op_llvm);
1603        }
1604    }
1605
1606    Ok(())
1607}
1608
1609/// Convert a pliron [FuncOp] to [LLVMValue]
1610fn convert_function(
1611    ctx: &Context,
1612    llvm_ctx: &LLVMContext,
1613    cctx: &mut ConversionContext,
1614    func_op: FuncOp,
1615) -> Result<LLVMValue> {
1616    cctx.clear_per_function_data();
1617    let func_llvm = cctx.function_map[&func_op.get_symbol_name(ctx)];
1618
1619    if let Some(linkage) = func_op.get_attr_llvm_function_linkage(ctx) {
1620        let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
1621        llvm_set_linkage(func_llvm, llvm_linkage);
1622    }
1623
1624    let f_region = func_op.get_region(ctx).expect("Function missing region");
1625
1626    // Map all blocks, staring with entry.
1627    let mut block_iter = f_region.deref(ctx).iter(ctx);
1628    {
1629        let entry = block_iter.next().expect("Missing entry block");
1630        // Map entry block arguments to LLVM function arguments.
1631        for (arg_idx, arg) in entry.deref(ctx).arguments().enumerate() {
1632            cctx.value_map
1633                .insert(arg, llvm_get_param(func_llvm, arg_idx.try_into().unwrap()));
1634        }
1635        let llvm_entry_block = llvm_append_basic_block_in_context(
1636            llvm_ctx,
1637            func_llvm,
1638            &entry.deref(ctx).unique_name(ctx),
1639        );
1640        cctx.block_map.insert(entry, llvm_entry_block);
1641    }
1642    for block in block_iter {
1643        let llvm_block = llvm_append_basic_block_in_context(
1644            llvm_ctx,
1645            func_llvm,
1646            &block.deref(ctx).unique_name(ctx),
1647        );
1648        llvm_position_builder_at_end(&cctx.builder, llvm_block);
1649        for arg in block.deref(ctx).arguments() {
1650            let arg_type = convert_type(ctx, llvm_ctx, cctx, arg.get_type(ctx))?;
1651            let phi = llvm_build_phi(&cctx.builder, arg_type, &arg.unique_name(ctx));
1652            cctx.value_map.insert(arg, phi);
1653        }
1654        cctx.block_map.insert(block, llvm_block);
1655    }
1656
1657    // Convert within every block.
1658    for block in topological_order(ctx, &f_region) {
1659        convert_block(ctx, llvm_ctx, cctx, block)?;
1660    }
1661
1662    Ok(func_llvm)
1663}
1664
1665#[op_interface]
1666trait ToLLVMConstValue {
1667    /// Convert from pliron [Op] to a constant [LLVMValue].
1668    fn convert(
1669        &self,
1670        ctx: &Context,
1671        llvm_ctx: &LLVMContext,
1672        cctx: &mut ConversionContext,
1673    ) -> Result<LLVMValue>;
1674
1675    fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
1676    where
1677        Self: Sized,
1678    {
1679        Ok(())
1680    }
1681}
1682
1683#[op_interface_impl]
1684impl ToLLVMConstValue for ConstantOp {
1685    fn convert(
1686        &self,
1687        ctx: &Context,
1688        llvm_ctx: &LLVMContext,
1689        cctx: &mut ConversionContext,
1690    ) -> Result<LLVMValue> {
1691        let op = self.get_operation().deref(ctx);
1692        let value = self.get_value(ctx);
1693        if let Some(int_val) = value.downcast_ref::<IntegerAttr>() {
1694            let int_ty = int_val.get_type();
1695            let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
1696            let ap_int_val: APInt = int_val.clone().into();
1697            let const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
1698            Ok(const_val)
1699        } else if let Some(float_val) = attr_cast::<dyn FloatAttrToFP64>(&*value) {
1700            let float_ty = float_val.get_type(ctx);
1701            let float_ty_llvm = convert_type(ctx, llvm_ctx, cctx, float_ty)?;
1702            let const_val = llvm_const_real(float_ty_llvm, float_val.to_fp64());
1703            Ok(const_val)
1704        } else {
1705            input_err!(op.loc(), ToLLVMErr::ConstOpNotIntOrFloat)
1706        }
1707    }
1708}
1709
1710#[op_interface_impl]
1711impl ToLLVMConstValue for UndefOp {
1712    fn convert(
1713        &self,
1714        ctx: &Context,
1715        llvm_ctx: &LLVMContext,
1716        cctx: &mut ConversionContext,
1717    ) -> Result<LLVMValue> {
1718        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1719        Ok(llvm_get_undef(ty))
1720    }
1721}
1722
1723#[op_interface_impl]
1724impl ToLLVMConstValue for PoisonOp {
1725    fn convert(
1726        &self,
1727        ctx: &Context,
1728        llvm_ctx: &LLVMContext,
1729        cctx: &mut ConversionContext,
1730    ) -> Result<LLVMValue> {
1731        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1732        Ok(llvm_get_poison(ty))
1733    }
1734}
1735
1736#[op_interface_impl]
1737impl ToLLVMConstValue for ZeroOp {
1738    fn convert(
1739        &self,
1740        ctx: &Context,
1741        llvm_ctx: &LLVMContext,
1742        cctx: &mut ConversionContext,
1743    ) -> Result<LLVMValue> {
1744        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1745        let zero_val = llvm_const_null(ty);
1746        Ok(zero_val)
1747    }
1748}
1749
1750#[op_interface_impl]
1751impl ToLLVMConstValue for AddressOfOp {
1752    fn convert(
1753        &self,
1754        ctx: &Context,
1755        _llvm_ctx: &LLVMContext,
1756        cctx: &mut ConversionContext,
1757    ) -> Result<LLVMValue> {
1758        let sym = self.get_global_name(ctx);
1759        cctx.globals_map
1760            .get(&sym)
1761            .or_else(|| cctx.function_map.get(&sym))
1762            .cloned()
1763            .ok_or_else(|| input_error_noloc!(ToLLVMErr::CannotEvaluateToConst))
1764    }
1765}
1766#[op_interface_impl]
1767impl ToLLVMConstValue for InsertValueOp {
1768    fn convert(
1769        &self,
1770        ctx: &Context,
1771        llvm_ctx: &LLVMContext,
1772        cctx: &mut ConversionContext,
1773    ) -> Result<LLVMValue> {
1774        let op = self.get_operation().deref(ctx);
1775        let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1776        let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1777        let indices = self.indices(ctx);
1778        if indices.len() != 1 {
1779            return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1780        }
1781
1782        // LLVM's builder tries to fold this, so we rely on that.
1783        let insert_op = llvm_build_insert_value(
1784            &cctx.scratch_builder,
1785            base,
1786            value,
1787            indices[0],
1788            &self.get_result(ctx).unique_name(ctx),
1789        );
1790        if !llvm_is_a::constant(insert_op) {
1791            return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1792        }
1793        Ok(insert_op)
1794    }
1795}
1796
1797#[op_interface_impl]
1798impl ToLLVMConstValue for InsertElementOp {
1799    fn convert(
1800        &self,
1801        ctx: &Context,
1802        llvm_ctx: &LLVMContext,
1803        cctx: &mut ConversionContext,
1804    ) -> Result<LLVMValue> {
1805        let op = self.get_operation().deref(ctx);
1806        let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1807        let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1808        let index = self.index_operand(ctx);
1809        let index = convert_to_llvm_const(ctx, cctx, llvm_ctx, index)?;
1810
1811        // LLVM's builder tries to fold this, so we rely on that.
1812        let insert_op = llvm_build_insert_element(
1813            &cctx.scratch_builder,
1814            base,
1815            value,
1816            index,
1817            &self.get_result(ctx).unique_name(ctx),
1818        );
1819        if !llvm_is_a::constant(insert_op) {
1820            return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1821        }
1822        Ok(insert_op)
1823    }
1824}
1825
1826#[op_interface_impl]
1827impl ToLLVMConstValue for TruncOp {
1828    fn convert(
1829        &self,
1830        ctx: &Context,
1831        llvm_ctx: &LLVMContext,
1832        cctx: &mut ConversionContext,
1833    ) -> Result<LLVMValue> {
1834        let op = self.get_operation().deref(ctx);
1835        let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1836        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1837
1838        // LLVM's builder tries to fold this, so we rely on that.
1839        let trunc_op = llvm_build_trunc(
1840            &cctx.scratch_builder,
1841            arg,
1842            ty,
1843            &self.get_result(ctx).unique_name(ctx),
1844        );
1845        if !llvm_is_a::constant(trunc_op) {
1846            return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1847        }
1848        Ok(trunc_op)
1849    }
1850}
1851
1852#[op_interface_impl]
1853impl ToLLVMConstValue for SubOp {
1854    fn convert(
1855        &self,
1856        ctx: &Context,
1857        llvm_ctx: &LLVMContext,
1858        cctx: &mut ConversionContext,
1859    ) -> Result<LLVMValue> {
1860        let op = self.get_operation().deref(ctx);
1861        let lhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1862        let rhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1863
1864        // LLVM's builder tries to fold this, so we rely on that.
1865        let sub_op = llvm_build_sub(
1866            &cctx.scratch_builder,
1867            lhs,
1868            rhs,
1869            &self.get_result(ctx).unique_name(ctx),
1870        );
1871        if !llvm_is_a::constant(sub_op) {
1872            return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1873        }
1874        Ok(sub_op)
1875    }
1876}
1877
1878#[op_interface_impl]
1879impl ToLLVMConstValue for PtrToIntOp {
1880    fn convert(
1881        &self,
1882        ctx: &Context,
1883        llvm_ctx: &LLVMContext,
1884        cctx: &mut ConversionContext,
1885    ) -> Result<LLVMValue> {
1886        let op = self.get_operation().deref(ctx);
1887        let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1888        let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1889
1890        // LLVM's builder tries to fold this, so we rely on that.
1891        let ptoi_op = llvm_build_ptr_to_int(
1892            &cctx.scratch_builder,
1893            arg,
1894            ty,
1895            &self.get_result(ctx).unique_name(ctx),
1896        );
1897        if !llvm_is_a::constant(ptoi_op) {
1898            return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1899        }
1900        Ok(ptoi_op)
1901    }
1902}
1903
1904fn convert_to_llvm_const(
1905    ctx: &Context,
1906    cctx: &mut ConversionContext,
1907    llvm_ctx: &LLVMContext,
1908    value: Value,
1909) -> Result<LLVMValue> {
1910    match value.defining_entity() {
1911        DefiningEntity::Op(op) => {
1912            let op = Operation::get_op_dyn(op, ctx);
1913            if let Some(const_trans) = op_cast::<dyn ToLLVMConstValue>(op.as_ref()) {
1914                const_trans.convert(ctx, llvm_ctx, cctx)
1915            } else {
1916                input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
1917            }
1918        }
1919        DefiningEntity::Block(_) => {
1920            input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
1921        }
1922    }
1923}
1924
1925fn convert_global_initializer(
1926    ctx: &Context,
1927    llvm_ctx: &LLVMContext,
1928    cctx: &mut ConversionContext,
1929    global_op: GlobalOp,
1930) -> Result<Option<LLVMValue>> {
1931    if let Some(_initializer) = global_op.get_initializer_value(ctx) {
1932        todo!()
1933    }
1934
1935    if let Some(init_block) = global_op.get_initializer_block(ctx) {
1936        let ret =
1937            Operation::get_op::<ReturnOp>(init_block.deref(ctx).get_terminator(ctx).unwrap(), ctx);
1938        let ret = ret.ok_or_else(|| {
1939            input_error!(
1940                global_op.loc(ctx),
1941                ToLLVMErr::GlobalOpInitializerRegionBadReturn
1942            )
1943        })?;
1944        let Some(ret_val) = ret.retval(ctx) else {
1945            return input_err!(
1946                global_op.loc(ctx),
1947                ToLLVMErr::GlobalOpInitializerRegionBadReturn
1948            );
1949        };
1950        let initializer_val = convert_to_llvm_const(ctx, cctx, llvm_ctx, ret_val)?;
1951        return Ok(Some(initializer_val));
1952    }
1953
1954    Ok(None)
1955}
1956
1957/// Convert pliron [ModuleOp] to [LLVMModule].
1958pub fn convert_module(
1959    ctx: &Context,
1960    llvm_ctx: &LLVMContext,
1961    module: ModuleOp,
1962) -> Result<LLVMModule> {
1963    let mod_name = module.get_symbol_name(ctx);
1964    let llvm_module = LLVMModule::new(&mod_name, llvm_ctx);
1965    let cctx = &mut ConversionContext::new(llvm_ctx, &llvm_module);
1966
1967    // Setup the scratch builder for evaluating constants.
1968    // `scratch_module` is freed at the end of this function, when it exits the scope.
1969    let scratch_module = LLVMModule::new("__pliron_scratch_module", llvm_ctx);
1970    let scratch_function = llvm_add_function(
1971        &scratch_module,
1972        "scratch",
1973        llvm_function_type(llvm_void_type_in_context(llvm_ctx), &[], false),
1974    );
1975    let scratch_function_entry =
1976        llvm_append_basic_block_in_context(llvm_ctx, scratch_function, "entry");
1977    llvm_position_builder_at_end(&cctx.scratch_builder, scratch_function_entry);
1978
1979    // Create new functions and map them.
1980    for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
1981        if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx) {
1982            let func_ty = func_op.get_type(ctx).deref(ctx);
1983            let func_ty_to_llvm = type_cast::<dyn ToLLVMType>(&*func_ty).ok_or_else(|| {
1984                input_error_noloc!(ToLLVMErr::MissingTypeConversion(
1985                    func_ty.disp(ctx).to_string()
1986                ))
1987            })?;
1988            let fn_ty_llvm = func_ty_to_llvm.convert(ctx, llvm_ctx, cctx)?;
1989            let name = func_op.get_symbol_name(ctx);
1990            let llvm_name = func_op.llvm_symbol_name(ctx).unwrap_or(name.clone().into());
1991            let func_llvm = llvm_add_function(&llvm_module, &llvm_name, fn_ty_llvm);
1992            cctx.function_map.insert(name, func_llvm);
1993        }
1994        if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
1995            let global_ty = global_op.get_type(ctx);
1996            let global_ty_llvm = convert_type(ctx, llvm_ctx, cctx, global_ty)?;
1997            let global_name = global_op.get_symbol_name(ctx);
1998            let llvm_global_name = global_op
1999                .llvm_symbol_name(ctx)
2000                .unwrap_or(global_name.clone().into());
2001            let global_llvm = llvm_add_global(&llvm_module, global_ty_llvm, &llvm_global_name);
2002            cctx.globals_map.insert(global_name, global_llvm);
2003        }
2004    }
2005
2006    for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
2007        if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx)
2008            && !func_op.is_declaration(ctx)
2009        {
2010            convert_function(ctx, llvm_ctx, cctx, func_op)?;
2011        }
2012        if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
2013            let global_name = global_op.get_symbol_name(ctx);
2014            let global_llvm = cctx.globals_map[&global_name];
2015            if !global_op.is_declaration(ctx)
2016                && let Some(initializer) =
2017                    convert_global_initializer(ctx, llvm_ctx, cctx, global_op)?
2018            {
2019                llvm_set_initializer(global_llvm, initializer);
2020            }
2021            if let Some(linkage) = global_op.get_attr_llvm_global_linkage(ctx) {
2022                let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
2023                llvm_set_linkage(global_llvm, llvm_linkage);
2024            }
2025            if let Some(alignment) = global_op.alignment(ctx) {
2026                llvm_set_alignment(global_llvm, alignment);
2027            }
2028        }
2029    }
2030
2031    Ok(llvm_module)
2032}