Skip to main content

pliron_llvm/
from_llvm_ir.rs

1//! Translate from LLVM-IR to pliron's LLVM dialect
2
3use std::num::NonZero;
4
5use llvm_sys::{
6    LLVMIntPredicate, LLVMLinkage, LLVMOpcode, LLVMRealPredicate, LLVMTypeKind, LLVMValueKind,
7};
8use pliron::{
9    attribute::AttrObj,
10    basic_block::BasicBlock,
11    builtin::{
12        attributes::{FPDoubleAttr, FPSingleAttr, IntegerAttr},
13        op_interfaces::{
14            AtMostOneRegionInterface, CallOpCallable, OneResultInterface,
15            SingleBlockRegionInterface,
16        },
17        ops::ModuleOp,
18        type_interfaces::FloatTypeInterface,
19        types::{FP32Type, FP64Type, IntegerType, Signedness},
20    },
21    context::{Context, Ptr},
22    debug_info,
23    derive::{type_interface, type_interface_impl},
24    identifier::{self, Identifier},
25    input_err_noloc, input_error_noloc,
26    irbuild::{
27        inserter::{IRInserter, Inserter},
28        listener::DummyListener,
29    },
30    linked_list::ContainsLinkedList,
31    op::Op,
32    operation::Operation,
33    result::Result,
34    r#type::{Type, TypeObj, TypePtr, type_cast},
35    utils::apint::APInt,
36    value::Value,
37};
38use rustc_hash::{FxHashMap, FxHashSet};
39use thiserror::Error;
40
41use crate::{
42    attributes::{
43        FCmpPredicateAttr, FastmathFlagsAttr, ICmpPredicateAttr, IntegerOverflowFlagsAttr,
44        LinkageAttr,
45    },
46    llvm_sys::core::{
47        LLVMBasicBlock, LLVMModule, LLVMType, LLVMValue, basic_block_iter, function_iter,
48        global_iter, incoming_iter, instruction_iter, llvm_can_value_use_fast_math_flags,
49        llvm_const_int_get_zext_value, llvm_const_real_get_double, llvm_count_struct_element_types,
50        llvm_get_aggregate_element, llvm_get_alignment, llvm_get_allocated_type,
51        llvm_get_array_length2, llvm_get_basic_block_name, llvm_get_basic_block_terminator,
52        llvm_get_called_function_type, llvm_get_called_value, llvm_get_const_opcode,
53        llvm_get_element_type, llvm_get_fast_math_flags, llvm_get_fcmp_predicate,
54        llvm_get_gep_source_element_type, llvm_get_icmp_predicate, llvm_get_indices,
55        llvm_get_initializer, llvm_get_instruction_opcode, llvm_get_instruction_parent,
56        llvm_get_int_type_width, llvm_get_linkage, llvm_get_mask_value, llvm_get_module_identifier,
57        llvm_get_nneg, llvm_get_nsw, llvm_get_num_arg_operands, llvm_get_num_mask_elements,
58        llvm_get_num_operands, llvm_get_nuw, llvm_get_operand, llvm_get_param_types,
59        llvm_get_return_type, llvm_get_struct_element_types, llvm_get_struct_name,
60        llvm_get_switch_case_value, llvm_get_type_kind, llvm_get_value_kind, llvm_get_value_name,
61        llvm_get_vector_size, llvm_global_get_value_type, llvm_is_a, llvm_is_declaration,
62        llvm_is_function_type_var_arg, llvm_is_opaque_struct, llvm_lookup_intrinsic_id,
63        llvm_print_value_to_string, llvm_type_of, llvm_value_as_basic_block,
64        llvm_value_is_basic_block, param_iter,
65    },
66    op_interfaces::{
67        AlignableOpInterface, BinArithOp, CastOpInterface, CastOpWithNNegInterface, FastMathFlags,
68        FloatBinArithOpWithFastMathFlags, IntBinArithOpWithOverflowFlag, LlvmSymbolName,
69    },
70    ops::{
71        AShrOp, AddOp, AddressOfOp, AllocaOp, AndOp, BitcastOp, BrOp, CallIntrinsicOp, CallOp,
72        CondBrOp, ConstantOp, ExtractElementOp, ExtractValueOp, FAddOp, FCmpOp, FDivOp, FMulOp,
73        FNegOp, FPExtOp, FPToSIOp, FPToUIOp, FPTruncOp, FRemOp, FSubOp, FreezeOp, FuncOp, GepIndex,
74        GetElementPtrOp, GlobalOp, ICmpOp, InsertElementOp, InsertValueOp, IntToPtrOp, LShrOp,
75        LoadOp, MulOp, OrOp, PoisonOp, PtrToIntOp, ReturnOp, SDivOp, SExtOp, SIToFPOp, SRemOp,
76        SelectOp, ShlOp, ShuffleVectorOp, StoreOp, SubOp, SwitchCase, SwitchOp, TruncOp, UDivOp,
77        UIToFPOp, URemOp, UndefOp, UnreachableOp, VAArgOp, XorOp, ZExtOp, ZeroOp,
78    },
79    types::{
80        ArrayType, FuncType, PointerType, StructErr, StructType, VectorType, VectorTypeKind,
81        VoidType,
82    },
83};
84
85/// Given a floating point type and an f64 value, get an equivalent attribute.
86/// LLVM's C-API pretty much restricts us to f64 for floating point constants.
87#[type_interface]
88trait FloatAttrBuilder: FloatTypeInterface {
89    fn value_from_f64(&self, val: f64) -> AttrObj;
90    fn verify(_attr: &dyn Type, _ctx: &Context) -> Result<()>
91    where
92        Self: Sized,
93    {
94        Ok(())
95    }
96}
97
98#[type_interface_impl]
99impl FloatAttrBuilder for FP32Type {
100    fn value_from_f64(&self, val: f64) -> AttrObj {
101        FPSingleAttr::from(val as f32).into()
102    }
103}
104
105#[type_interface_impl]
106impl FloatAttrBuilder for FP64Type {
107    fn value_from_f64(&self, val: f64) -> AttrObj {
108        FPDoubleAttr::from(val).into()
109    }
110}
111
112fn convert_type(
113    ctx: &mut Context,
114    cctx: &mut ConversionContext,
115    ty: LLVMType,
116) -> Result<Ptr<TypeObj>> {
117    if let Some(cached) = cctx.type_cache.get(&ty) {
118        return Ok(*cached);
119    }
120    let kind = llvm_get_type_kind(ty);
121    let converted_ty: Result<Ptr<TypeObj>> = match kind {
122        LLVMTypeKind::LLVMArrayTypeKind => {
123            let (element_ty, len) = (llvm_get_element_type(ty), llvm_get_array_length2(ty));
124            let elem = convert_type(ctx, cctx, element_ty)?;
125            Ok(ArrayType::get(ctx, elem, len).into())
126        }
127        LLVMTypeKind::LLVMFunctionTypeKind => {
128            let return_type = convert_type(ctx, cctx, llvm_get_return_type(ty))?;
129            let param_types = llvm_get_param_types(ty)
130                .into_iter()
131                .map(|ty| convert_type(ctx, cctx, ty))
132                .collect::<Result<_>>()?;
133            let is_var_arg = llvm_is_function_type_var_arg(ty);
134            Ok(FuncType::get(ctx, return_type, param_types, is_var_arg).into())
135        }
136        LLVMTypeKind::LLVMIntegerTypeKind => {
137            let bit_width = llvm_get_int_type_width(ty);
138            Ok(IntegerType::get(ctx, bit_width, Signedness::Signless).into())
139        }
140        LLVMTypeKind::LLVMPointerTypeKind => Ok(PointerType::get(ctx).into()),
141        LLVMTypeKind::LLVMStructTypeKind => {
142            let name_opt: Option<Identifier> =
143                llvm_get_struct_name(ty).map(|str| cctx.id_legaliser.legalise(&str));
144            if llvm_is_opaque_struct(ty) {
145                // Opaque structs must be named.
146                let Some(name) = name_opt else {
147                    return input_err_noloc!(StructErr::OpaqueAndAnonymousErr);
148                };
149                Ok(StructType::get_named(ctx, name, None)?.into())
150            } else {
151                let field_types = llvm_get_struct_element_types(ty)
152                    .into_iter()
153                    .map(|ty| convert_type(ctx, cctx, ty))
154                    .collect::<Result<_>>()?;
155                if let Some(name) = name_opt {
156                    Ok(StructType::get_named(ctx, name, Some(field_types))?.into())
157                } else {
158                    Ok(StructType::get_unnamed(ctx, field_types).into())
159                }
160            }
161        }
162        LLVMTypeKind::LLVMVoidTypeKind => Ok(VoidType::get(ctx).into()),
163        LLVMTypeKind::LLVMFloatTypeKind => Ok(FP32Type::get(ctx).into()),
164        LLVMTypeKind::LLVMDoubleTypeKind => Ok(FP64Type::get(ctx).into()),
165        LLVMTypeKind::LLVMVectorTypeKind | LLVMTypeKind::LLVMScalableVectorTypeKind => {
166            let element_ty = llvm_get_element_type(ty);
167            let elem_ty = convert_type(ctx, cctx, element_ty)?;
168            let num_elements = llvm_get_vector_size(ty);
169            let kind = if matches!(kind, LLVMTypeKind::LLVMScalableVectorTypeKind) {
170                VectorTypeKind::Scalable
171            } else {
172                VectorTypeKind::Fixed
173            };
174            Ok(VectorType::get(ctx, elem_ty, num_elements, kind).into())
175        }
176        LLVMTypeKind::LLVMHalfTypeKind => todo!(),
177        LLVMTypeKind::LLVMX86_FP80TypeKind => todo!(),
178        LLVMTypeKind::LLVMFP128TypeKind => todo!(),
179        LLVMTypeKind::LLVMPPC_FP128TypeKind => todo!(),
180        LLVMTypeKind::LLVMLabelTypeKind => todo!(),
181        LLVMTypeKind::LLVMMetadataTypeKind => todo!(),
182        LLVMTypeKind::LLVMTokenTypeKind => todo!(),
183        LLVMTypeKind::LLVMBFloatTypeKind => todo!(),
184        LLVMTypeKind::LLVMX86_AMXTypeKind => todo!(),
185        LLVMTypeKind::LLVMTargetExtTypeKind => todo!(),
186    };
187
188    let converted_ty = converted_ty?;
189    cctx.type_cache.insert(ty, converted_ty);
190    Ok(converted_ty)
191}
192
193pub fn convert_ipredicate(ipred: LLVMIntPredicate) -> ICmpPredicateAttr {
194    match ipred {
195        LLVMIntPredicate::LLVMIntEQ => ICmpPredicateAttr::EQ,
196        LLVMIntPredicate::LLVMIntNE => ICmpPredicateAttr::NE,
197        LLVMIntPredicate::LLVMIntUGT => ICmpPredicateAttr::UGT,
198        LLVMIntPredicate::LLVMIntUGE => ICmpPredicateAttr::UGE,
199        LLVMIntPredicate::LLVMIntULT => ICmpPredicateAttr::ULT,
200        LLVMIntPredicate::LLVMIntULE => ICmpPredicateAttr::ULE,
201        LLVMIntPredicate::LLVMIntSGT => ICmpPredicateAttr::SGT,
202        LLVMIntPredicate::LLVMIntSGE => ICmpPredicateAttr::SGE,
203        LLVMIntPredicate::LLVMIntSLT => ICmpPredicateAttr::SLT,
204        LLVMIntPredicate::LLVMIntSLE => ICmpPredicateAttr::SLE,
205    }
206}
207
208pub fn convert_fpredicate(fpred: LLVMRealPredicate) -> FCmpPredicateAttr {
209    match fpred {
210        LLVMRealPredicate::LLVMRealPredicateFalse => FCmpPredicateAttr::False,
211        LLVMRealPredicate::LLVMRealOEQ => FCmpPredicateAttr::OEQ,
212        LLVMRealPredicate::LLVMRealOGT => FCmpPredicateAttr::OGT,
213        LLVMRealPredicate::LLVMRealOGE => FCmpPredicateAttr::OGE,
214        LLVMRealPredicate::LLVMRealOLT => FCmpPredicateAttr::OLT,
215        LLVMRealPredicate::LLVMRealOLE => FCmpPredicateAttr::OLE,
216        LLVMRealPredicate::LLVMRealONE => FCmpPredicateAttr::ONE,
217        LLVMRealPredicate::LLVMRealORD => FCmpPredicateAttr::ORD,
218        LLVMRealPredicate::LLVMRealUNO => FCmpPredicateAttr::UNO,
219        LLVMRealPredicate::LLVMRealUEQ => FCmpPredicateAttr::UEQ,
220        LLVMRealPredicate::LLVMRealUGT => FCmpPredicateAttr::UGT,
221        LLVMRealPredicate::LLVMRealUGE => FCmpPredicateAttr::UGE,
222        LLVMRealPredicate::LLVMRealULT => FCmpPredicateAttr::ULT,
223        LLVMRealPredicate::LLVMRealULE => FCmpPredicateAttr::ULE,
224        LLVMRealPredicate::LLVMRealUNE => FCmpPredicateAttr::UNE,
225        LLVMRealPredicate::LLVMRealPredicateTrue => FCmpPredicateAttr::True,
226    }
227}
228
229pub fn convert_linkage(linkage: LLVMLinkage) -> LinkageAttr {
230    match linkage {
231        LLVMLinkage::LLVMExternalLinkage => LinkageAttr::ExternalLinkage,
232        LLVMLinkage::LLVMAvailableExternallyLinkage => LinkageAttr::AvailableExternallyLinkage,
233        LLVMLinkage::LLVMLinkOnceAnyLinkage => LinkageAttr::LinkOnceAnyLinkage,
234        LLVMLinkage::LLVMLinkOnceODRLinkage => LinkageAttr::LinkOnceODRLinkage,
235        LLVMLinkage::LLVMWeakAnyLinkage => LinkageAttr::WeakAnyLinkage,
236        LLVMLinkage::LLVMWeakODRLinkage => LinkageAttr::WeakODRLinkage,
237        LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage => LinkageAttr::LinkOnceODRAutoHideLinkage,
238        LLVMLinkage::LLVMCommonLinkage => LinkageAttr::CommonLinkage,
239        LLVMLinkage::LLVMAppendingLinkage => LinkageAttr::AppendingLinkage,
240        LLVMLinkage::LLVMInternalLinkage => LinkageAttr::InternalLinkage,
241        LLVMLinkage::LLVMPrivateLinkage => LinkageAttr::PrivateLinkage,
242        LLVMLinkage::LLVMDLLImportLinkage => LinkageAttr::DLLImportLinkage,
243        LLVMLinkage::LLVMDLLExportLinkage => LinkageAttr::DLLExportLinkage,
244        LLVMLinkage::LLVMExternalWeakLinkage => LinkageAttr::ExternalWeakLinkage,
245        LLVMLinkage::LLVMLinkerPrivateLinkage => LinkageAttr::LinkerPrivateLinkage,
246        LLVMLinkage::LLVMLinkerPrivateWeakLinkage => LinkageAttr::LinkerPrivateWeakLinkage,
247        LLVMLinkage::LLVMGhostLinkage => LinkageAttr::GhostLinkage,
248    }
249}
250
251/// Mapping from LLVM entities to pliron entities.
252#[derive(Default)]
253struct ConversionContext {
254    /// A map from LLVM's Values to pliron's Values.
255    value_map: FxHashMap<LLVMValue, Value>,
256    /// A map from LLVM's basic blocks to plirons'.
257    block_map: FxHashMap<LLVMBasicBlock, Ptr<BasicBlock>>,
258    /// Cache already converted types.
259    type_cache: FxHashMap<LLVMType, Ptr<TypeObj>>,
260    /// Insertion point for constants in the entry block.
261    constants_inserter: Option<IRInserter<DummyListener>>,
262    /// Identifier legaliser
263    id_legaliser: identifier::Legaliser,
264}
265
266impl ConversionContext {
267    /// Reset the value and block maps and initialize
268    /// constants inserter to the start of the entry block.
269    /// Identifier::Legaliser remains unmodified.
270    fn reset_for_region(&mut self, entry_block: Ptr<BasicBlock>) {
271        self.constants_inserter = Some(IRInserter::new_at_block_start(entry_block));
272        self.value_map.clear();
273        self.block_map.clear();
274    }
275}
276
277/// Get the successors of an LLVM block.
278fn successors(block: LLVMBasicBlock) -> Vec<LLVMBasicBlock> {
279    let Some(term) = llvm_get_basic_block_terminator(block) else {
280        return vec![];
281    };
282
283    match llvm_get_instruction_opcode(term) {
284        LLVMOpcode::LLVMBr => {
285            if llvm_get_num_operands(term) == 1 {
286                // Conditional branch
287                vec![llvm_value_as_basic_block(llvm_get_operand(term, 0))]
288            } else {
289                assert!(llvm_get_num_operands(term) == 3);
290                vec![
291                    llvm_value_as_basic_block(llvm_get_operand(term, 1)),
292                    llvm_value_as_basic_block(llvm_get_operand(term, 2)),
293                ]
294            }
295        }
296        LLVMOpcode::LLVMSwitch => {
297            // The first two operands are the condition value and the default destination.
298            // After that there are pairs of case value and destination.
299            let num_cases = (llvm_get_num_operands(term) - 2) / 2;
300            let mut succs = vec![llvm_value_as_basic_block(llvm_get_operand(term, 1))];
301            for i in 0..num_cases {
302                succs.push(llvm_value_as_basic_block(llvm_get_operand(
303                    term,
304                    2 + (2 * i) + 1,
305                )));
306            }
307            succs
308        }
309        LLVMOpcode::LLVMRet | LLVMOpcode::LLVMUnreachable => {
310            // No successors.
311            vec![]
312        }
313        _ => {
314            todo!(
315                "Unsupported instruction: {}",
316                llvm_print_value_to_string(term).unwrap_or_default()
317            )
318        }
319    }
320}
321
322/// Return RPO ordering of blocks in an LLVM function.
323fn rpo(function: LLVMValue) -> Vec<LLVMBasicBlock> {
324    let visited = &mut FxHashSet::<LLVMBasicBlock>::default();
325    let mut po = Vec::<LLVMBasicBlock>::new();
326    let mut revpo = Vec::<LLVMBasicBlock>::new();
327
328    fn walk(
329        block: LLVMBasicBlock,
330        visited: &mut FxHashSet<LLVMBasicBlock>,
331        po: &mut Vec<LLVMBasicBlock>,
332    ) {
333        if !visited.insert(block) {
334            // block already visited.
335            return;
336        }
337        // Visit successors before visiting self.
338        for succ in successors(block).into_iter() {
339            walk(succ, visited, po);
340        }
341        // Visit self.
342        po.push(block);
343    }
344
345    // Walk every block (not just entry) since we may have unreachable blocks.
346    for block in basic_block_iter(function) {
347        if visited.contains(&block) {
348            continue;
349        }
350        walk(block, visited, &mut po);
351        // We collect the RPO for this connected component right now
352        // so that the entry block of the function comes first in the final ordering.
353        revpo.extend(po.drain(..).rev());
354    }
355
356    revpo
357}
358
359#[derive(Error, Debug)]
360pub enum ConversionErr {
361    #[error("Unable to get operand with idx {0}")]
362    OpdMissing(usize),
363    #[error("Unable to get successor with idx {0}")]
364    SuccMissing(usize),
365    #[error("PHI node must have argument from predecessor block \"^{0}\"")]
366    PhiArgMissing(String),
367    #[error("Definition for value \"{0}\" not seen yet")]
368    UndefinedValue(String),
369    #[error("Block definition \"^{0}\" not seen yet")]
370    UndefinedBlock(String),
371    #[error("Integer constant has bit-width 0")]
372    ZeroWidthIntConst,
373    #[error("Floating point constant not of floating point type")]
374    FloatConstNotFloatType,
375    #[error("Switch case value is not an integer constant")]
376    SwitchCaseNonIntConst,
377}
378
379/// If a value is a ConstantOp with integer type, return the value.
380fn get_const_op_as_int(ctx: &Context, val: Value) -> Option<IntegerAttr> {
381    let defining_op = val.defining_op()?;
382
383    Operation::get_op::<ConstantOp>(defining_op, ctx).and_then(|const_op| {
384        const_op
385            .get_value(ctx)
386            .downcast_ref::<IntegerAttr>()
387            .cloned()
388    })
389}
390
391/// If a value is a ConstantOp with a 32-bit integer type, return the value.
392fn get_const_op_as_u32(ctx: &Context, val: Value) -> Option<u32> {
393    get_const_op_as_int(ctx, val).and_then(|int_attr| {
394        let int_ty = int_attr.get_type().deref(ctx);
395        // LLVM integers are signless.
396        (int_ty.is_signless() && int_ty.width() == 32).then(|| int_attr.value().to_u32())
397    })
398}
399
400/// Checks if a constant has been processed already, and if not
401/// converts it and puts it in the [ConversionContext::value_map].
402fn process_constant(ctx: &mut Context, cctx: &mut ConversionContext, val: LLVMValue) -> Result<()> {
403    if cctx.value_map.contains_key(&val) {
404        return Ok(());
405    }
406    let ll_ty = llvm_type_of(val);
407    let ty = convert_type(ctx, cctx, ll_ty)?;
408
409    // Insert a new constant instruction in the entry block.
410    fn insert_const_inst(ctx: &mut Context, cctx: &mut ConversionContext, op: Ptr<Operation>) {
411        cctx.constants_inserter
412            .as_mut()
413            .unwrap()
414            .append_operation(ctx, op);
415    }
416
417    match llvm_get_value_kind(val) {
418        LLVMValueKind::LLVMUndefValueValueKind => {
419            let undef_op = UndefOp::new(ctx, ty);
420            insert_const_inst(ctx, cctx, undef_op.get_operation());
421            cctx.value_map.insert(val, undef_op.get_result(ctx));
422        }
423        LLVMValueKind::LLVMPoisonValueKind => {
424            let poison_op = PoisonOp::new(ctx, ty);
425            insert_const_inst(ctx, cctx, poison_op.get_operation());
426            cctx.value_map.insert(val, poison_op.get_result(ctx));
427        }
428        LLVMValueKind::LLVMConstantPointerNullValueKind => {
429            let null_op = ZeroOp::new(ctx, ty);
430            insert_const_inst(ctx, cctx, null_op.get_operation());
431            cctx.value_map.insert(val, null_op.get_result(ctx));
432        }
433        LLVMValueKind::LLVMConstantIntValueKind => {
434            // TODO: Zero extend or sign extend?
435            let u64 = llvm_const_int_get_zext_value(val);
436            let int_ty = TypePtr::<IntegerType>::from_ptr(ty, ctx)?;
437            let width = int_ty.deref(ctx).width() as usize;
438            if width == 0 {
439                return input_err_noloc!(ConversionErr::ZeroWidthIntConst);
440            }
441            let val_attr =
442                IntegerAttr::new(int_ty, APInt::from_u64(u64, NonZero::new(width).unwrap()));
443            let const_op = ConstantOp::new(ctx, Box::new(val_attr));
444            insert_const_inst(ctx, cctx, const_op.get_operation());
445            cctx.value_map.insert(val, const_op.get_result(ctx));
446        }
447        LLVMValueKind::LLVMConstantFPValueKind => {
448            let (fp64, lost_info) = llvm_const_real_get_double(val);
449            assert!(!lost_info, "Lost information when converting FP constant");
450            let val_attr: AttrObj = {
451                let float_ty = &**ty.deref(ctx);
452                let Some(float_ty_attr): Option<&dyn FloatAttrBuilder> = type_cast(float_ty) else {
453                    return input_err_noloc!(ConversionErr::FloatConstNotFloatType);
454                };
455                float_ty_attr.value_from_f64(fp64)
456            };
457            let const_op = ConstantOp::new(ctx, val_attr);
458            insert_const_inst(ctx, cctx, const_op.get_operation());
459            cctx.value_map.insert(val, const_op.get_result(ctx));
460        }
461        LLVMValueKind::LLVMConstantArrayValueKind
462        | LLVMValueKind::LLVMConstantDataArrayValueKind => {
463            fn get_operand(val: LLVMValue, index: u32) -> Result<LLVMValue> {
464                if matches!(
465                    llvm_get_value_kind(val),
466                    LLVMValueKind::LLVMConstantDataArrayValueKind
467                ) {
468                    llvm_get_aggregate_element(val, index).ok_or_else(|| {
469                        input_error_noloc!("LLVMConstantDataArrayValueKind does not have an element at index {index}")
470                    })
471                } else {
472                    Ok(llvm_get_operand(val, index))
473                }
474            }
475            let mut field_vals = vec![];
476            let num_elements = llvm_get_array_length2(ll_ty);
477            for i in 0..num_elements {
478                let field_val = get_operand(val, i.try_into().unwrap())?;
479                process_constant(ctx, cctx, field_val)?;
480                let Some(m_val) = cctx.value_map.get(&field_val) else {
481                    panic!("We just processed this constant, it must be in the map");
482                };
483                field_vals.push(*m_val);
484            }
485            // Starting with an Undef value, we insert elements, for each field.
486            let undef_op = UndefOp::new(ctx, ty);
487            insert_const_inst(ctx, cctx, undef_op.get_operation());
488            let (ctx, const_array) = field_vals.iter().enumerate().try_fold(
489                (ctx, undef_op.get_operation()),
490                |(ctx, acc), (field_idx, field_val)| -> Result<_> {
491                    let acc_val = acc.deref(ctx).get_result(0);
492                    let insert_op = InsertValueOp::new(
493                        ctx,
494                        acc_val,
495                        *field_val,
496                        vec![field_idx.try_into().unwrap()],
497                    )
498                    .get_operation();
499                    insert_const_inst(ctx, cctx, insert_op);
500                    Ok((ctx, insert_op))
501                },
502            )?;
503
504            cctx.value_map
505                .insert(val, const_array.deref(ctx).get_result(0));
506        }
507        LLVMValueKind::LLVMConstantStructValueKind => {
508            let mut field_vals = vec![];
509            let num_fields = llvm_count_struct_element_types(ll_ty);
510            for i in 0..num_fields {
511                let field_val = llvm_get_operand(val, i);
512                process_constant(ctx, cctx, field_val)?;
513                let Some(m_val) = cctx.value_map.get(&field_val) else {
514                    panic!("We just processed this constant, it must be in the map");
515                };
516                field_vals.push(*m_val);
517            }
518            // Starting with an Undef value, we insert elements, for each field.
519            let undef_op = UndefOp::new(ctx, ty);
520            insert_const_inst(ctx, cctx, undef_op.get_operation());
521            let (ctx, const_struct) = field_vals.iter().enumerate().try_fold(
522                (ctx, undef_op.get_operation()),
523                |(ctx, acc), (field_idx, field_val)| -> Result<_> {
524                    let acc_val = acc.deref(ctx).get_result(0);
525                    let insert_op = InsertValueOp::new(
526                        ctx,
527                        acc_val,
528                        *field_val,
529                        vec![field_idx.try_into().unwrap()],
530                    )
531                    .get_operation();
532                    insert_const_inst(ctx, cctx, insert_op);
533                    Ok((ctx, insert_op))
534                },
535            )?;
536
537            cctx.value_map
538                .insert(val, const_struct.deref(ctx).get_result(0));
539        }
540        LLVMValueKind::LLVMConstantExprValueKind => {
541            let opcode = llvm_get_const_opcode(val);
542            match opcode {
543                LLVMOpcode::LLVMBitCast => {
544                    let opd = llvm_get_operand(val, 0);
545                    process_constant(ctx, cctx, opd)?;
546                    let Some(m_val) = cctx.value_map.get(&opd) else {
547                        panic!("We just processed this constant, it must be in the map");
548                    };
549                    let cast_op = BitcastOp::new(ctx, *m_val, ty);
550                    insert_const_inst(ctx, cctx, cast_op.get_operation());
551                    cctx.value_map.insert(val, cast_op.get_result(ctx));
552                }
553                LLVMOpcode::LLVMIntToPtr => {
554                    let opd = llvm_get_operand(val, 0);
555                    process_constant(ctx, cctx, opd)?;
556                    let Some(m_val) = cctx.value_map.get(&opd) else {
557                        panic!("We just processed this constant, it must be in the map");
558                    };
559                    let cast_op = IntToPtrOp::new(ctx, *m_val, ty);
560                    insert_const_inst(ctx, cctx, cast_op.get_operation());
561                    cctx.value_map.insert(val, cast_op.get_result(ctx));
562                }
563                LLVMOpcode::LLVMPtrToInt => {
564                    let opd = llvm_get_operand(val, 0);
565                    process_constant(ctx, cctx, opd)?;
566                    let Some(m_val) = cctx.value_map.get(&opd) else {
567                        panic!("We just processed this constant, it must be in the map");
568                    };
569                    let cast_op = PtrToIntOp::new(ctx, *m_val, ty);
570                    insert_const_inst(ctx, cctx, cast_op.get_operation());
571                    cctx.value_map.insert(val, cast_op.get_result(ctx));
572                }
573                LLVMOpcode::LLVMTrunc => {
574                    let opd = llvm_get_operand(val, 0);
575                    process_constant(ctx, cctx, opd)?;
576                    let Some(m_val) = cctx.value_map.get(&opd).cloned() else {
577                        panic!("We just processed this constant, it must be in the map");
578                    };
579                    let trunc_op = TruncOp::new(ctx, m_val, ty);
580                    insert_const_inst(ctx, cctx, trunc_op.get_operation());
581                    cctx.value_map.insert(val, trunc_op.get_result(ctx));
582                }
583                LLVMOpcode::LLVMGetElementPtr => {
584                    let base = llvm_get_operand(val, 0);
585                    process_constant(ctx, cctx, base)?;
586                    let Some(m_base) = cctx.value_map.get(&base).cloned() else {
587                        panic!("We just processed this constant, it must be in the map");
588                    };
589                    let mut indices = vec![];
590                    for i in 1..llvm_get_num_operands(val) {
591                        let opd = llvm_get_operand(val, i);
592                        process_constant(ctx, cctx, opd)?;
593                        let Some(m_val) = cctx.value_map.get(&opd) else {
594                            panic!("We just processed this constant, it must be in the map");
595                        };
596                        if let Some(c) = get_const_op_as_u32(ctx, *m_val) {
597                            indices.push(GepIndex::Constant(c));
598                        } else {
599                            indices.push(GepIndex::Value(*m_val));
600                        }
601                    }
602                    let src_elm_type =
603                        convert_type(ctx, cctx, llvm_get_gep_source_element_type(val))?;
604                    let gep_op = GetElementPtrOp::new(ctx, m_base, indices, src_elm_type);
605                    insert_const_inst(ctx, cctx, gep_op.get_operation());
606                    cctx.value_map.insert(val, gep_op.get_result(ctx));
607                }
608                LLVMOpcode::LLVMAdd | LLVMOpcode::LLVMSub => {
609                    let (lhs, rhs) = (llvm_get_operand(val, 0), llvm_get_operand(val, 1));
610                    process_constant(ctx, cctx, lhs)?;
611                    process_constant(ctx, cctx, rhs)?;
612                    let Some(m_lhs) = cctx.value_map.get(&lhs).cloned() else {
613                        panic!("We just processed this constant, it must be in the map");
614                    };
615                    let Some(m_rhs) = cctx.value_map.get(&rhs).cloned() else {
616                        panic!("We just processed this constant, it must be in the map");
617                    };
618                    // `Instruction *ConstantExpr::getAsInstruction() const ` just sets no flags.
619                    let flags = IntegerOverflowFlagsAttr::default();
620                    let (op, res_val) = if opcode == LLVMOpcode::LLVMAdd {
621                        let op = AddOp::new(ctx, m_lhs, m_rhs);
622                        op.set_integer_overflow_flag(ctx, flags);
623                        (op.get_operation(), op.get_result(ctx))
624                    } else {
625                        let op = SubOp::new(ctx, m_lhs, m_rhs);
626                        op.set_integer_overflow_flag(ctx, flags);
627                        (op.get_operation(), op.get_result(ctx))
628                    };
629                    insert_const_inst(ctx, cctx, op);
630                    cctx.value_map.insert(val, res_val);
631                }
632                _ => {
633                    todo!("Unsupported constant expression opcode: {:?}", opcode)
634                }
635            }
636        }
637        LLVMValueKind::LLVMGlobalVariableValueKind => {
638            let global_name = llvm_get_value_name(val).unwrap_or_default();
639            let global_name = cctx.id_legaliser.legalise(&global_name);
640            let global_op = AddressOfOp::new(ctx, global_name);
641            insert_const_inst(ctx, cctx, global_op.get_operation());
642            cctx.value_map.insert(val, global_op.get_result(ctx));
643        }
644        LLVMValueKind::LLVMFunctionValueKind => {
645            let fn_name = llvm_get_value_name(val).unwrap_or_default();
646            let fn_name = cctx.id_legaliser.legalise(&fn_name);
647            let func_op = AddressOfOp::new(ctx, fn_name);
648            insert_const_inst(ctx, cctx, func_op.get_operation());
649            cctx.value_map.insert(val, func_op.get_result(ctx));
650        }
651        LLVMValueKind::LLVMConstantAggregateZeroValueKind => {
652            let zero_op = ZeroOp::new(ctx, ty);
653            insert_const_inst(ctx, cctx, zero_op.get_operation());
654            cctx.value_map.insert(val, zero_op.get_result(ctx));
655        }
656        LLVMValueKind::LLVMConstantVectorValueKind
657        | LLVMValueKind::LLVMConstantDataVectorValueKind => {
658            let num_elements = llvm_get_vector_size(ll_ty);
659            let mut element_vals = vec![];
660            for i in 0..num_elements {
661                let element_val = llvm_get_aggregate_element(val, i)
662                    .expect("Constant vector must have element at index");
663                process_constant(ctx, cctx, element_val)?;
664                let Some(m_val) = cctx.value_map.get(&element_val) else {
665                    panic!("We just processed this constant, it must be in the map");
666                };
667                element_vals.push(*m_val);
668            }
669            // Starting with an Undef value, we insert elements, for each element.
670            let undef_op = UndefOp::new(ctx, ty);
671            let ty_int32 = TypePtr::<IntegerType>::from_ptr(
672                IntegerType::get(ctx, 32, Signedness::Signless).into(),
673                ctx,
674            )?;
675            insert_const_inst(ctx, cctx, undef_op.get_operation());
676            let const_vector = element_vals.iter().enumerate().try_fold(
677                undef_op.get_operation(),
678                |acc, (elem_idx, elem_val)| -> Result<_> {
679                    let acc_val = acc.deref(ctx).get_result(0);
680                    // The index needs to be a [Value], so we create a ConstantOp for it.
681                    let idx_attr = IntegerAttr::new(
682                        ty_int32,
683                        APInt::from_u64(elem_idx.try_into().unwrap(), NonZero::new(32).unwrap()),
684                    );
685                    let idx_const_op = ConstantOp::new(ctx, Box::new(idx_attr)).get_operation();
686                    insert_const_inst(ctx, cctx, idx_const_op);
687                    let idx_val = idx_const_op.deref(ctx).get_result(0);
688                    let insert_op =
689                        InsertElementOp::new(ctx, acc_val, *elem_val, idx_val).get_operation();
690                    insert_const_inst(ctx, cctx, insert_op);
691                    Ok(insert_op)
692                },
693            )?;
694            cctx.value_map
695                .insert(val, const_vector.deref(ctx).get_result(0));
696        }
697        LLVMValueKind::LLVMArgumentValueKind => todo!(),
698        LLVMValueKind::LLVMBasicBlockValueKind => todo!(),
699        LLVMValueKind::LLVMMemoryUseValueKind => todo!(),
700        LLVMValueKind::LLVMMemoryDefValueKind => todo!(),
701        LLVMValueKind::LLVMMemoryPhiValueKind => todo!(),
702        LLVMValueKind::LLVMGlobalAliasValueKind => todo!(),
703        LLVMValueKind::LLVMGlobalIFuncValueKind => todo!(),
704        LLVMValueKind::LLVMBlockAddressValueKind => todo!(),
705        LLVMValueKind::LLVMConstantTokenNoneValueKind => todo!(),
706        LLVMValueKind::LLVMMetadataAsValueValueKind => todo!(),
707        LLVMValueKind::LLVMInlineAsmValueKind => todo!(),
708        LLVMValueKind::LLVMInstructionValueKind => todo!(),
709        LLVMValueKind::LLVMConstantTargetNoneValueKind => todo!(),
710        LLVMValueKind::LLVMConstantPtrAuthValueKind => todo!(),
711    }
712    Ok(())
713}
714
715fn convert_operands(
716    ctx: &mut Context,
717    cctx: &mut ConversionContext,
718    operands: &[LLVMValue],
719) -> Result<(Vec<Value>, Vec<Ptr<BasicBlock>>)> {
720    let mut opds = vec![];
721    let mut succs = vec![];
722
723    for opd in operands.iter().cloned() {
724        if !llvm_value_is_basic_block(opd) {
725            process_constant(ctx, cctx, opd)?;
726            if let Some(m_val) = cctx.value_map.get(&opd) {
727                opds.push(*m_val);
728            } else {
729                return input_err_noloc!(ConversionErr::UndefinedValue(
730                    llvm_get_value_name(opd).unwrap_or_default()
731                ));
732            }
733        } else {
734            let block = llvm_value_as_basic_block(opd);
735            let Some(m_block) = cctx.block_map.get(&block) else {
736                return input_err_noloc!(ConversionErr::UndefinedBlock(
737                    llvm_get_basic_block_name(block).unwrap_or_default()
738                ));
739            };
740            succs.push(*m_block);
741        }
742    }
743    Ok((opds, succs))
744}
745
746fn get_operand<T: Clone>(opds: &[T], idx: usize) -> Result<T> {
747    opds.get(idx)
748        .ok_or_else(|| input_error_noloc!(ConversionErr::OpdMissing(idx)))
749        .cloned()
750}
751
752/// Compute the arguments to be passed when branching from `src` to `dest`.
753fn convert_branch_args(
754    ctx: &mut Context,
755    cctx: &mut ConversionContext,
756    src_block: LLVMBasicBlock,
757    dst_block: LLVMBasicBlock,
758) -> Result<Vec<Value>> {
759    let mut args = vec![];
760    for inst in instruction_iter(dst_block) {
761        if llvm_is_a::phi_node(inst) {
762            let Some((incoming_val, _)) =
763                incoming_iter(inst).find(|(_, block)| *block == src_block)
764            else {
765                return input_err_noloc!(ConversionErr::PhiArgMissing(
766                    llvm_get_basic_block_name(src_block).unwrap_or_default()
767                ));
768            };
769            process_constant(ctx, cctx, incoming_val)?;
770            let Some(m_incoming_val) = cctx.value_map.get(&incoming_val) else {
771                return input_err_noloc!(ConversionErr::UndefinedValue(
772                    llvm_get_value_name(incoming_val).unwrap_or_default()
773                ));
774            };
775            args.push(*m_incoming_val)
776        } else {
777            // PHIs are at the start of the block.
778            break;
779        }
780    }
781    Ok(args)
782}
783
784fn convert_call(
785    ctx: &mut Context,
786    cctx: &mut ConversionContext,
787    inst: LLVMValue,
788) -> Result<Ptr<Operation>> {
789    let llvm_operands: Vec<_> = (0..llvm_get_num_arg_operands(inst))
790        .map(|opd_idx| llvm_get_operand(inst, opd_idx))
791        .collect();
792    let (args, _) = convert_operands(ctx, cctx, &llvm_operands)?;
793
794    let callee = llvm_get_called_value(inst);
795
796    enum Callee {
797        FnCall(CallOpCallable),
798        IntrinsicCall(String),
799    }
800    let callee = if llvm_is_a::function(callee) {
801        let llvm_fn_name =
802            llvm_get_value_name(callee).expect("Unable to obtain valid function name");
803        if llvm_lookup_intrinsic_id(&llvm_fn_name).is_some() {
804            Callee::IntrinsicCall(llvm_fn_name)
805        } else {
806            let fn_name = cctx.id_legaliser.legalise(&llvm_fn_name);
807            Callee::FnCall(CallOpCallable::Direct(fn_name))
808        }
809    } else {
810        let (callee_converted, _) = convert_operands(ctx, cctx, &[callee])?;
811        Callee::FnCall(CallOpCallable::Indirect(callee_converted[0]))
812    };
813
814    let callee_ty = llvm_get_called_function_type(inst);
815    let callee_ty: TypePtr<FuncType> =
816        convert_type(ctx, cctx, callee_ty).and_then(|ty| TypePtr::from_ptr(ty, ctx))?;
817
818    let fmf: Option<FastmathFlagsAttr> = if llvm_can_value_use_fast_math_flags(inst) {
819        // Not all calls can have fast-math flags.
820        let fmf = llvm_get_fast_math_flags(inst);
821        (!fmf.is_empty()).then_some(fmf.into())
822    } else {
823        None
824    };
825
826    let op = match callee {
827        Callee::FnCall(callable) => {
828            let op = CallOp::new(ctx, callable, callee_ty, args);
829            if let Some(fmf) = fmf {
830                op.set_attr_llvm_call_fastmath_flags(ctx, fmf);
831            }
832            op.get_operation()
833        }
834        Callee::IntrinsicCall(name) => {
835            let op = CallIntrinsicOp::new(ctx, name.into(), callee_ty, args);
836            if let Some(fmf) = fmf {
837                op.set_attr_llvm_intrinsic_fastmath_flags(ctx, fmf);
838            }
839            op.get_operation()
840        }
841    };
842
843    Ok(op)
844}
845
846fn convert_instruction(
847    ctx: &mut Context,
848    cctx: &mut ConversionContext,
849    inst: LLVMValue,
850) -> Result<Ptr<Operation>> {
851    if llvm_is_a::call_inst(inst) {
852        return convert_call(ctx, cctx, inst);
853    }
854
855    fn get_integer_overflow_flag(inst: LLVMValue) -> IntegerOverflowFlagsAttr {
856        let mut flags = IntegerOverflowFlagsAttr::default();
857        if llvm_get_nsw(inst) {
858            flags.nsw = true;
859        }
860        if llvm_get_nuw(inst) {
861            flags.nuw = true;
862        }
863        flags
864    }
865
866    let llvm_operands: Vec<_> = (0..llvm_get_num_operands(inst))
867        .map(|opd_idx| llvm_get_operand(inst, opd_idx))
868        .collect();
869
870    let (ref opds, ref succs) = convert_operands(ctx, cctx, &llvm_operands)?;
871    match llvm_get_instruction_opcode(inst) {
872        LLVMOpcode::LLVMAdd => {
873            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
874            Ok(
875                AddOp::new_with_overflow_flag(ctx, lhs, rhs, get_integer_overflow_flag(inst))
876                    .get_operation(),
877            )
878        }
879        LLVMOpcode::LLVMAddrSpaceCast => todo!(),
880        LLVMOpcode::LLVMAlloca => {
881            let elem_type = convert_type(ctx, cctx, llvm_get_allocated_type(inst))?;
882            let size = get_operand(opds, 0)?;
883            let op = AllocaOp::new(ctx, elem_type, size);
884            let alignment = llvm_get_alignment(inst);
885            if alignment != 0 {
886                op.set_alignment(ctx, alignment);
887            }
888            Ok(op.get_operation())
889        }
890        LLVMOpcode::LLVMAnd => {
891            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
892            Ok(AndOp::new(ctx, lhs, rhs).get_operation())
893        }
894        LLVMOpcode::LLVMAShr => {
895            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
896            Ok(AShrOp::new(ctx, lhs, rhs).get_operation())
897        }
898        LLVMOpcode::LLVMAtomicCmpXchg => todo!(),
899        LLVMOpcode::LLVMAtomicRMW => todo!(),
900        LLVMOpcode::LLVMBitCast => {
901            let arg = get_operand(opds, 0)?;
902            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
903            Ok(BitcastOp::new(ctx, arg, res_ty).get_operation())
904        }
905        LLVMOpcode::LLVMBr => {
906            if !opds.is_empty() {
907                assert!(
908                    succs.len() == 2,
909                    "Conditional branch must have two successors"
910                );
911                let true_dest_opds = convert_branch_args(
912                    ctx,
913                    cctx,
914                    llvm_get_instruction_parent(inst).unwrap(),
915                    llvm_value_as_basic_block(llvm_get_operand(inst, 2)),
916                )?;
917                let false_dest_opds = convert_branch_args(
918                    ctx,
919                    cctx,
920                    llvm_get_instruction_parent(inst).unwrap(),
921                    llvm_value_as_basic_block(llvm_get_operand(inst, 1)),
922                )?;
923                Ok(CondBrOp::new(
924                    ctx,
925                    get_operand(opds, 0)?,
926                    get_operand(succs, 1)?,
927                    true_dest_opds,
928                    get_operand(succs, 0)?,
929                    false_dest_opds,
930                )
931                .get_operation())
932            } else {
933                let dest_opds = convert_branch_args(
934                    ctx,
935                    cctx,
936                    llvm_get_instruction_parent(inst).unwrap(),
937                    llvm_value_as_basic_block(llvm_get_operand(inst, 0)),
938                )?;
939                Ok(BrOp::new(ctx, get_operand(succs, 0)?, dest_opds).get_operation())
940            }
941        }
942        LLVMOpcode::LLVMCall => {
943            unreachable!("Should've already been processed separately")
944        }
945        LLVMOpcode::LLVMCallBr => todo!(),
946        LLVMOpcode::LLVMCatchPad => todo!(),
947        LLVMOpcode::LLVMCatchRet => todo!(),
948        LLVMOpcode::LLVMCatchSwitch => todo!(),
949        LLVMOpcode::LLVMCleanupPad => todo!(),
950        LLVMOpcode::LLVMCleanupRet => todo!(),
951        LLVMOpcode::LLVMFNeg => {
952            let arg = get_operand(opds, 0)?;
953            Ok(
954                FNegOp::new_with_fast_math_flags(ctx, arg, llvm_get_fast_math_flags(inst).into())
955                    .get_operation(),
956            )
957        }
958        LLVMOpcode::LLVMFAdd => {
959            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
960            Ok(FAddOp::new_with_fast_math_flags(
961                ctx,
962                lhs,
963                rhs,
964                llvm_get_fast_math_flags(inst).into(),
965            )
966            .get_operation())
967        }
968        LLVMOpcode::LLVMFCmp => {
969            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
970            let pred = convert_fpredicate(llvm_get_fcmp_predicate(inst));
971            let fastmath = llvm_get_fast_math_flags(inst);
972            let op = FCmpOp::new(ctx, pred, lhs, rhs);
973            op.set_fast_math_flags(ctx, fastmath.into());
974            Ok(op.get_operation())
975        }
976        LLVMOpcode::LLVMFDiv => {
977            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
978            Ok(FDivOp::new_with_fast_math_flags(
979                ctx,
980                lhs,
981                rhs,
982                llvm_get_fast_math_flags(inst).into(),
983            )
984            .get_operation())
985        }
986        LLVMOpcode::LLVMFMul => {
987            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
988            Ok(FMulOp::new_with_fast_math_flags(
989                ctx,
990                lhs,
991                rhs,
992                llvm_get_fast_math_flags(inst).into(),
993            )
994            .get_operation())
995        }
996        LLVMOpcode::LLVMFRem => {
997            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
998            Ok(FRemOp::new_with_fast_math_flags(
999                ctx,
1000                lhs,
1001                rhs,
1002                llvm_get_fast_math_flags(inst).into(),
1003            )
1004            .get_operation())
1005        }
1006        LLVMOpcode::LLVMFSub => {
1007            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1008            Ok(FSubOp::new_with_fast_math_flags(
1009                ctx,
1010                lhs,
1011                rhs,
1012                llvm_get_fast_math_flags(inst).into(),
1013            )
1014            .get_operation())
1015        }
1016        LLVMOpcode::LLVMFPExt => {
1017            let arg = get_operand(opds, 0)?;
1018            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1019            let op = FPExtOp::new(ctx, arg, res_ty);
1020            op.set_fast_math_flags(ctx, llvm_get_fast_math_flags(inst).into());
1021            Ok(op.get_operation())
1022        }
1023        LLVMOpcode::LLVMFPTrunc => {
1024            let arg = get_operand(opds, 0)?;
1025            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1026            let op = FPTruncOp::new(ctx, arg, res_ty);
1027            op.set_fast_math_flags(ctx, llvm_get_fast_math_flags(inst).into());
1028            Ok(op.get_operation())
1029        }
1030        LLVMOpcode::LLVMFPToSI => {
1031            let arg = get_operand(opds, 0)?;
1032            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1033            Ok(FPToSIOp::new(ctx, arg, res_ty).get_operation())
1034        }
1035        LLVMOpcode::LLVMFPToUI => {
1036            let arg = get_operand(opds, 0)?;
1037            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1038            Ok(FPToUIOp::new(ctx, arg, res_ty).get_operation())
1039        }
1040        LLVMOpcode::LLVMSIToFP => {
1041            let arg = get_operand(opds, 0)?;
1042            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1043            Ok(SIToFPOp::new(ctx, arg, res_ty).get_operation())
1044        }
1045        LLVMOpcode::LLVMUIToFP => {
1046            let arg = get_operand(opds, 0)?;
1047            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1048            let nneg = llvm_get_nneg(inst);
1049            Ok(UIToFPOp::new_with_nneg(ctx, arg, res_ty, nneg).get_operation())
1050        }
1051        LLVMOpcode::LLVMFence => todo!(),
1052        LLVMOpcode::LLVMFreeze => {
1053            let arg = get_operand(opds, 0)?;
1054            Ok(FreezeOp::new(ctx, arg).get_operation())
1055        }
1056        LLVMOpcode::LLVMGetElementPtr => {
1057            let mut opds = opds.iter();
1058            let base = opds
1059                .next()
1060                .ok_or_else(|| input_error_noloc!(ConversionErr::OpdMissing(0)))?;
1061            let indices = opds
1062                .map(|v| {
1063                    if let Some(c) = get_const_op_as_u32(ctx, *v) {
1064                        GepIndex::Constant(c)
1065                    } else {
1066                        GepIndex::Value(*v)
1067                    }
1068                })
1069                .collect::<Vec<_>>();
1070            let src_elm_type = convert_type(ctx, cctx, llvm_get_gep_source_element_type(inst))?;
1071            Ok(GetElementPtrOp::new(ctx, *base, indices, src_elm_type).get_operation())
1072        }
1073        LLVMOpcode::LLVMICmp => {
1074            let pred = convert_ipredicate(llvm_get_icmp_predicate(inst));
1075            Ok(
1076                ICmpOp::new(ctx, pred, get_operand(opds, 0)?, get_operand(opds, 1)?)
1077                    .get_operation(),
1078            )
1079        }
1080        LLVMOpcode::LLVMIndirectBr => todo!(),
1081        LLVMOpcode::LLVMInsertElement => {
1082            let vector = get_operand(opds, 0)?;
1083            let element = get_operand(opds, 1)?;
1084            let index = get_operand(opds, 2)?;
1085            Ok(InsertElementOp::new(ctx, vector, element, index).get_operation())
1086        }
1087        LLVMOpcode::LLVMExtractElement => {
1088            let vector = get_operand(opds, 0)?;
1089            let index = get_operand(opds, 1)?;
1090            Ok(ExtractElementOp::new(ctx, vector, index).get_operation())
1091        }
1092        LLVMOpcode::LLVMShuffleVector => {
1093            let vec1 = get_operand(opds, 0)?;
1094            let vec2 = get_operand(opds, 1)?;
1095            let num_mask_elems = llvm_get_num_mask_elements(inst);
1096            let mask = (0..num_mask_elems)
1097                .map(|i| llvm_get_mask_value(inst, i))
1098                .collect();
1099            Ok(ShuffleVectorOp::new(ctx, vec1, vec2, mask).get_operation())
1100        }
1101        LLVMOpcode::LLVMInsertValue => {
1102            let (aggr, val) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1103            let indices = llvm_get_indices(inst);
1104            Ok(InsertValueOp::new(ctx, aggr, val, indices).get_operation())
1105        }
1106        LLVMOpcode::LLVMExtractValue => {
1107            let aggr = get_operand(opds, 0)?;
1108            let indices = llvm_get_indices(inst);
1109            Ok(ExtractValueOp::new(ctx, aggr, indices)?.get_operation())
1110        }
1111        LLVMOpcode::LLVMIntToPtr => {
1112            let arg = get_operand(opds, 0)?;
1113            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1114            Ok(IntToPtrOp::new(ctx, arg, res_ty).get_operation())
1115        }
1116        LLVMOpcode::LLVMInvoke => todo!(),
1117        LLVMOpcode::LLVMLandingPad => todo!(),
1118        LLVMOpcode::LLVMLoad => {
1119            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1120            let load_op = LoadOp::new(ctx, get_operand(opds, 0)?, res_ty);
1121            let alignment = llvm_get_alignment(inst);
1122            if alignment != 0 {
1123                load_op.set_alignment(ctx, alignment);
1124            }
1125            Ok(load_op.get_operation())
1126        }
1127        LLVMOpcode::LLVMLShr => {
1128            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1129            Ok(LShrOp::new(ctx, lhs, rhs).get_operation())
1130        }
1131        LLVMOpcode::LLVMMul => {
1132            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1133            Ok(
1134                MulOp::new_with_overflow_flag(ctx, lhs, rhs, get_integer_overflow_flag(inst))
1135                    .get_operation(),
1136            )
1137        }
1138        LLVMOpcode::LLVMOr => {
1139            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1140            Ok(OrOp::new(ctx, lhs, rhs).get_operation())
1141        }
1142        LLVMOpcode::LLVMPHI => {
1143            unreachable!("PHI nodes must already be handled")
1144        }
1145        LLVMOpcode::LLVMPtrToInt => {
1146            let arg = get_operand(opds, 0)?;
1147            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1148            Ok(PtrToIntOp::new(ctx, arg, res_ty).get_operation())
1149        }
1150        LLVMOpcode::LLVMPtrToAddr => {
1151            unimplemented!("LLVM-C does not have LLVMBuildPtrToAddr yet")
1152        }
1153        LLVMOpcode::LLVMResume => todo!(),
1154        LLVMOpcode::LLVMRet => {
1155            let retval = if llvm_get_num_operands(inst) == 1 {
1156                Some(get_operand(opds, 0)?)
1157            } else {
1158                None
1159            };
1160            Ok(ReturnOp::new(ctx, retval).get_operation())
1161        }
1162        LLVMOpcode::LLVMSDiv => {
1163            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1164            Ok(SDivOp::new(ctx, lhs, rhs).get_operation())
1165        }
1166        LLVMOpcode::LLVMSelect => {
1167            let (cond, true_val, false_val) = (
1168                get_operand(opds, 0)?,
1169                get_operand(opds, 1)?,
1170                get_operand(opds, 2)?,
1171            );
1172            Ok(SelectOp::new(ctx, cond, true_val, false_val).get_operation())
1173        }
1174        LLVMOpcode::LLVMSExt => {
1175            let arg = get_operand(opds, 0)?;
1176            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1177            Ok(SExtOp::new(ctx, arg, res_ty).get_operation())
1178        }
1179        LLVMOpcode::LLVMZExt => {
1180            let arg = get_operand(opds, 0)?;
1181            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1182            let nneg = llvm_get_nneg(inst);
1183            Ok(ZExtOp::new_with_nneg(ctx, arg, res_ty, nneg).get_operation())
1184        }
1185        LLVMOpcode::LLVMTrunc => {
1186            let arg = get_operand(opds, 0)?;
1187            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1188            Ok(TruncOp::new(ctx, arg, res_ty).get_operation())
1189        }
1190        LLVMOpcode::LLVMShl => {
1191            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1192            Ok(
1193                ShlOp::new_with_overflow_flag(ctx, lhs, rhs, get_integer_overflow_flag(inst))
1194                    .get_operation(),
1195            )
1196        }
1197        LLVMOpcode::LLVMSRem => {
1198            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1199            Ok(SRemOp::new(ctx, lhs, rhs).get_operation())
1200        }
1201        LLVMOpcode::LLVMStore => {
1202            let (value_opd, ptr_opd) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1203            let store_op = StoreOp::new(ctx, value_opd, ptr_opd);
1204            let alignment = llvm_get_alignment(inst);
1205            if alignment != 0 {
1206                store_op.set_alignment(ctx, alignment);
1207            }
1208            Ok(store_op.get_operation())
1209        }
1210        LLVMOpcode::LLVMSub => {
1211            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1212            Ok(
1213                SubOp::new_with_overflow_flag(ctx, lhs, rhs, get_integer_overflow_flag(inst))
1214                    .get_operation(),
1215            )
1216        }
1217        LLVMOpcode::LLVMSwitch => {
1218            let cond = get_operand(opds, 0)?;
1219            let default_dest = succs
1220                .first()
1221                .ok_or_else(|| input_error_noloc!(ConversionErr::SuccMissing(0)))?;
1222            let num_cases = succs.len() - 1;
1223            // Case values aren't stored as operands, but we can get them using `llvm_get_switch_case_value`.
1224            let mut case_values = vec![];
1225            // Case 0 is the default destination, so we start with 1.
1226            for case_idx in 1..=num_cases {
1227                let case_value = llvm_get_switch_case_value(inst, case_idx.try_into().unwrap());
1228                process_constant(ctx, cctx, case_value)?;
1229                let Some(case_value) = cctx.value_map.get(&case_value) else {
1230                    return input_err_noloc!(ConversionErr::SwitchCaseNonIntConst);
1231                };
1232                case_values.push(*case_value);
1233            }
1234            let cases = case_values
1235                .iter()
1236                // Skip the first successor which is the default destination
1237                .zip(succs.iter().skip(1))
1238                .enumerate()
1239                .map(|(case_idx, (case_val, dest_block))| {
1240                    let case_val = get_const_op_as_int(ctx, *case_val).ok_or_else(|| {
1241                        input_error_noloc!("Switch case value must be a constant integer")
1242                    })?;
1243                    let case_idx: u32 = case_idx.try_into().unwrap();
1244                    // Operand 0 is the condition and operand 1 is the default destination,
1245                    // so case destinations start at operand index 2.
1246                    let llvm_dest = llvm_value_as_basic_block(llvm_get_operand(inst, 2 + case_idx));
1247                    assert!(
1248                        cctx.block_map.get(&llvm_dest).unwrap() == dest_block,
1249                        "Switch case destination block does not match the expected block"
1250                    );
1251                    let case_args = convert_branch_args(
1252                        ctx,
1253                        cctx,
1254                        llvm_get_instruction_parent(inst).unwrap(),
1255                        llvm_dest,
1256                    )?;
1257                    Ok(SwitchCase {
1258                        value: case_val,
1259                        dest: *dest_block,
1260                        dest_opds: case_args,
1261                    })
1262                })
1263                .collect::<Result<Vec<_>>>()?;
1264            let default_dest_args = convert_branch_args(
1265                ctx,
1266                cctx,
1267                llvm_get_instruction_parent(inst).unwrap(),
1268                llvm_value_as_basic_block(llvm_get_operand(inst, 1)),
1269            )?;
1270            Ok(SwitchOp::new(ctx, cond, *default_dest, default_dest_args, cases).get_operation())
1271        }
1272        LLVMOpcode::LLVMUDiv => {
1273            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1274            Ok(UDivOp::new(ctx, lhs, rhs).get_operation())
1275        }
1276        LLVMOpcode::LLVMUnreachable => Ok(UnreachableOp::new(ctx).get_operation()),
1277        LLVMOpcode::LLVMURem => {
1278            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1279            Ok(URemOp::new(ctx, lhs, rhs).get_operation())
1280        }
1281        LLVMOpcode::LLVMVAArg => {
1282            let arg = get_operand(opds, 0)?;
1283            let res_ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1284            Ok(VAArgOp::new(ctx, arg, res_ty).get_operation())
1285        }
1286        LLVMOpcode::LLVMUserOp1 => todo!(),
1287        LLVMOpcode::LLVMUserOp2 => todo!(),
1288
1289        LLVMOpcode::LLVMXor => {
1290            let (lhs, rhs) = (get_operand(opds, 0)?, get_operand(opds, 1)?);
1291            Ok(XorOp::new(ctx, lhs, rhs).get_operation())
1292        }
1293    }
1294}
1295
1296/// Convert [LLVMBasicBlock] to pliron's [BasicBlock].
1297fn convert_block(
1298    ctx: &mut Context,
1299    cctx: &mut ConversionContext,
1300    block: LLVMBasicBlock,
1301    m_block: Ptr<BasicBlock>,
1302) -> Result<()> {
1303    let mut inserter = IRInserter::<DummyListener>::new_at_block_end(m_block);
1304    for inst in instruction_iter(block) {
1305        if llvm_get_instruction_opcode(inst) == LLVMOpcode::LLVMPHI {
1306            let ty = convert_type(ctx, cctx, llvm_type_of(inst))?;
1307            let arg_idx = BasicBlock::push_argument(m_block, ctx, ty);
1308            cctx.value_map
1309                .insert(inst, m_block.deref(ctx).get_argument(arg_idx));
1310        } else {
1311            let m_inst = convert_instruction(ctx, cctx, inst)?;
1312            inserter.insert_operation(ctx, m_inst);
1313            let m_inst_result = m_inst.deref(ctx).results().next();
1314            // LLVM instructions have at most one result.
1315            if let Some(result) = m_inst_result {
1316                if let Some(res_name) = llvm_get_value_name(inst).filter(|name| !name.is_empty()) {
1317                    let res_name = cctx.id_legaliser.legalise(&res_name);
1318                    debug_info::set_operation_result_name(ctx, m_inst, 0, Some(res_name));
1319                }
1320                cctx.value_map.insert(inst, result);
1321            }
1322        }
1323    }
1324    Ok(())
1325}
1326
1327fn convert_function(
1328    ctx: &mut Context,
1329    cctx: &mut ConversionContext,
1330    function: LLVMValue,
1331) -> Result<FuncOp> {
1332    assert!(llvm_is_a::function(function));
1333
1334    let llvm_name = llvm_get_value_name(function).expect("Expected function to have a name");
1335    let name = cctx.id_legaliser.legalise(&llvm_name);
1336    let fn_ty = convert_type(ctx, cctx, llvm_global_get_value_type(function))?;
1337    let fn_ty = TypePtr::from_ptr(fn_ty, ctx)?;
1338    // Create a new FuncOp.
1339    let m_func = FuncOp::new(ctx, name.clone(), fn_ty);
1340
1341    let linkage = convert_linkage(llvm_get_linkage(function));
1342    m_func.set_attr_llvm_function_linkage(ctx, linkage);
1343
1344    if llvm_name != <Identifier as Into<String>>::into(name) {
1345        m_func.set_llvm_symbol_name(ctx, llvm_name);
1346    }
1347
1348    // If function is just a declaration, we have nothing more to do.
1349    if llvm_is_declaration(function) {
1350        return Ok(m_func);
1351    }
1352
1353    let m_entry_block = m_func.get_or_create_entry_block(ctx);
1354    let m_func_reg = m_func.get_region(ctx).unwrap();
1355    cctx.reset_for_region(m_entry_block);
1356
1357    let blocks = rpo(function);
1358    // Map entry block
1359    let mut blocks_iter = blocks.iter();
1360    let Some(entry) = blocks_iter.next() else {
1361        return Ok(m_func);
1362    };
1363
1364    cctx.block_map.insert(*entry, m_entry_block);
1365    {
1366        let val_map = &mut cctx.value_map;
1367        let m_entry_block_ref = m_entry_block.deref(ctx);
1368        // Map function args to entry block args.
1369        for (arg_idx, arg) in param_iter(function).enumerate() {
1370            val_map.insert(arg, m_entry_block_ref.get_argument(arg_idx));
1371        }
1372    }
1373
1374    // Create, place and map rest of the blocks.
1375    for block in blocks_iter {
1376        let label = llvm_get_basic_block_name(*block)
1377            .filter(|name| !name.is_empty())
1378            .map(|name| cctx.id_legaliser.legalise(&name));
1379        let m_block = BasicBlock::new(ctx, label, vec![]);
1380        m_block.insert_at_back(m_func_reg, ctx);
1381        cctx.block_map.insert(*block, m_block);
1382    }
1383
1384    // Finally, convert all blocks
1385    for block in blocks {
1386        let m_block = *cctx
1387            .block_map
1388            .get(&block)
1389            .expect("We have an unmapped block !");
1390        convert_block(ctx, cctx, block, m_block)?;
1391    }
1392
1393    Ok(m_func)
1394}
1395
1396fn convert_global(
1397    ctx: &mut Context,
1398    cctx: &mut ConversionContext,
1399    global: LLVMValue,
1400) -> Result<GlobalOp> {
1401    let llvm_name = llvm_get_value_name(global).unwrap_or_default();
1402    let name = cctx.id_legaliser.legalise(&llvm_name);
1403
1404    let ty = convert_type(
1405        ctx,
1406        &mut ConversionContext::default(),
1407        llvm_global_get_value_type(global),
1408    )?;
1409
1410    let op = GlobalOp::new(ctx, name.clone(), ty);
1411
1412    if <Identifier as Into<String>>::into(name) != llvm_name {
1413        op.set_llvm_symbol_name(ctx, llvm_name);
1414    }
1415
1416    let linkage = convert_linkage(llvm_get_linkage(global));
1417    op.set_attr_llvm_global_linkage(ctx, linkage);
1418
1419    let alignment = llvm_get_alignment(global);
1420    if alignment != 0 {
1421        op.set_alignment(ctx, alignment);
1422    }
1423
1424    if let Some(init) = llvm_get_initializer(global) {
1425        assert!(!llvm_is_declaration(global));
1426        // TODO: Use attribute based initializer for simple constants.
1427        let init_region = op.add_initializer_region(ctx);
1428        let entry_block = init_region.deref(ctx).iter(ctx).next().unwrap();
1429        cctx.reset_for_region(entry_block);
1430
1431        // Convert the initializer.
1432        process_constant(ctx, cctx, init)?;
1433        let Some(m_val) = cctx.value_map.get(&init) else {
1434            panic!("We just processed this constant, it must be in the map");
1435        };
1436
1437        let return_op = ReturnOp::new(ctx, Some(*m_val));
1438        return_op.get_operation().insert_at_back(entry_block, ctx);
1439    }
1440
1441    Ok(op)
1442}
1443
1444/// Convert [LLVMModule] to [ModuleOp].
1445pub fn convert_module(ctx: &mut Context, module: &LLVMModule) -> Result<ModuleOp> {
1446    let cctx = &mut ConversionContext::default();
1447
1448    let module_name = llvm_get_module_identifier(module).unwrap_or_default();
1449    let module_name = cctx.id_legaliser.legalise(&module_name);
1450
1451    let m = ModuleOp::new(ctx, module_name);
1452
1453    // Convert globals.
1454    for gv in global_iter(module) {
1455        let m_gv = convert_global(ctx, cctx, gv)?;
1456        m.append_operation(ctx, m_gv.get_operation(), 0);
1457    }
1458
1459    // Convert functions.
1460    for fun in function_iter(module) {
1461        let llvm_name = llvm_get_value_name(fun).expect("Expected function to have a name");
1462        if llvm_lookup_intrinsic_id(&llvm_name).is_some() {
1463            // Skip LLVM intrinsics.
1464            continue;
1465        }
1466        let m_fun = convert_function(ctx, cctx, fun)?;
1467        m.append_operation(ctx, m_fun.get_operation(), 0);
1468    }
1469    Ok(m)
1470}