1use 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#[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 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#[derive(Default)]
253struct ConversionContext {
254 value_map: FxHashMap<LLVMValue, Value>,
256 block_map: FxHashMap<LLVMBasicBlock, Ptr<BasicBlock>>,
258 type_cache: FxHashMap<LLVMType, Ptr<TypeObj>>,
260 constants_inserter: Option<IRInserter<DummyListener>>,
262 id_legaliser: identifier::Legaliser,
264}
265
266impl ConversionContext {
267 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
277fn 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 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 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 vec![]
312 }
313 _ => {
314 todo!(
315 "Unsupported instruction: {}",
316 llvm_print_value_to_string(term).unwrap_or_default()
317 )
318 }
319 }
320}
321
322fn 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 return;
336 }
337 for succ in successors(block).into_iter() {
339 walk(succ, visited, po);
340 }
341 po.push(block);
343 }
344
345 for block in basic_block_iter(function) {
347 if visited.contains(&block) {
348 continue;
349 }
350 walk(block, visited, &mut po);
351 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
379fn 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
391fn 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 (int_ty.is_signless() && int_ty.width() == 32).then(|| int_attr.value().to_u32())
397 })
398}
399
400fn 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 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 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 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 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 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 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 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
752fn 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 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 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 let mut case_values = vec![];
1225 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 .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 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
1296fn 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 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 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 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 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 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 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 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 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 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
1444pub 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 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 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 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}