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