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