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