1use llvm_sys::{
7 LLVMAtomicOrdering, LLVMAtomicRMWBinOp, LLVMInlineAsmDialect, LLVMIntPredicate, LLVMLinkage,
8 LLVMRealPredicate,
9};
10use pliron::{
11 attribute::{Attribute, attr_cast},
12 basic_block::BasicBlock,
13 builtin::{
14 attr_interfaces::FloatAttr,
15 attributes::{FPDoubleAttr, FPSingleAttr, IntegerAttr, StringAttr},
16 op_interfaces::{
17 AtMostOneRegionInterface, BranchOpInterface, CallOpCallable, CallOpInterface,
18 OneOpdInterface, OneResultInterface, SingleBlockRegionInterface, SymbolOpInterface,
19 },
20 ops::ModuleOp,
21 type_interfaces::FunctionTypeInterface,
22 types::{FP16Type, FP32Type, FP64Type, IntegerType},
23 },
24 common_traits::Named,
25 context::{Context, Ptr},
26 derive::{attr_interface, attr_interface_impl},
27 graph::traversals::region::topological_order,
28 identifier::Identifier,
29 input_err, input_err_noloc, input_error, input_error_noloc,
30 linked_list::ContainsLinkedList,
31 location::Located,
32 op::{Op, op_cast},
33 operation::Operation,
34 printable::Printable,
35 result::Result,
36 std_deps::hash::{FxHashMap, hash_map},
37 r#type::{Type, TypeHandle, Typed, type_cast},
38 utils::apint::APInt,
39 value::{DefiningEntity, Value},
40};
41
42use pliron::derive::{op_interface, op_interface_impl, type_interface, type_interface_impl};
43use thiserror::Error;
44
45use crate::{
46 attributes::{
47 AtomicOrderingAttr, AtomicRmwKindAttr, FCmpPredicateAttr, ICmpPredicateAttr, LinkageAttr,
48 },
49 llvm_sys::core::{
50 LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue,
51 instruction_iter, llvm_add_case, llvm_add_destination, llvm_add_function,
52 llvm_add_global_in_address_space, llvm_add_incoming, llvm_append_basic_block_in_context,
53 llvm_array_type2, llvm_block_address, llvm_build_add, llvm_build_addrspacecast,
54 llvm_build_and, llvm_build_array_alloca, llvm_build_ashr, llvm_build_atomic_cmpxchg,
55 llvm_build_atomic_rmw, llvm_build_bitcast, llvm_build_br, llvm_build_call2,
56 llvm_build_cond_br, llvm_build_extract_element, llvm_build_extract_value, llvm_build_fadd,
57 llvm_build_fcmp, llvm_build_fdiv, llvm_build_fence, llvm_build_fmul, llvm_build_fneg,
58 llvm_build_fpext, llvm_build_fptosi, llvm_build_fptoui, llvm_build_fptrunc,
59 llvm_build_freeze, llvm_build_frem, llvm_build_fsub, llvm_build_gep2, llvm_build_icmp,
60 llvm_build_indirect_br, llvm_build_insert_element, llvm_build_insert_value,
61 llvm_build_int_to_ptr, llvm_build_load2, llvm_build_lshr, llvm_build_mul, llvm_build_or,
62 llvm_build_phi, llvm_build_ptr_to_int, llvm_build_ret, llvm_build_ret_void,
63 llvm_build_sdiv, llvm_build_select, llvm_build_sext, llvm_build_shl,
64 llvm_build_shuffle_vector, llvm_build_sitofp, llvm_build_srem, llvm_build_store,
65 llvm_build_sub, llvm_build_switch, llvm_build_trunc, llvm_build_udiv, llvm_build_uitofp,
66 llvm_build_unreachable, llvm_build_urem, llvm_build_va_arg, llvm_build_xor,
67 llvm_build_zext, llvm_can_value_use_fast_math_flags, llvm_clear_insertion_position,
68 llvm_const_int, llvm_const_null, llvm_const_real, llvm_const_vector, llvm_delete_global,
69 llvm_double_type_in_context, llvm_float_type_in_context, llvm_function_type,
70 llvm_get_inline_asm, llvm_get_named_function, llvm_get_param,
71 llvm_get_pointer_address_space, llvm_get_poison, llvm_get_sync_scope_id, llvm_get_undef,
72 llvm_half_type_in_context, llvm_int_type_in_context, llvm_is_a, llvm_lookup_intrinsic_id,
73 llvm_pointer_type_in_context, llvm_position_builder_at_end, llvm_replace_all_uses_with,
74 llvm_scalable_vector_type, llvm_set_alignment, llvm_set_atomic_sync_scope_id,
75 llvm_set_fast_math_flags, llvm_set_initializer, llvm_set_linkage, llvm_set_nneg,
76 llvm_set_ordering, llvm_struct_create_named, llvm_struct_set_body,
77 llvm_struct_type_in_context, llvm_type_of, llvm_vector_type, llvm_void_type_in_context,
78 },
79 op_interfaces::{
80 AlignableOpInterface, FastMathFlags, IsDeclaration, LlvmSymbolName, NNegFlag,
81 PointerTypeResult,
82 },
83 ops::{
84 AShrOp, AddOp, AddrSpaceCastOp, AddressOfOp, AllocaOp, AndOp, AtomicCmpxchgOp,
85 AtomicLoadOp, AtomicRmwOp, AtomicStoreOp, BitcastOp, BlockAddressOp, BlockTagOp, BrOp,
86 CallIntrinsicOp, CallOp, CondBrOp, ConstantOp, ExtractElementOp, ExtractValueOp, FAddOp,
87 FCmpOp, FDivOp, FMulOp, FNegOp, FPExtOp, FPToSIOp, FPToUIOp, FPTruncOp, FRemOp, FSubOp,
88 FenceOp, FreezeOp, FuncOp, GetElementPtrOp, GlobalOp, ICmpOp, IndirectBrOp, InlineAsmOp,
89 InsertElementOp, InsertValueOp, IntToPtrOp, LShrOp, LoadOp, MulOp, OrOp, PoisonOp,
90 PtrToIntOp, ReturnOp, SDivOp, SExtOp, SIToFPOp, SRemOp, SelectOp, ShlOp, ShuffleVectorOp,
91 StoreOp, SubOp, SwitchOp, TruncOp, UDivOp, UIToFPOp, URemOp, UndefOp, UnreachableOp,
92 VAArgOp, XorOp, ZExtOp, ZeroOp,
93 },
94 types::{ArrayType, FuncType, PointerType, StructType, VectorType, VoidType},
95};
96
97pub struct ConversionContext<'a> {
99 cur_llvm_module: &'a LLVMModule,
101 value_map: FxHashMap<Value, LLVMValue>,
103 block_map: FxHashMap<Ptr<BasicBlock>, LLVMBasicBlock>,
105 function_map: FxHashMap<Identifier, LLVMValue>,
107 globals_map: FxHashMap<Identifier, LLVMValue>,
109 block_tags: FxHashMap<(Identifier, u64), LLVMBasicBlock>,
111 pending_block_address_ops: FxHashMap<LLVMValue, (Identifier, u64)>,
114 structs_map: FxHashMap<Identifier, LLVMType>,
116 type_cache: FxHashMap<TypeHandle, LLVMType>,
118 builder: LLVMBuilder,
120 scratch_builder: LLVMBuilder,
122}
123
124impl<'a> ConversionContext<'a> {
125 pub fn new(llvm_ctx: &'a LLVMContext, cur_llvm_module: &'a LLVMModule) -> Self {
126 Self {
127 cur_llvm_module,
128 value_map: FxHashMap::default(),
129 block_map: FxHashMap::default(),
130 function_map: FxHashMap::default(),
131 globals_map: FxHashMap::default(),
132 block_tags: FxHashMap::default(),
133 pending_block_address_ops: FxHashMap::default(),
134 structs_map: FxHashMap::default(),
135 type_cache: FxHashMap::default(),
136 builder: LLVMBuilder::new(llvm_ctx),
137 scratch_builder: LLVMBuilder::new(llvm_ctx),
138 }
139 }
140
141 pub fn clear_per_function_data(&mut self) {
142 self.value_map.clear();
143 self.block_map.clear();
144 llvm_clear_insertion_position(&self.builder);
145 }
146}
147
148#[derive(Error, Debug)]
149pub enum ToLLVMErr {
150 #[error("Type {0} does not have a conversion to LLVM type implemented")]
151 MissingTypeConversion(String),
152 #[error("Operation {0} does not have a conversion to LLVM instruction implemented")]
153 MissingOpConversion(String),
154 #[error("Definition for value {0} not seen yet")]
155 UndefinedValue(String),
156 #[error("Block definition {0} not seen yet")]
157 UndefinedBlock(String),
158 #[error("Number of block args in the source dialect equal the number of PHIs in target IR")]
159 NumBlockArgsNumPhisMismatch,
160 #[error("ConstantOp must have integer or float value")]
161 ConstOpNotIntOrFloat,
162 #[error(
163 "Insert/Extract value instructions must specify exactly one index, an LLVM-C API limitation"
164 )]
165 InsertExtractValueIndices,
166 #[error("GlobalOp Initializer region does not terminate with a return with value")]
167 GlobalOpInitializerRegionBadReturn,
168 #[error("Cannot evaluate value to a constant")]
169 CannotEvaluateToConst,
170 #[error("BlockAddressOp refers to missing block tag {1} in function {0}")]
171 MissingBlockTag(String, u64),
172}
173
174pub fn convert_ipredicate(pred: ICmpPredicateAttr) -> LLVMIntPredicate {
175 match pred {
176 ICmpPredicateAttr::EQ => LLVMIntPredicate::LLVMIntEQ,
177 ICmpPredicateAttr::NE => LLVMIntPredicate::LLVMIntNE,
178 ICmpPredicateAttr::UGT => LLVMIntPredicate::LLVMIntUGT,
179 ICmpPredicateAttr::UGE => LLVMIntPredicate::LLVMIntUGE,
180 ICmpPredicateAttr::ULT => LLVMIntPredicate::LLVMIntULT,
181 ICmpPredicateAttr::ULE => LLVMIntPredicate::LLVMIntULE,
182 ICmpPredicateAttr::SGT => LLVMIntPredicate::LLVMIntSGT,
183 ICmpPredicateAttr::SGE => LLVMIntPredicate::LLVMIntSGE,
184 ICmpPredicateAttr::SLT => LLVMIntPredicate::LLVMIntSLT,
185 ICmpPredicateAttr::SLE => LLVMIntPredicate::LLVMIntSLE,
186 }
187}
188
189pub fn convert_fpredicate(pred: FCmpPredicateAttr) -> LLVMRealPredicate {
190 match pred {
191 FCmpPredicateAttr::False => LLVMRealPredicate::LLVMRealPredicateFalse,
192 FCmpPredicateAttr::OEQ => LLVMRealPredicate::LLVMRealOEQ,
193 FCmpPredicateAttr::OGT => LLVMRealPredicate::LLVMRealOGT,
194 FCmpPredicateAttr::OGE => LLVMRealPredicate::LLVMRealOGE,
195 FCmpPredicateAttr::OLT => LLVMRealPredicate::LLVMRealOLT,
196 FCmpPredicateAttr::OLE => LLVMRealPredicate::LLVMRealOLE,
197 FCmpPredicateAttr::ONE => LLVMRealPredicate::LLVMRealONE,
198 FCmpPredicateAttr::ORD => LLVMRealPredicate::LLVMRealORD,
199 FCmpPredicateAttr::UNO => LLVMRealPredicate::LLVMRealUNO,
200 FCmpPredicateAttr::UEQ => LLVMRealPredicate::LLVMRealUEQ,
201 FCmpPredicateAttr::UGT => LLVMRealPredicate::LLVMRealUGT,
202 FCmpPredicateAttr::UGE => LLVMRealPredicate::LLVMRealUGE,
203 FCmpPredicateAttr::ULT => LLVMRealPredicate::LLVMRealULT,
204 FCmpPredicateAttr::ULE => LLVMRealPredicate::LLVMRealULE,
205 FCmpPredicateAttr::UNE => LLVMRealPredicate::LLVMRealUNE,
206 FCmpPredicateAttr::True => LLVMRealPredicate::LLVMRealPredicateTrue,
207 }
208}
209
210pub fn convert_linkage(linkage: LinkageAttr) -> LLVMLinkage {
211 match linkage {
212 LinkageAttr::ExternalLinkage => LLVMLinkage::LLVMExternalLinkage,
213 LinkageAttr::AvailableExternallyLinkage => LLVMLinkage::LLVMAvailableExternallyLinkage,
214 LinkageAttr::LinkOnceAnyLinkage => LLVMLinkage::LLVMLinkOnceAnyLinkage,
215 LinkageAttr::LinkOnceODRLinkage => LLVMLinkage::LLVMLinkOnceODRLinkage,
216 LinkageAttr::WeakAnyLinkage => LLVMLinkage::LLVMWeakAnyLinkage,
217 LinkageAttr::WeakODRLinkage => LLVMLinkage::LLVMWeakODRLinkage,
218 LinkageAttr::AppendingLinkage => LLVMLinkage::LLVMAppendingLinkage,
219 LinkageAttr::InternalLinkage => LLVMLinkage::LLVMInternalLinkage,
220 LinkageAttr::PrivateLinkage => LLVMLinkage::LLVMPrivateLinkage,
221 LinkageAttr::DLLImportLinkage => LLVMLinkage::LLVMDLLImportLinkage,
222 LinkageAttr::DLLExportLinkage => LLVMLinkage::LLVMDLLExportLinkage,
223 LinkageAttr::ExternalWeakLinkage => LLVMLinkage::LLVMExternalWeakLinkage,
224 LinkageAttr::GhostLinkage => LLVMLinkage::LLVMGhostLinkage,
225 LinkageAttr::CommonLinkage => LLVMLinkage::LLVMCommonLinkage,
226 LinkageAttr::LinkOnceODRAutoHideLinkage => LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage,
227 LinkageAttr::LinkerPrivateLinkage => LLVMLinkage::LLVMLinkerPrivateLinkage,
228 LinkageAttr::LinkerPrivateWeakLinkage => LLVMLinkage::LLVMLinkerPrivateWeakLinkage,
229 }
230}
231
232#[::pliron::linkme::distributed_slice]
233#[linkme(crate = pliron::linkme)]
234pub static TEST: [u64];
235
236#[attr_interface]
238trait FloatAttrToFP64: FloatAttr {
239 fn to_fp64(&self) -> f64;
240 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
241 where
242 Self: Sized,
243 {
244 Ok(())
245 }
246}
247
248#[attr_interface_impl]
249impl FloatAttrToFP64 for FPSingleAttr {
250 fn to_fp64(&self) -> f64 {
251 Into::<f32>::into(self.clone()) as f64
252 }
253}
254
255#[attr_interface_impl]
256impl FloatAttrToFP64 for FPDoubleAttr {
257 fn to_fp64(&self) -> f64 {
258 Into::<f64>::into(self.clone())
259 }
260}
261
262#[type_interface]
264trait ToLLVMType {
265 fn convert(
267 &self,
268 ctx: &Context,
269 llvm_ctx: &LLVMContext,
270 cctx: &mut ConversionContext,
271 ) -> Result<LLVMType>;
272
273 fn verify(_type: &dyn Type, _ctx: &Context) -> Result<()>
274 where
275 Self: Sized,
276 {
277 Ok(())
278 }
279}
280
281#[op_interface]
283trait ToLLVMValue {
284 fn convert(
286 &self,
287 ctx: &Context,
288 llvm_ctx: &LLVMContext,
289 cctx: &mut ConversionContext,
290 ) -> Result<LLVMValue>;
291
292 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
293 where
294 Self: Sized,
295 {
296 Ok(())
297 }
298}
299
300#[type_interface_impl]
301impl ToLLVMType for IntegerType {
302 fn convert(
303 &self,
304 _ctx: &Context,
305 llvm_ctx: &LLVMContext,
306 _cctx: &mut ConversionContext,
307 ) -> Result<LLVMType> {
308 Ok(llvm_int_type_in_context(llvm_ctx, self.width()))
309 }
310}
311
312#[type_interface_impl]
313impl ToLLVMType for ArrayType {
314 fn convert(
315 &self,
316 ctx: &Context,
317 llvm_ctx: &LLVMContext,
318 cctx: &mut ConversionContext,
319 ) -> Result<LLVMType> {
320 let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
321 Ok(llvm_array_type2(elem_ty, self.size()))
322 }
323}
324
325#[type_interface_impl]
326impl ToLLVMType for FuncType {
327 fn convert(
328 &self,
329 ctx: &Context,
330 llvm_ctx: &LLVMContext,
331 cctx: &mut ConversionContext,
332 ) -> Result<LLVMType> {
333 let args_tys: Vec<_> = self
334 .arg_types()
335 .iter()
336 .map(|ty| convert_type(ctx, llvm_ctx, cctx, *ty))
337 .collect::<Result<_>>()?;
338 let ret_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type())?;
339 Ok(llvm_function_type(ret_ty, &args_tys, self.is_var_arg()))
340 }
341}
342
343#[type_interface_impl]
344impl ToLLVMType for VoidType {
345 fn convert(
346 &self,
347 _ctx: &Context,
348 llvm_ctx: &LLVMContext,
349 _cctx: &mut ConversionContext,
350 ) -> Result<LLVMType> {
351 Ok(llvm_void_type_in_context(llvm_ctx))
352 }
353}
354
355#[type_interface_impl]
356impl ToLLVMType for PointerType {
357 fn convert(
358 &self,
359 _ctx: &Context,
360 llvm_ctx: &LLVMContext,
361 _cctx: &mut ConversionContext,
362 ) -> Result<LLVMType> {
363 Ok(llvm_pointer_type_in_context(llvm_ctx, self.address_space()))
364 }
365}
366
367#[type_interface_impl]
368impl ToLLVMType for StructType {
369 fn convert(
370 &self,
371 ctx: &Context,
372 llvm_ctx: &LLVMContext,
373 cctx: &mut ConversionContext,
374 ) -> Result<LLVMType> {
375 if self.is_opaque() {
376 let name = self.name().expect("Opaqaue struct must have a name");
377 Ok(llvm_struct_create_named(llvm_ctx, name.as_str()))
378 } else {
379 let field_types = self
380 .fields()
381 .map(|fty| convert_type(ctx, llvm_ctx, cctx, fty))
382 .collect::<Result<Vec<_>>>()?;
383 if let Some(name) = self.name() {
384 match cctx.structs_map.entry(name) {
385 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
386 hash_map::Entry::Vacant(entry) => {
387 let str_ty = llvm_struct_create_named(llvm_ctx, entry.key());
388 llvm_struct_set_body(str_ty, &field_types, false);
389 entry.insert(str_ty);
390 Ok(str_ty)
391 }
392 }
393 } else {
394 Ok(llvm_struct_type_in_context(llvm_ctx, &field_types, false))
395 }
396 }
397 }
398}
399
400#[type_interface_impl]
401impl ToLLVMType for VectorType {
402 fn convert(
403 &self,
404 ctx: &Context,
405 llvm_ctx: &LLVMContext,
406 cctx: &mut ConversionContext,
407 ) -> Result<LLVMType> {
408 let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
409 let num_elems = self.num_elements();
410 if self.is_scalable() {
411 Ok(llvm_scalable_vector_type(elem_ty, num_elems))
412 } else {
413 Ok(llvm_vector_type(elem_ty, num_elems))
414 }
415 }
416}
417
418#[type_interface_impl]
419impl ToLLVMType for FP32Type {
420 fn convert(
421 &self,
422 _ctx: &Context,
423 llvm_ctx: &LLVMContext,
424 _cctx: &mut ConversionContext,
425 ) -> Result<LLVMType> {
426 Ok(llvm_float_type_in_context(llvm_ctx))
427 }
428}
429
430#[type_interface_impl]
431impl ToLLVMType for FP64Type {
432 fn convert(
433 &self,
434 _ctx: &Context,
435 llvm_ctx: &LLVMContext,
436 _cctx: &mut ConversionContext,
437 ) -> Result<LLVMType> {
438 Ok(llvm_double_type_in_context(llvm_ctx))
439 }
440}
441
442#[type_interface_impl]
443impl ToLLVMType for FP16Type {
444 fn convert(
445 &self,
446 _ctx: &Context,
447 llvm_ctx: &LLVMContext,
448 _cctx: &mut ConversionContext,
449 ) -> Result<LLVMType> {
450 Ok(llvm_half_type_in_context(llvm_ctx))
451 }
452}
453
454pub fn convert_type(
456 ctx: &Context,
457 llvm_ctx: &LLVMContext,
458 cctx: &mut ConversionContext,
459 ty: TypeHandle,
460) -> Result<LLVMType> {
461 if let Some(cached) = cctx.type_cache.get(&ty) {
462 return Ok(*cached);
463 }
464 if let Some(converter) = type_cast::<dyn ToLLVMType>(&*ty.deref(ctx)) {
465 let llvm_ty = converter.convert(ctx, llvm_ctx, cctx)?;
466 cctx.type_cache.insert(ty, llvm_ty);
467 return Ok(llvm_ty);
468 }
469
470 input_err_noloc!(ToLLVMErr::MissingTypeConversion(
471 ty.deref(ctx).get_type_id().to_string()
472 ))
473}
474
475fn convert_value_operand(
476 cctx: &mut ConversionContext,
477 ctx: &Context,
478 value: &Value,
479) -> Result<LLVMValue> {
480 match cctx.value_map.get(value) {
481 Some(v) => Ok(*v),
482 None => {
483 input_err_noloc!(ToLLVMErr::UndefinedValue(value.unique_name(ctx).into()))
484 }
485 }
486}
487
488fn convert_block_operand(
489 cctx: &mut ConversionContext,
490 ctx: &Context,
491 block: Ptr<BasicBlock>,
492) -> Result<LLVMBasicBlock> {
493 match cctx.block_map.get(&block) {
494 Some(v) => Ok(*v),
495 None => {
496 input_err_noloc!(ToLLVMErr::UndefinedBlock(block.unique_name(ctx).into()))
497 }
498 }
499}
500
501macro_rules! to_llvm_value_int_bin_op {
502 (
503 $op_name:ident, $builder_function:ident
504 ) => {
505 #[pliron::derive::op_interface_impl]
506 impl ToLLVMValue for $op_name {
507 fn convert(
508 &self,
509 ctx: &Context,
510 _llvm_ctx: &LLVMContext,
511 cctx: &mut ConversionContext,
512 ) -> Result<LLVMValue> {
513 let op = self.get_operation().deref(ctx);
514 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
515 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
516 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
517 Ok($builder_function(
518 &cctx.builder,
519 lhs,
520 rhs,
521 &self.get_result(ctx).unique_name(ctx),
522 ))
523 }
524 }
525 };
526}
527
528to_llvm_value_int_bin_op!(AddOp, llvm_build_add);
529to_llvm_value_int_bin_op!(SubOp, llvm_build_sub);
530to_llvm_value_int_bin_op!(MulOp, llvm_build_mul);
531to_llvm_value_int_bin_op!(SDivOp, llvm_build_sdiv);
532to_llvm_value_int_bin_op!(UDivOp, llvm_build_udiv);
533to_llvm_value_int_bin_op!(URemOp, llvm_build_urem);
534to_llvm_value_int_bin_op!(SRemOp, llvm_build_srem);
535to_llvm_value_int_bin_op!(AndOp, llvm_build_and);
536to_llvm_value_int_bin_op!(OrOp, llvm_build_or);
537to_llvm_value_int_bin_op!(XorOp, llvm_build_xor);
538to_llvm_value_int_bin_op!(ShlOp, llvm_build_shl);
539to_llvm_value_int_bin_op!(LShrOp, llvm_build_lshr);
540to_llvm_value_int_bin_op!(AShrOp, llvm_build_ashr);
541
542#[op_interface_impl]
543impl ToLLVMValue for AllocaOp {
544 fn convert(
545 &self,
546 ctx: &Context,
547 llvm_ctx: &LLVMContext,
548 cctx: &mut ConversionContext,
549 ) -> Result<LLVMValue> {
550 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_pointee_type(ctx))?;
551 let size = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
552 let alloca_op = llvm_build_array_alloca(
553 &cctx.builder,
554 ty,
555 size,
556 &self.get_result(ctx).unique_name(ctx),
557 );
558 if let Some(alignment) = self.alignment(ctx) {
559 llvm_set_alignment(alloca_op, alignment);
560 }
561 Ok(alloca_op)
562 }
563}
564
565#[op_interface_impl]
566impl ToLLVMValue for BitcastOp {
567 fn convert(
568 &self,
569 ctx: &Context,
570 llvm_ctx: &LLVMContext,
571 cctx: &mut ConversionContext,
572 ) -> Result<LLVMValue> {
573 let arg = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
574 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
575 let bitcast_op = llvm_build_bitcast(
576 &cctx.builder,
577 arg,
578 ty,
579 &self.get_result(ctx).unique_name(ctx),
580 );
581 Ok(bitcast_op)
582 }
583}
584
585#[op_interface_impl]
586impl ToLLVMValue for AddrSpaceCastOp {
587 fn convert(
588 &self,
589 ctx: &Context,
590 llvm_ctx: &LLVMContext,
591 cctx: &mut ConversionContext,
592 ) -> Result<LLVMValue> {
593 let arg = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
594 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
595 let addrspacecast_op = llvm_build_addrspacecast(
596 &cctx.builder,
597 arg,
598 ty,
599 &self.get_result(ctx).unique_name(ctx),
600 );
601 Ok(addrspacecast_op)
602 }
603}
604
605fn link_succ_operands_with_phis(
606 ctx: &Context,
607 cctx: &mut ConversionContext,
608 source_block: Ptr<BasicBlock>,
609 target_block: LLVMBasicBlock,
610 opds: Vec<Value>,
611) -> Result<()> {
612 let mut phis = vec![];
613 for inst in instruction_iter(target_block) {
614 if !llvm_is_a::phi_node(inst) {
615 break;
616 };
617 phis.push(inst);
618 }
619
620 if phis.len() != opds.len() {
621 return input_err!(
622 source_block.deref(ctx).loc(),
623 ToLLVMErr::NumBlockArgsNumPhisMismatch
624 );
625 }
626
627 let source_block = convert_block_operand(cctx, ctx, source_block)?;
628
629 for (idx, arg) in opds.iter().enumerate() {
630 let arg = convert_value_operand(cctx, ctx, arg)?;
631 llvm_add_incoming(phis[idx], &[arg], &[source_block]);
632 }
633 Ok(())
634}
635
636#[op_interface_impl]
637impl ToLLVMValue for BrOp {
638 fn convert(
639 &self,
640 ctx: &Context,
641 _llvm_ctx: &LLVMContext,
642 cctx: &mut ConversionContext,
643 ) -> Result<LLVMValue> {
644 let op = self.get_operation().deref(ctx);
645 let succ = op.get_successor(0);
646 let succ_llvm = convert_block_operand(cctx, ctx, succ)?;
647 let branch_op = llvm_build_br(&cctx.builder, succ_llvm);
648
649 link_succ_operands_with_phis(
651 ctx,
652 cctx,
653 op.get_parent_block().expect("Unlinked operation"),
654 succ_llvm,
655 self.successor_operands(ctx, 0),
656 )?;
657
658 Ok(branch_op)
659 }
660}
661
662#[op_interface_impl]
663impl ToLLVMValue for CondBrOp {
664 fn convert(
665 &self,
666 ctx: &Context,
667 _llvm_ctx: &LLVMContext,
668 cctx: &mut ConversionContext,
669 ) -> Result<LLVMValue> {
670 let op = self.get_operation().deref(ctx);
671 let (true_succ, false_succ) = (op.get_successor(0), op.get_successor(1));
672 let true_succ_llvm = convert_block_operand(cctx, ctx, true_succ)?;
673 let false_succ_llvm = convert_block_operand(cctx, ctx, false_succ)?;
674 let cond = convert_value_operand(cctx, ctx, &self.get_operand_condition(ctx))?;
675
676 let branch_op = llvm_build_cond_br(&cctx.builder, cond, true_succ_llvm, false_succ_llvm);
677
678 link_succ_operands_with_phis(
680 ctx,
681 cctx,
682 op.get_parent_block().expect("Unlinked operation"),
683 true_succ_llvm,
684 self.successor_operands(ctx, 0),
685 )?;
686 link_succ_operands_with_phis(
687 ctx,
688 cctx,
689 op.get_parent_block().expect("Unlinked operation"),
690 false_succ_llvm,
691 self.successor_operands(ctx, 1),
692 )?;
693
694 Ok(branch_op)
695 }
696}
697
698#[op_interface_impl]
699impl ToLLVMValue for SwitchOp {
700 fn convert(
701 &self,
702 ctx: &Context,
703 llvm_ctx: &LLVMContext,
704 cctx: &mut ConversionContext,
705 ) -> Result<LLVMValue> {
706 let op = self.get_operation().deref(ctx);
707 let cond = convert_value_operand(cctx, ctx, &self.get_operand_condition(ctx))?;
708 let default_succ = convert_block_operand(cctx, ctx, self.default_dest(ctx))?;
709 let switch_op = llvm_build_switch(
710 &cctx.builder,
711 cond,
712 default_succ,
713 self.cases(ctx).len() as u32,
714 );
715
716 link_succ_operands_with_phis(
718 ctx,
719 cctx,
720 op.get_parent_block().expect("Unlinked operation"),
721 default_succ,
722 self.default_dest_operands(ctx),
723 )?;
724 for case in self.cases(ctx) {
725 let succ_llvm = convert_block_operand(cctx, ctx, case.dest)?;
726 link_succ_operands_with_phis(
727 ctx,
728 cctx,
729 op.get_parent_block().expect("Unlinked operation"),
730 succ_llvm,
731 case.dest_opds,
732 )?;
733
734 let int_ty = case.value.get_type();
735 let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
736 let ap_int_val: APInt = case.value.clone().into();
737 let case_const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
738
739 llvm_add_case(switch_op, case_const_val, succ_llvm);
740 }
741
742 Ok(switch_op)
743 }
744}
745
746#[op_interface_impl]
747impl ToLLVMValue for IndirectBrOp {
748 fn convert(
749 &self,
750 ctx: &Context,
751 _llvm_ctx: &LLVMContext,
752 cctx: &mut ConversionContext,
753 ) -> Result<LLVMValue> {
754 let op = self.get_operation().deref(ctx);
755 let addr = convert_value_operand(cctx, ctx, &self.get_operand_address(ctx))?;
756 let dests = self.destinations(ctx);
757 let indirect_br_op = llvm_build_indirect_br(&cctx.builder, addr, dests.len() as u32);
758
759 for dest in dests {
760 let succ_llvm = convert_block_operand(cctx, ctx, dest.dest)?;
761 llvm_add_destination(indirect_br_op, succ_llvm);
762 link_succ_operands_with_phis(
763 ctx,
764 cctx,
765 op.get_parent_block().expect("Unlinked operation"),
766 succ_llvm,
767 dest.dest_opds,
768 )?;
769 }
770
771 Ok(indirect_br_op)
772 }
773}
774
775#[op_interface_impl]
776impl ToLLVMValue for LoadOp {
777 fn convert(
778 &self,
779 ctx: &Context,
780 llvm_ctx: &LLVMContext,
781 cctx: &mut ConversionContext,
782 ) -> Result<LLVMValue> {
783 let pointee_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
784 let ptr = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
785 let load_op = llvm_build_load2(
786 &cctx.builder,
787 pointee_ty,
788 ptr,
789 &self.get_result(ctx).unique_name(ctx),
790 );
791 if let Some(alignment) = self.alignment(ctx) {
792 llvm_set_alignment(load_op, alignment);
793 }
794 Ok(load_op)
795 }
796}
797
798#[op_interface_impl]
799impl ToLLVMValue for StoreOp {
800 fn convert(
801 &self,
802 ctx: &Context,
803 _llvm_ctx: &LLVMContext,
804 cctx: &mut ConversionContext,
805 ) -> Result<LLVMValue> {
806 let value = convert_value_operand(cctx, ctx, &self.get_operand_value(ctx))?;
807 let ptr = convert_value_operand(cctx, ctx, &self.get_operand_address(ctx))?;
808 let store_op = llvm_build_store(&cctx.builder, value, ptr);
809 if let Some(alignment) = self.alignment(ctx) {
810 llvm_set_alignment(store_op, alignment);
811 }
812 Ok(store_op)
813 }
814}
815
816fn convert_atomic_ordering(o: &AtomicOrderingAttr) -> LLVMAtomicOrdering {
818 match o {
819 AtomicOrderingAttr::Monotonic => LLVMAtomicOrdering::LLVMAtomicOrderingMonotonic,
820 AtomicOrderingAttr::Acquire => LLVMAtomicOrdering::LLVMAtomicOrderingAcquire,
821 AtomicOrderingAttr::Release => LLVMAtomicOrdering::LLVMAtomicOrderingRelease,
822 AtomicOrderingAttr::AcqRel => LLVMAtomicOrdering::LLVMAtomicOrderingAcquireRelease,
823 AtomicOrderingAttr::SeqCst => LLVMAtomicOrdering::LLVMAtomicOrderingSequentiallyConsistent,
824 }
825}
826
827fn convert_rmw_kind(k: &AtomicRmwKindAttr) -> LLVMAtomicRMWBinOp {
829 match k {
830 AtomicRmwKindAttr::Xchg => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXchg,
831 AtomicRmwKindAttr::Add => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd,
832 AtomicRmwKindAttr::Sub => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub,
833 AtomicRmwKindAttr::And => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAnd,
834 AtomicRmwKindAttr::Nand => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpNand,
835 AtomicRmwKindAttr::Or => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpOr,
836 AtomicRmwKindAttr::Xor => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXor,
837 AtomicRmwKindAttr::Max => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMax,
838 AtomicRmwKindAttr::Min => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMin,
839 AtomicRmwKindAttr::UMax => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMax,
840 AtomicRmwKindAttr::UMin => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMin,
841 AtomicRmwKindAttr::FAdd => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFAdd,
842 AtomicRmwKindAttr::FSub => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFSub,
843 AtomicRmwKindAttr::FMax => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMax,
844 AtomicRmwKindAttr::FMin => LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMin,
845 }
846}
847
848#[op_interface_impl]
849impl ToLLVMValue for AtomicRmwOp {
850 fn convert(
851 &self,
852 ctx: &Context,
853 llvm_ctx: &LLVMContext,
854 cctx: &mut ConversionContext,
855 ) -> Result<LLVMValue> {
856 let (ptr_opd, val_opd) = {
857 let op = self.get_operation().deref(ctx);
858 (op.get_operand(0), op.get_operand(1))
859 };
860 let ptr = convert_value_operand(cctx, ctx, &ptr_opd)?;
861 let val = convert_value_operand(cctx, ctx, &val_opd)?;
862 let kind = convert_rmw_kind(
863 &self
864 .get_attr_llvm_rmw_kind(ctx)
865 .expect("atomicrmw missing rmw kind"),
866 );
867 let ordering = convert_atomic_ordering(
868 &self
869 .get_attr_llvm_rmw_ordering(ctx)
870 .expect("atomicrmw missing ordering"),
871 );
872 let scope = self
873 .get_attr_llvm_rmw_syncscope(ctx)
874 .map(|s| String::from((*s).clone()))
875 .unwrap_or_default();
876 let ssid = llvm_get_sync_scope_id(llvm_ctx, &scope);
877 Ok(llvm_build_atomic_rmw(
878 &cctx.builder,
879 kind,
880 ptr,
881 val,
882 ordering,
883 ssid,
884 ))
885 }
886}
887
888#[op_interface_impl]
889impl ToLLVMValue for AtomicCmpxchgOp {
890 fn convert(
891 &self,
892 ctx: &Context,
893 llvm_ctx: &LLVMContext,
894 cctx: &mut ConversionContext,
895 ) -> Result<LLVMValue> {
896 let (ptr_opd, cmp_opd, new_opd) = {
897 let op = self.get_operation().deref(ctx);
898 (op.get_operand(0), op.get_operand(1), op.get_operand(2))
899 };
900 let ptr = convert_value_operand(cctx, ctx, &ptr_opd)?;
901 let cmp = convert_value_operand(cctx, ctx, &cmp_opd)?;
902 let new = convert_value_operand(cctx, ctx, &new_opd)?;
903 let success = convert_atomic_ordering(
904 &self
905 .get_attr_llvm_cas_success_ordering(ctx)
906 .expect("cmpxchg missing success ordering"),
907 );
908 let failure = convert_atomic_ordering(
909 &self
910 .get_attr_llvm_cas_failure_ordering(ctx)
911 .expect("cmpxchg missing failure ordering"),
912 );
913 let scope = self
914 .get_attr_llvm_cas_syncscope(ctx)
915 .map(|s| String::from((*s).clone()))
916 .unwrap_or_default();
917 let ssid = llvm_get_sync_scope_id(llvm_ctx, &scope);
918 Ok(llvm_build_atomic_cmpxchg(
919 &cctx.builder,
920 ptr,
921 cmp,
922 new,
923 success,
924 failure,
925 ssid,
926 ))
927 }
928}
929
930#[op_interface_impl]
931impl ToLLVMValue for FenceOp {
932 fn convert(
933 &self,
934 ctx: &Context,
935 llvm_ctx: &LLVMContext,
936 cctx: &mut ConversionContext,
937 ) -> Result<LLVMValue> {
938 let ordering = convert_atomic_ordering(
939 &self
940 .get_attr_llvm_fence_ordering(ctx)
941 .expect("fence missing ordering"),
942 );
943 let scope = self
944 .get_attr_llvm_fence_syncscope(ctx)
945 .map(|s| String::from((*s).clone()))
946 .unwrap_or_default();
947 let ssid = llvm_get_sync_scope_id(llvm_ctx, &scope);
948 Ok(llvm_build_fence(&cctx.builder, ordering, ssid, ""))
949 }
950}
951
952#[op_interface_impl]
953impl ToLLVMValue for AtomicLoadOp {
954 fn convert(
955 &self,
956 ctx: &Context,
957 llvm_ctx: &LLVMContext,
958 cctx: &mut ConversionContext,
959 ) -> Result<LLVMValue> {
960 let (ptr_opd, result_val) = {
961 let op = self.get_operation().deref(ctx);
962 (op.get_operand(0), op.get_result(0))
963 };
964 let pointee_ty = convert_type(ctx, llvm_ctx, cctx, result_val.get_type(ctx))?;
965 let ptr = convert_value_operand(cctx, ctx, &ptr_opd)?;
966 let load = llvm_build_load2(&cctx.builder, pointee_ty, ptr, &result_val.unique_name(ctx));
967 let ordering = convert_atomic_ordering(
968 &self
969 .get_attr_llvm_ld_ordering(ctx)
970 .expect("atomic load missing ordering"),
971 );
972 llvm_set_ordering(load, ordering);
973 let scope = self
974 .get_attr_llvm_ld_syncscope(ctx)
975 .map(|s| String::from((*s).clone()))
976 .unwrap_or_default();
977 llvm_set_atomic_sync_scope_id(load, llvm_get_sync_scope_id(llvm_ctx, &scope));
978 if let Some(alignment) = self.alignment(ctx) {
979 llvm_set_alignment(load, alignment);
980 }
981 Ok(load)
982 }
983}
984
985#[op_interface_impl]
986impl ToLLVMValue for AtomicStoreOp {
987 fn convert(
988 &self,
989 ctx: &Context,
990 llvm_ctx: &LLVMContext,
991 cctx: &mut ConversionContext,
992 ) -> Result<LLVMValue> {
993 let (val_opd, ptr_opd) = {
994 let op = self.get_operation().deref(ctx);
995 (op.get_operand(0), op.get_operand(1))
996 };
997 let value = convert_value_operand(cctx, ctx, &val_opd)?;
998 let ptr = convert_value_operand(cctx, ctx, &ptr_opd)?;
999 let store = llvm_build_store(&cctx.builder, value, ptr);
1000 let ordering = convert_atomic_ordering(
1001 &self
1002 .get_attr_llvm_st_ordering(ctx)
1003 .expect("atomic store missing ordering"),
1004 );
1005 llvm_set_ordering(store, ordering);
1006 let scope = self
1007 .get_attr_llvm_st_syncscope(ctx)
1008 .map(|s| String::from((*s).clone()))
1009 .unwrap_or_default();
1010 llvm_set_atomic_sync_scope_id(store, llvm_get_sync_scope_id(llvm_ctx, &scope));
1011 if let Some(alignment) = self.alignment(ctx) {
1012 llvm_set_alignment(store, alignment);
1013 }
1014 Ok(store)
1015 }
1016}
1017
1018#[op_interface_impl]
1019impl ToLLVMValue for InlineAsmOp {
1020 fn convert(
1021 &self,
1022 ctx: &Context,
1023 llvm_ctx: &LLVMContext,
1024 cctx: &mut ConversionContext,
1025 ) -> Result<LLVMValue> {
1026 let (arg_opds, result_val) = {
1027 let op = self.get_operation().deref(ctx);
1028 let n = op.get_num_operands();
1029 let args: Vec<Value> = (0..n).map(|i| op.get_operand(i)).collect();
1030 (args, op.get_result(0))
1031 };
1032 let args: Vec<LLVMValue> = arg_opds
1033 .iter()
1034 .map(|v| convert_value_operand(cctx, ctx, v))
1035 .collect::<Result<_>>()?;
1036 let result_ty = result_val.get_type(ctx);
1037 let result_llvm_ty = convert_type(ctx, llvm_ctx, cctx, result_ty)?;
1038 let arg_types: Vec<LLVMType> = args.iter().map(|a| llvm_type_of(*a)).collect();
1039 let fn_ty = llvm_function_type(result_llvm_ty, &arg_types, false);
1040 let asm = String::from(
1041 (*self
1042 .get_attr_inline_asm_template(ctx)
1043 .expect("inline asm missing template"))
1044 .clone(),
1045 );
1046 let constraints = String::from(
1047 (*self
1048 .get_attr_inline_asm_constraints(ctx)
1049 .expect("inline asm missing constraints"))
1050 .clone(),
1051 );
1052 let asm_val = llvm_get_inline_asm(
1058 fn_ty,
1059 &asm,
1060 &constraints,
1061 true,
1062 false,
1063 LLVMInlineAsmDialect::LLVMInlineAsmDialectATT,
1064 false,
1065 );
1066 let name = if result_ty.deref(ctx).is::<VoidType>() {
1067 String::new()
1068 } else {
1069 result_val.unique_name(ctx).to_string()
1070 };
1071 Ok(llvm_build_call2(
1072 &cctx.builder,
1073 fn_ty,
1074 asm_val,
1075 &args,
1076 &name,
1077 ))
1078 }
1079}
1080
1081#[op_interface_impl]
1082impl ToLLVMValue for ICmpOp {
1083 fn convert(
1084 &self,
1085 ctx: &Context,
1086 _llvm_ctx: &LLVMContext,
1087 cctx: &mut ConversionContext,
1088 ) -> Result<LLVMValue> {
1089 let op = self.get_operation().deref(ctx);
1090 let predicate = convert_ipredicate(self.predicate(ctx));
1091 let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1092 let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1093 let icmp_op = llvm_build_icmp(
1094 &cctx.builder,
1095 predicate,
1096 lhs,
1097 rhs,
1098 &self.get_result(ctx).unique_name(ctx),
1099 );
1100 Ok(icmp_op)
1101 }
1102}
1103
1104#[op_interface_impl]
1105impl ToLLVMValue for ReturnOp {
1106 fn convert(
1107 &self,
1108 ctx: &Context,
1109 _llvm_ctx: &LLVMContext,
1110 cctx: &mut ConversionContext,
1111 ) -> Result<LLVMValue> {
1112 let ret_op = if let Some(retval) = self.retval(ctx) {
1113 let retval = convert_value_operand(cctx, ctx, &retval)?;
1114 llvm_build_ret(&cctx.builder, retval)
1115 } else {
1116 llvm_build_ret_void(&cctx.builder)
1117 };
1118 Ok(ret_op)
1119 }
1120}
1121
1122#[op_interface_impl]
1123impl ToLLVMValue for UnreachableOp {
1124 fn convert(
1125 &self,
1126 _ctx: &Context,
1127 _llvm_ctx: &LLVMContext,
1128 cctx: &mut ConversionContext,
1129 ) -> Result<LLVMValue> {
1130 Ok(llvm_build_unreachable(&cctx.builder))
1131 }
1132}
1133
1134#[op_interface_impl]
1135impl ToLLVMValue for ConstantOp {
1136 fn convert(
1137 &self,
1138 ctx: &Context,
1139 llvm_ctx: &LLVMContext,
1140 cctx: &mut ConversionContext,
1141 ) -> Result<LLVMValue> {
1142 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1143 }
1144}
1145
1146#[op_interface_impl]
1147impl ToLLVMValue for ZeroOp {
1148 fn convert(
1149 &self,
1150 ctx: &Context,
1151 llvm_ctx: &LLVMContext,
1152 cctx: &mut ConversionContext,
1153 ) -> Result<LLVMValue> {
1154 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1155 }
1156}
1157
1158#[op_interface_impl]
1159impl ToLLVMValue for IntToPtrOp {
1160 fn convert(
1161 &self,
1162 ctx: &Context,
1163 llvm_ctx: &LLVMContext,
1164 cctx: &mut ConversionContext,
1165 ) -> Result<LLVMValue> {
1166 let op = self.get_operation().deref(ctx);
1167 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1168 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1169 let inttoptr_op = llvm_build_int_to_ptr(
1170 &cctx.builder,
1171 arg,
1172 ty,
1173 &self.get_result(ctx).unique_name(ctx),
1174 );
1175 Ok(inttoptr_op)
1176 }
1177}
1178
1179#[op_interface_impl]
1180impl ToLLVMValue for PtrToIntOp {
1181 fn convert(
1182 &self,
1183 ctx: &Context,
1184 llvm_ctx: &LLVMContext,
1185 cctx: &mut ConversionContext,
1186 ) -> Result<LLVMValue> {
1187 let op = self.get_operation().deref(ctx);
1188 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1189 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1190 let ptrtoint_op = llvm_build_ptr_to_int(
1191 &cctx.builder,
1192 arg,
1193 ty,
1194 &self.get_result(ctx).unique_name(ctx),
1195 );
1196 Ok(ptrtoint_op)
1197 }
1198}
1199
1200#[op_interface_impl]
1201impl ToLLVMValue for UndefOp {
1202 fn convert(
1203 &self,
1204 ctx: &Context,
1205 llvm_ctx: &LLVMContext,
1206 cctx: &mut ConversionContext,
1207 ) -> Result<LLVMValue> {
1208 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1209 }
1210}
1211
1212#[op_interface_impl]
1213impl ToLLVMValue for PoisonOp {
1214 fn convert(
1215 &self,
1216 ctx: &Context,
1217 llvm_ctx: &LLVMContext,
1218 cctx: &mut ConversionContext,
1219 ) -> Result<LLVMValue> {
1220 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1221 }
1222}
1223
1224#[op_interface_impl]
1225impl ToLLVMValue for AddressOfOp {
1226 fn convert(
1227 &self,
1228 ctx: &Context,
1229 llvm_ctx: &LLVMContext,
1230 cctx: &mut ConversionContext,
1231 ) -> Result<LLVMValue> {
1232 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1233 }
1234}
1235
1236#[op_interface_impl]
1237impl ToLLVMValue for BlockAddressOp {
1238 fn convert(
1239 &self,
1240 ctx: &Context,
1241 llvm_ctx: &LLVMContext,
1242 cctx: &mut ConversionContext,
1243 ) -> Result<LLVMValue> {
1244 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
1245 }
1246}
1247
1248#[op_interface_impl]
1249impl ToLLVMValue for BlockTagOp {
1250 fn convert(
1251 &self,
1252 ctx: &Context,
1253 llvm_ctx: &LLVMContext,
1254 cctx: &mut ConversionContext,
1255 ) -> Result<LLVMValue> {
1256 let cur_block = self
1257 .get_operation()
1258 .deref(ctx)
1259 .get_parent_block()
1260 .expect("BlockTagOp must be in a basic block");
1261 let cur_func = cur_block
1262 .deref(ctx)
1263 .get_parent_op(ctx)
1264 .expect("BlockTagOp must be in a basic block of a function");
1265 let cur_func =
1266 Operation::get_op::<FuncOp>(cur_func, ctx).expect("Block's parent op must be FuncOp");
1267 let cur_func_name = cur_func.get_symbol_name(ctx);
1268 let tag = self.get_tag_id(ctx);
1269
1270 let cur_llvm_block = cctx
1271 .block_map
1272 .get(&cur_block)
1273 .expect("Current block must be in block_map");
1274
1275 cctx.block_tags
1277 .insert((cur_func_name, tag), *cur_llvm_block);
1278
1279 Ok(llvm_const_null(llvm_pointer_type_in_context(llvm_ctx, 0)))
1282 }
1283}
1284
1285#[op_interface_impl]
1286impl ToLLVMValue for FreezeOp {
1287 fn convert(
1288 &self,
1289 ctx: &Context,
1290 _llvm_ctx: &LLVMContext,
1291 cctx: &mut ConversionContext,
1292 ) -> Result<LLVMValue> {
1293 let op = self.get_operation().deref(ctx);
1294 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1295 let freeze_op =
1296 llvm_build_freeze(&cctx.builder, arg, &self.get_result(ctx).unique_name(ctx));
1297 Ok(freeze_op)
1298 }
1299}
1300
1301#[op_interface_impl]
1302impl ToLLVMValue for CallOp {
1303 fn convert(
1304 &self,
1305 ctx: &Context,
1306 llvm_ctx: &LLVMContext,
1307 cctx: &mut ConversionContext,
1308 ) -> Result<LLVMValue> {
1309 let args: Vec<_> = self
1310 .args(ctx)
1311 .into_iter()
1312 .map(|v| convert_value_operand(cctx, ctx, &v))
1313 .collect::<Result<_>>()?;
1314 let ty = convert_type(ctx, llvm_ctx, cctx, self.callee_type(ctx))?;
1315 let res = self.get_result(ctx);
1316 let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
1317 ""
1318 } else {
1319 &res.unique_name(ctx)
1320 };
1321 let callee = match self.callee(ctx) {
1322 CallOpCallable::Direct(callee_sym) => {
1323 *cctx.function_map.get(&callee_sym).ok_or_else(|| {
1324 input_error_noloc!(ToLLVMErr::UndefinedValue(callee_sym.to_string()))
1325 })?
1326 }
1327 CallOpCallable::Indirect(callee) => convert_value_operand(cctx, ctx, &callee)?,
1328 };
1329 let call_val = llvm_build_call2(&cctx.builder, ty, callee, &args, name);
1330 if let Some(fmf) = self.get_attr_llvm_call_fastmath_flags(ctx)
1331 && llvm_can_value_use_fast_math_flags(call_val)
1332 {
1333 llvm_set_fast_math_flags(call_val, (*fmf).into());
1334 }
1335 Ok(call_val)
1336 }
1337}
1338
1339#[op_interface_impl]
1340impl ToLLVMValue for CallIntrinsicOp {
1341 fn convert(
1342 &self,
1343 ctx: &Context,
1344 llvm_ctx: &LLVMContext,
1345 cctx: &mut ConversionContext,
1346 ) -> Result<LLVMValue> {
1347 let op = self.get_operation().deref(ctx);
1348 let args: Vec<_> = (0..op.get_num_operands())
1349 .map(|i| convert_value_operand(cctx, ctx, &op.get_operand(i)))
1350 .collect::<Result<_>>()?;
1351 let fn_ty = convert_type(
1352 ctx,
1353 llvm_ctx,
1354 cctx,
1355 self.get_attr_llvm_intrinsic_type(ctx)
1356 .unwrap()
1357 .get_type(ctx),
1358 )?;
1359
1360 let intrinsic_name = <StringAttr as Into<String>>::into(
1361 self.get_attr_llvm_intrinsic_name(ctx)
1362 .expect("Intrinsic call does not name the intrinsic to be called")
1363 .clone(),
1364 );
1365
1366 let _intrinsic_id = llvm_lookup_intrinsic_id(&intrinsic_name).ok_or_else(|| {
1367 input_error_noloc!(ToLLVMErr::UndefinedValue(intrinsic_name.to_string()))
1368 })?;
1369
1370 let intrinsic_fn = llvm_get_named_function(cctx.cur_llvm_module, &intrinsic_name)
1376 .unwrap_or_else(|| llvm_add_function(cctx.cur_llvm_module, &intrinsic_name, fn_ty));
1377
1378 let res = self.get_result(ctx);
1379 let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
1380 ""
1381 } else {
1382 &res.unique_name(ctx)
1383 };
1384
1385 let intrinsic_op = llvm_build_call2(&cctx.builder, fn_ty, intrinsic_fn, &args, name);
1386
1387 if let Some(fmf) = self.get_attr_llvm_intrinsic_fastmath_flags(ctx)
1388 && llvm_can_value_use_fast_math_flags(intrinsic_op)
1389 {
1390 llvm_set_fast_math_flags(intrinsic_op, (*fmf).into());
1391 }
1392
1393 Ok(intrinsic_op)
1394 }
1395}
1396
1397#[op_interface_impl]
1398impl ToLLVMValue for SExtOp {
1399 fn convert(
1400 &self,
1401 ctx: &Context,
1402 llvm_ctx: &LLVMContext,
1403 cctx: &mut ConversionContext,
1404 ) -> Result<LLVMValue> {
1405 let op = self.get_operation().deref(ctx);
1406 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1407 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1408 let sext_op = llvm_build_sext(
1409 &cctx.builder,
1410 arg,
1411 ty,
1412 &self.get_result(ctx).unique_name(ctx),
1413 );
1414 Ok(sext_op)
1415 }
1416}
1417
1418#[op_interface_impl]
1419impl ToLLVMValue for ZExtOp {
1420 fn convert(
1421 &self,
1422 ctx: &Context,
1423 llvm_ctx: &LLVMContext,
1424 cctx: &mut ConversionContext,
1425 ) -> Result<LLVMValue> {
1426 let op = self.get_operation().deref(ctx);
1427 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1428 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1429 let zext_op = llvm_build_zext(
1430 &cctx.builder,
1431 arg,
1432 ty,
1433 &self.get_result(ctx).unique_name(ctx),
1434 );
1435 if llvm_is_a::instruction(zext_op) {
1437 let nneg = self.nneg(ctx);
1438 llvm_set_nneg(zext_op, nneg);
1439 }
1440 Ok(zext_op)
1441 }
1442}
1443
1444#[op_interface_impl]
1445impl ToLLVMValue for TruncOp {
1446 fn convert(
1447 &self,
1448 ctx: &Context,
1449 llvm_ctx: &LLVMContext,
1450 cctx: &mut ConversionContext,
1451 ) -> Result<LLVMValue> {
1452 let op = self.get_operation().deref(ctx);
1453 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1454 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1455 let trunc_op = llvm_build_trunc(
1456 &cctx.builder,
1457 arg,
1458 ty,
1459 &self.get_result(ctx).unique_name(ctx),
1460 );
1461 Ok(trunc_op)
1462 }
1463}
1464
1465#[op_interface_impl]
1466impl ToLLVMValue for GetElementPtrOp {
1467 fn convert(
1468 &self,
1469 ctx: &Context,
1470 llvm_ctx: &LLVMContext,
1471 cctx: &mut ConversionContext,
1472 ) -> Result<LLVMValue> {
1473 let indices = self
1474 .indices(ctx)
1475 .iter()
1476 .map(|v| match v {
1477 crate::ops::GepIndex::Constant(c) => Ok(llvm_const_int(
1478 llvm_int_type_in_context(llvm_ctx, 32),
1479 Into::<u64>::into(*c),
1480 false,
1481 )),
1482 crate::ops::GepIndex::Value(value) => convert_value_operand(cctx, ctx, value),
1483 })
1484 .collect::<Result<Vec<_>>>()?;
1485
1486 let base = convert_value_operand(cctx, ctx, &self.get_operand_src_ptr(ctx))?;
1487
1488 let src_elem_type = convert_type(ctx, llvm_ctx, cctx, self.src_elem_type(ctx))?;
1489 let gep_op = llvm_build_gep2(
1490 &cctx.builder,
1491 src_elem_type,
1492 base,
1493 &indices,
1494 &self.get_result(ctx).unique_name(ctx),
1495 );
1496 Ok(gep_op)
1497 }
1498}
1499
1500#[op_interface_impl]
1501impl ToLLVMValue for InsertValueOp {
1502 fn convert(
1503 &self,
1504 ctx: &Context,
1505 _llvm_ctx: &LLVMContext,
1506 cctx: &mut ConversionContext,
1507 ) -> Result<LLVMValue> {
1508 let op = self.get_operation().deref(ctx);
1509 let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1510 let value = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1511 let indices = self.indices(ctx);
1512 if indices.len() != 1 {
1513 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1514 }
1515 let insert_op = llvm_build_insert_value(
1516 &cctx.builder,
1517 base,
1518 value,
1519 indices[0],
1520 &self.get_result(ctx).unique_name(ctx),
1521 );
1522 Ok(insert_op)
1523 }
1524}
1525
1526#[op_interface_impl]
1527impl ToLLVMValue for ExtractValueOp {
1528 fn convert(
1529 &self,
1530 ctx: &Context,
1531 _llvm_ctx: &LLVMContext,
1532 cctx: &mut ConversionContext,
1533 ) -> Result<LLVMValue> {
1534 let op = self.get_operation().deref(ctx);
1535 let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1536 let indices = self.indices(ctx);
1537 if indices.len() != 1 {
1538 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1539 }
1540 let extract_op = llvm_build_extract_value(
1541 &cctx.builder,
1542 base,
1543 indices[0],
1544 &self.get_result(ctx).unique_name(ctx),
1545 );
1546 Ok(extract_op)
1547 }
1548}
1549
1550#[op_interface_impl]
1551impl ToLLVMValue for InsertElementOp {
1552 fn convert(
1553 &self,
1554 ctx: &Context,
1555 _llvm_ctx: &LLVMContext,
1556 cctx: &mut ConversionContext,
1557 ) -> Result<LLVMValue> {
1558 let base = convert_value_operand(cctx, ctx, &self.get_operand_vector(ctx))?;
1559 let value = convert_value_operand(cctx, ctx, &self.get_operand_element(ctx))?;
1560 let index = convert_value_operand(cctx, ctx, &self.get_operand_index(ctx))?;
1561 let insert_op = llvm_build_insert_element(
1562 &cctx.builder,
1563 base,
1564 value,
1565 index,
1566 &self.get_result(ctx).unique_name(ctx),
1567 );
1568 Ok(insert_op)
1569 }
1570}
1571
1572#[op_interface_impl]
1573impl ToLLVMValue for ExtractElementOp {
1574 fn convert(
1575 &self,
1576 ctx: &Context,
1577 _llvm_ctx: &LLVMContext,
1578 cctx: &mut ConversionContext,
1579 ) -> Result<LLVMValue> {
1580 let base = convert_value_operand(cctx, ctx, &self.get_operand_vector(ctx))?;
1581 let index = convert_value_operand(cctx, ctx, &self.get_operand_index(ctx))?;
1582 let extract_op = llvm_build_extract_element(
1583 &cctx.builder,
1584 base,
1585 index,
1586 &self.get_result(ctx).unique_name(ctx),
1587 );
1588 Ok(extract_op)
1589 }
1590}
1591
1592#[op_interface_impl]
1593impl ToLLVMValue for ShuffleVectorOp {
1594 fn convert(
1595 &self,
1596 ctx: &Context,
1597 llvm_ctx: &LLVMContext,
1598 cctx: &mut ConversionContext,
1599 ) -> Result<LLVMValue> {
1600 let mask = &self
1601 .get_attr_llvm_shuffle_vector_mask(ctx)
1602 .expect("ShuffleVectorOp missing mask attribute")
1603 .0;
1604 let op = self.get_operation().deref(ctx);
1605 let vec1 = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1606 let vec2 = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1607 let int_ty = llvm_int_type_in_context(llvm_ctx, 32);
1608
1609 let mask = mask
1610 .iter()
1611 .map(|&i| llvm_const_int(int_ty, i as u64, true))
1612 .collect::<Vec<LLVMValue>>();
1613 let mask = llvm_const_vector(&mask);
1614
1615 let shuffle_op = llvm_build_shuffle_vector(
1616 &cctx.builder,
1617 vec1,
1618 vec2,
1619 mask,
1620 &self.get_result(ctx).unique_name(ctx),
1621 );
1622 Ok(shuffle_op)
1623 }
1624}
1625
1626#[op_interface_impl]
1627impl ToLLVMValue for SelectOp {
1628 fn convert(
1629 &self,
1630 ctx: &Context,
1631 _llvm_ctx: &LLVMContext,
1632 cctx: &mut ConversionContext,
1633 ) -> Result<LLVMValue> {
1634 let op = self.get_operation().deref(ctx);
1635 let cond = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1636 let true_val = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1637 let false_val = convert_value_operand(cctx, ctx, &op.get_operand(2))?;
1638 let select_op = llvm_build_select(
1639 &cctx.builder,
1640 cond,
1641 true_val,
1642 false_val,
1643 &self.get_result(ctx).unique_name(ctx),
1644 );
1645 if let Some(fmf) = self.get_attr_llvm_select_fast_math_flags(ctx)
1647 && llvm_can_value_use_fast_math_flags(select_op)
1648 {
1649 llvm_set_fast_math_flags(select_op, (*fmf).into());
1650 }
1651 Ok(select_op)
1652 }
1653}
1654
1655#[op_interface_impl]
1656impl ToLLVMValue for FAddOp {
1657 fn convert(
1658 &self,
1659 ctx: &Context,
1660 _llvm_ctx: &LLVMContext,
1661 cctx: &mut ConversionContext,
1662 ) -> Result<LLVMValue> {
1663 let op = self.get_operation().deref(ctx);
1664 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1665 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1666 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1667 let inst = llvm_build_fadd(
1668 &cctx.builder,
1669 lhs,
1670 rhs,
1671 &self.get_result(ctx).unique_name(ctx),
1672 );
1673 if llvm_can_value_use_fast_math_flags(inst) {
1675 let fastmath = self.fast_math_flags(ctx);
1676 llvm_set_fast_math_flags(inst, fastmath.into());
1677 }
1678 Ok(inst)
1679 }
1680}
1681
1682#[op_interface_impl]
1683impl ToLLVMValue for FSubOp {
1684 fn convert(
1685 &self,
1686 ctx: &Context,
1687 _llvm_ctx: &LLVMContext,
1688 cctx: &mut ConversionContext,
1689 ) -> Result<LLVMValue> {
1690 let op = self.get_operation().deref(ctx);
1691 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1692 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1693 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1694 let inst = llvm_build_fsub(
1695 &cctx.builder,
1696 lhs,
1697 rhs,
1698 &self.get_result(ctx).unique_name(ctx),
1699 );
1700 if llvm_can_value_use_fast_math_flags(inst) {
1702 let fastmath = self.fast_math_flags(ctx);
1703 llvm_set_fast_math_flags(inst, fastmath.into());
1704 }
1705 Ok(inst)
1706 }
1707}
1708
1709#[op_interface_impl]
1710impl ToLLVMValue for FMulOp {
1711 fn convert(
1712 &self,
1713 ctx: &Context,
1714 _llvm_ctx: &LLVMContext,
1715 cctx: &mut ConversionContext,
1716 ) -> Result<LLVMValue> {
1717 let op = self.get_operation().deref(ctx);
1718 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1719 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1720 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1721 let inst = llvm_build_fmul(
1722 &cctx.builder,
1723 lhs,
1724 rhs,
1725 &self.get_result(ctx).unique_name(ctx),
1726 );
1727 if llvm_can_value_use_fast_math_flags(inst) {
1729 let fastmath = self.fast_math_flags(ctx);
1730 llvm_set_fast_math_flags(inst, fastmath.into());
1731 }
1732 Ok(inst)
1733 }
1734}
1735
1736#[op_interface_impl]
1737impl ToLLVMValue for FDivOp {
1738 fn convert(
1739 &self,
1740 ctx: &Context,
1741 _llvm_ctx: &LLVMContext,
1742 cctx: &mut ConversionContext,
1743 ) -> Result<LLVMValue> {
1744 let op = self.get_operation().deref(ctx);
1745 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1746 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1747 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1748 let inst = llvm_build_fdiv(
1749 &cctx.builder,
1750 lhs,
1751 rhs,
1752 &self.get_result(ctx).unique_name(ctx),
1753 );
1754 if llvm_can_value_use_fast_math_flags(inst) {
1756 let fastmath = self.fast_math_flags(ctx);
1757 llvm_set_fast_math_flags(inst, fastmath.into());
1758 }
1759 Ok(inst)
1760 }
1761}
1762
1763#[op_interface_impl]
1764impl ToLLVMValue for FRemOp {
1765 fn convert(
1766 &self,
1767 ctx: &Context,
1768 _llvm_ctx: &LLVMContext,
1769 cctx: &mut ConversionContext,
1770 ) -> Result<LLVMValue> {
1771 let op = self.get_operation().deref(ctx);
1772 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1773 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1774 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1775 let inst = llvm_build_frem(
1776 &cctx.builder,
1777 lhs,
1778 rhs,
1779 &self.get_result(ctx).unique_name(ctx),
1780 );
1781 if llvm_can_value_use_fast_math_flags(inst) {
1783 let fastmath = self.fast_math_flags(ctx);
1784 llvm_set_fast_math_flags(inst, fastmath.into());
1785 }
1786 Ok(inst)
1787 }
1788}
1789
1790#[op_interface_impl]
1791impl ToLLVMValue for FCmpOp {
1792 fn convert(
1793 &self,
1794 ctx: &Context,
1795 _llvm_ctx: &LLVMContext,
1796 cctx: &mut ConversionContext,
1797 ) -> Result<LLVMValue> {
1798 let op = self.get_operation().deref(ctx);
1799 let predicate = convert_fpredicate(self.predicate(ctx));
1800 let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1801 let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1802 let fcmp_op = llvm_build_fcmp(
1803 &cctx.builder,
1804 predicate,
1805 lhs,
1806 rhs,
1807 &self.get_result(ctx).unique_name(ctx),
1808 );
1809 if llvm_can_value_use_fast_math_flags(fcmp_op) {
1811 let fastmath = self.fast_math_flags(ctx);
1812 llvm_set_fast_math_flags(fcmp_op, fastmath.into());
1813 }
1814 Ok(fcmp_op)
1815 }
1816}
1817
1818#[op_interface_impl]
1819impl ToLLVMValue for FNegOp {
1820 fn convert(
1821 &self,
1822 ctx: &Context,
1823 _llvm_ctx: &LLVMContext,
1824 cctx: &mut ConversionContext,
1825 ) -> Result<LLVMValue> {
1826 let op = self.get_operation().deref(ctx);
1827 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1828 let inst = llvm_build_fneg(&cctx.builder, arg, &self.get_result(ctx).unique_name(ctx));
1829 if llvm_can_value_use_fast_math_flags(inst) {
1831 let fastmath = self.fast_math_flags(ctx);
1832 llvm_set_fast_math_flags(inst, fastmath.into());
1833 }
1834 Ok(inst)
1835 }
1836}
1837
1838#[op_interface_impl]
1839impl ToLLVMValue for FPExtOp {
1840 fn convert(
1841 &self,
1842 ctx: &Context,
1843 llvm_ctx: &LLVMContext,
1844 cctx: &mut ConversionContext,
1845 ) -> Result<LLVMValue> {
1846 let op = self.get_operation().deref(ctx);
1847 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1848 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1849 let fpext_op = llvm_build_fpext(
1850 &cctx.builder,
1851 arg,
1852 ty,
1853 &self.get_result(ctx).unique_name(ctx),
1854 );
1855 if llvm_can_value_use_fast_math_flags(fpext_op) {
1857 let fastmath = self.fast_math_flags(ctx);
1858 llvm_set_fast_math_flags(fpext_op, fastmath.into());
1859 }
1860 Ok(fpext_op)
1861 }
1862}
1863
1864#[op_interface_impl]
1865impl ToLLVMValue for FPTruncOp {
1866 fn convert(
1867 &self,
1868 ctx: &Context,
1869 llvm_ctx: &LLVMContext,
1870 cctx: &mut ConversionContext,
1871 ) -> Result<LLVMValue> {
1872 let op = self.get_operation().deref(ctx);
1873 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1874 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1875 let fptrunc_op = llvm_build_fptrunc(
1876 &cctx.builder,
1877 arg,
1878 ty,
1879 &self.get_result(ctx).unique_name(ctx),
1880 );
1881 if llvm_can_value_use_fast_math_flags(fptrunc_op) {
1883 llvm_set_fast_math_flags(fptrunc_op, self.fast_math_flags(ctx).into());
1884 }
1885 Ok(fptrunc_op)
1886 }
1887}
1888
1889#[op_interface_impl]
1890impl ToLLVMValue for FPToSIOp {
1891 fn convert(
1892 &self,
1893 ctx: &Context,
1894 llvm_ctx: &LLVMContext,
1895 cctx: &mut ConversionContext,
1896 ) -> Result<LLVMValue> {
1897 let op = self.get_operation().deref(ctx);
1898 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1899 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1900 let fptosi_op = llvm_build_fptosi(
1901 &cctx.builder,
1902 arg,
1903 ty,
1904 &self.get_result(ctx).unique_name(ctx),
1905 );
1906 Ok(fptosi_op)
1907 }
1908}
1909
1910#[op_interface_impl]
1911impl ToLLVMValue for SIToFPOp {
1912 fn convert(
1913 &self,
1914 ctx: &Context,
1915 llvm_ctx: &LLVMContext,
1916 cctx: &mut ConversionContext,
1917 ) -> Result<LLVMValue> {
1918 let op = self.get_operation().deref(ctx);
1919 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1920 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1921 let sitofp_op = llvm_build_sitofp(
1922 &cctx.builder,
1923 arg,
1924 ty,
1925 &self.get_result(ctx).unique_name(ctx),
1926 );
1927 Ok(sitofp_op)
1928 }
1929}
1930
1931#[op_interface_impl]
1932impl ToLLVMValue for FPToUIOp {
1933 fn convert(
1934 &self,
1935 ctx: &Context,
1936 llvm_ctx: &LLVMContext,
1937 cctx: &mut ConversionContext,
1938 ) -> Result<LLVMValue> {
1939 let op = self.get_operation().deref(ctx);
1940 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1941 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1942 let fptoui_op = llvm_build_fptoui(
1943 &cctx.builder,
1944 arg,
1945 ty,
1946 &self.get_result(ctx).unique_name(ctx),
1947 );
1948 Ok(fptoui_op)
1949 }
1950}
1951
1952#[op_interface_impl]
1953impl ToLLVMValue for UIToFPOp {
1954 fn convert(
1955 &self,
1956 ctx: &Context,
1957 llvm_ctx: &LLVMContext,
1958 cctx: &mut ConversionContext,
1959 ) -> Result<LLVMValue> {
1960 let op = self.get_operation().deref(ctx);
1961 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1962 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1963 let uitofp_op = llvm_build_uitofp(
1964 &cctx.builder,
1965 arg,
1966 ty,
1967 &self.get_result(ctx).unique_name(ctx),
1968 );
1969 if llvm_is_a::instruction(uitofp_op) {
1971 let nneg = self.nneg(ctx);
1972 llvm_set_nneg(uitofp_op, nneg);
1973 }
1974 Ok(uitofp_op)
1975 }
1976}
1977
1978#[op_interface_impl]
1979impl ToLLVMValue for VAArgOp {
1980 fn convert(
1981 &self,
1982 ctx: &Context,
1983 llvm_ctx: &LLVMContext,
1984 cctx: &mut ConversionContext,
1985 ) -> Result<LLVMValue> {
1986 let op = self.get_operation().deref(ctx);
1987 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1988 let opd = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1989 log::warn!("Generating va_arg instruction: It is poorly supported by LLVM");
1990 let vaarg_op = llvm_build_va_arg(
1991 &cctx.builder,
1992 opd,
1993 ty,
1994 &self.get_result(ctx).unique_name(ctx),
1995 );
1996 Ok(vaarg_op)
1997 }
1998}
1999
2000fn convert_block(
2002 ctx: &Context,
2003 llvm_ctx: &LLVMContext,
2004 cctx: &mut ConversionContext,
2005 block: Ptr<BasicBlock>,
2006) -> Result<()> {
2007 let block_llvm = cctx.block_map[&block];
2008 llvm_position_builder_at_end(&cctx.builder, block_llvm);
2009
2010 for opr in block.deref(ctx).iter(ctx) {
2011 let op = Operation::get_op_dyn(opr, ctx);
2012 let op = op.as_ref();
2013 let Some(op_conv) = op_cast::<dyn ToLLVMValue>(op) else {
2014 let loc = op.loc(ctx);
2015 return input_err!(
2016 loc,
2017 ToLLVMErr::MissingOpConversion(op.get_opid().to_string())
2018 );
2019 };
2020 let op_llvm = op_conv.convert(ctx, llvm_ctx, cctx)?;
2021 let opr_ref = opr.deref(ctx);
2022 if opr_ref.get_num_results() == 1 {
2024 cctx.value_map.insert(opr_ref.get_result(0), op_llvm);
2025 }
2026 }
2027
2028 Ok(())
2029}
2030
2031fn convert_function(
2033 ctx: &Context,
2034 llvm_ctx: &LLVMContext,
2035 cctx: &mut ConversionContext,
2036 func_op: FuncOp,
2037) -> Result<LLVMValue> {
2038 cctx.clear_per_function_data();
2039 let func_llvm = cctx.function_map[&func_op.get_symbol_name(ctx)];
2040
2041 if let Some(linkage) = func_op.get_attr_llvm_function_linkage(ctx) {
2042 let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
2043 llvm_set_linkage(func_llvm, llvm_linkage);
2044 }
2045
2046 let f_region = func_op.get_region(ctx).expect("Function missing region");
2047
2048 let mut block_iter = f_region.deref(ctx).iter(ctx);
2050 {
2051 let entry = block_iter.next().expect("Missing entry block");
2052 for (arg_idx, arg) in entry.deref(ctx).arguments().enumerate() {
2054 cctx.value_map
2055 .insert(arg, llvm_get_param(func_llvm, arg_idx.try_into().unwrap()));
2056 }
2057 let llvm_entry_block = llvm_append_basic_block_in_context(
2058 llvm_ctx,
2059 func_llvm,
2060 &entry.deref(ctx).unique_name(ctx),
2061 );
2062 cctx.block_map.insert(entry, llvm_entry_block);
2063 }
2064 for block in block_iter {
2065 let llvm_block = llvm_append_basic_block_in_context(
2066 llvm_ctx,
2067 func_llvm,
2068 &block.deref(ctx).unique_name(ctx),
2069 );
2070 llvm_position_builder_at_end(&cctx.builder, llvm_block);
2071 for arg in block.deref(ctx).arguments() {
2072 let arg_type = convert_type(ctx, llvm_ctx, cctx, arg.get_type(ctx))?;
2073 let phi = llvm_build_phi(&cctx.builder, arg_type, &arg.unique_name(ctx));
2074 cctx.value_map.insert(arg, phi);
2075 }
2076 cctx.block_map.insert(block, llvm_block);
2077 }
2078
2079 for block in topological_order(ctx, &f_region) {
2081 convert_block(ctx, llvm_ctx, cctx, block)?;
2082 }
2083
2084 Ok(func_llvm)
2085}
2086
2087#[op_interface]
2088trait ToLLVMConstValue {
2089 fn convert(
2091 &self,
2092 ctx: &Context,
2093 llvm_ctx: &LLVMContext,
2094 cctx: &mut ConversionContext,
2095 ) -> Result<LLVMValue>;
2096
2097 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
2098 where
2099 Self: Sized,
2100 {
2101 Ok(())
2102 }
2103}
2104
2105#[op_interface_impl]
2106impl ToLLVMConstValue for ConstantOp {
2107 fn convert(
2108 &self,
2109 ctx: &Context,
2110 llvm_ctx: &LLVMContext,
2111 cctx: &mut ConversionContext,
2112 ) -> Result<LLVMValue> {
2113 let op = self.get_operation().deref(ctx);
2114 let value = self.get_value(ctx);
2115 if let Some(int_val) = value.downcast_ref::<IntegerAttr>() {
2116 let int_ty = int_val.get_type();
2117 let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
2118 let ap_int_val: APInt = int_val.clone().into();
2119 let const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
2120 Ok(const_val)
2121 } else if let Some(float_val) = attr_cast::<dyn FloatAttrToFP64>(&*value) {
2122 let float_ty = float_val.get_type(ctx);
2123 let float_ty_llvm = convert_type(ctx, llvm_ctx, cctx, float_ty)?;
2124 let const_val = llvm_const_real(float_ty_llvm, float_val.to_fp64());
2125 Ok(const_val)
2126 } else {
2127 input_err!(op.loc(), ToLLVMErr::ConstOpNotIntOrFloat)
2128 }
2129 }
2130}
2131
2132#[op_interface_impl]
2133impl ToLLVMConstValue for UndefOp {
2134 fn convert(
2135 &self,
2136 ctx: &Context,
2137 llvm_ctx: &LLVMContext,
2138 cctx: &mut ConversionContext,
2139 ) -> Result<LLVMValue> {
2140 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2141 Ok(llvm_get_undef(ty))
2142 }
2143}
2144
2145#[op_interface_impl]
2146impl ToLLVMConstValue for PoisonOp {
2147 fn convert(
2148 &self,
2149 ctx: &Context,
2150 llvm_ctx: &LLVMContext,
2151 cctx: &mut ConversionContext,
2152 ) -> Result<LLVMValue> {
2153 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2154 Ok(llvm_get_poison(ty))
2155 }
2156}
2157
2158#[op_interface_impl]
2159impl ToLLVMConstValue for ZeroOp {
2160 fn convert(
2161 &self,
2162 ctx: &Context,
2163 llvm_ctx: &LLVMContext,
2164 cctx: &mut ConversionContext,
2165 ) -> Result<LLVMValue> {
2166 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2167 let zero_val = llvm_const_null(ty);
2168 Ok(zero_val)
2169 }
2170}
2171
2172#[op_interface_impl]
2173impl ToLLVMConstValue for AddressOfOp {
2174 fn convert(
2175 &self,
2176 ctx: &Context,
2177 _llvm_ctx: &LLVMContext,
2178 cctx: &mut ConversionContext,
2179 ) -> Result<LLVMValue> {
2180 let sym = self.get_global_name(ctx);
2181 cctx.globals_map
2182 .get(&sym)
2183 .or_else(|| cctx.function_map.get(&sym))
2184 .cloned()
2185 .ok_or_else(|| input_error_noloc!(ToLLVMErr::CannotEvaluateToConst))
2186 }
2187}
2188
2189#[op_interface_impl]
2190impl ToLLVMConstValue for BlockAddressOp {
2191 fn convert(
2192 &self,
2193 ctx: &Context,
2194 llvm_ctx: &LLVMContext,
2195 cctx: &mut ConversionContext,
2196 ) -> Result<LLVMValue> {
2197 let tag = self.get_tag_id(ctx);
2198 let func = self.get_function_name(ctx);
2199
2200 let result_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2210 let addr_space = llvm_get_pointer_address_space(result_ty);
2211 let placeholder = llvm_add_global_in_address_space(
2212 cctx.cur_llvm_module,
2213 llvm_int_type_in_context(llvm_ctx, 8),
2214 "blockaddress_placeholder",
2215 addr_space,
2216 );
2217
2218 cctx.pending_block_address_ops
2219 .insert(placeholder, (func, tag));
2220 Ok(placeholder)
2221 }
2222}
2223
2224#[op_interface_impl]
2225impl ToLLVMConstValue for InsertValueOp {
2226 fn convert(
2227 &self,
2228 ctx: &Context,
2229 llvm_ctx: &LLVMContext,
2230 cctx: &mut ConversionContext,
2231 ) -> Result<LLVMValue> {
2232 let op = self.get_operation().deref(ctx);
2233 let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
2234 let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
2235 let indices = self.indices(ctx);
2236 if indices.len() != 1 {
2237 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
2238 }
2239
2240 let insert_op = llvm_build_insert_value(
2242 &cctx.scratch_builder,
2243 base,
2244 value,
2245 indices[0],
2246 &self.get_result(ctx).unique_name(ctx),
2247 );
2248 if !llvm_is_a::constant(insert_op) {
2249 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
2250 }
2251 Ok(insert_op)
2252 }
2253}
2254
2255#[op_interface_impl]
2256impl ToLLVMConstValue for InsertElementOp {
2257 fn convert(
2258 &self,
2259 ctx: &Context,
2260 llvm_ctx: &LLVMContext,
2261 cctx: &mut ConversionContext,
2262 ) -> Result<LLVMValue> {
2263 let op = self.get_operation().deref(ctx);
2264 let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
2265 let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
2266 let index = self.get_operand_index(ctx);
2267 let index = convert_to_llvm_const(ctx, cctx, llvm_ctx, index)?;
2268
2269 let insert_op = llvm_build_insert_element(
2271 &cctx.scratch_builder,
2272 base,
2273 value,
2274 index,
2275 &self.get_result(ctx).unique_name(ctx),
2276 );
2277 if !llvm_is_a::constant(insert_op) {
2278 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
2279 }
2280 Ok(insert_op)
2281 }
2282}
2283
2284#[op_interface_impl]
2285impl ToLLVMConstValue for TruncOp {
2286 fn convert(
2287 &self,
2288 ctx: &Context,
2289 llvm_ctx: &LLVMContext,
2290 cctx: &mut ConversionContext,
2291 ) -> Result<LLVMValue> {
2292 let op = self.get_operation().deref(ctx);
2293 let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
2294 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2295
2296 let trunc_op = llvm_build_trunc(
2298 &cctx.scratch_builder,
2299 arg,
2300 ty,
2301 &self.get_result(ctx).unique_name(ctx),
2302 );
2303 if !llvm_is_a::constant(trunc_op) {
2304 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
2305 }
2306 Ok(trunc_op)
2307 }
2308}
2309
2310#[op_interface_impl]
2311impl ToLLVMConstValue for SubOp {
2312 fn convert(
2313 &self,
2314 ctx: &Context,
2315 llvm_ctx: &LLVMContext,
2316 cctx: &mut ConversionContext,
2317 ) -> Result<LLVMValue> {
2318 let op = self.get_operation().deref(ctx);
2319 let lhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
2320 let rhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
2321
2322 let sub_op = llvm_build_sub(
2324 &cctx.scratch_builder,
2325 lhs,
2326 rhs,
2327 &self.get_result(ctx).unique_name(ctx),
2328 );
2329 if !llvm_is_a::constant(sub_op) {
2330 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
2331 }
2332 Ok(sub_op)
2333 }
2334}
2335
2336#[op_interface_impl]
2337impl ToLLVMConstValue for PtrToIntOp {
2338 fn convert(
2339 &self,
2340 ctx: &Context,
2341 llvm_ctx: &LLVMContext,
2342 cctx: &mut ConversionContext,
2343 ) -> Result<LLVMValue> {
2344 let op = self.get_operation().deref(ctx);
2345 let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
2346 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
2347
2348 let ptoi_op = llvm_build_ptr_to_int(
2350 &cctx.scratch_builder,
2351 arg,
2352 ty,
2353 &self.get_result(ctx).unique_name(ctx),
2354 );
2355 if !llvm_is_a::constant(ptoi_op) {
2356 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
2357 }
2358 Ok(ptoi_op)
2359 }
2360}
2361
2362fn convert_to_llvm_const(
2363 ctx: &Context,
2364 cctx: &mut ConversionContext,
2365 llvm_ctx: &LLVMContext,
2366 value: Value,
2367) -> Result<LLVMValue> {
2368 match value.defining_entity() {
2369 DefiningEntity::Op(op) => {
2370 let op = Operation::get_op_dyn(op, ctx);
2371 if let Some(const_trans) = op_cast::<dyn ToLLVMConstValue>(op.as_ref()) {
2372 const_trans.convert(ctx, llvm_ctx, cctx)
2373 } else {
2374 input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
2375 }
2376 }
2377 DefiningEntity::Block(_) => {
2378 input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
2379 }
2380 }
2381}
2382
2383fn convert_global_initializer(
2384 ctx: &Context,
2385 llvm_ctx: &LLVMContext,
2386 cctx: &mut ConversionContext,
2387 global_op: GlobalOp,
2388) -> Result<Option<LLVMValue>> {
2389 if let Some(_initializer) = global_op.get_initializer_value(ctx) {
2390 todo!()
2391 }
2392
2393 if let Some(init_block) = global_op.get_initializer_block(ctx) {
2394 let ret =
2395 Operation::get_op::<ReturnOp>(init_block.deref(ctx).get_terminator(ctx).unwrap(), ctx);
2396 let ret = ret.ok_or_else(|| {
2397 input_error!(
2398 global_op.loc(ctx),
2399 ToLLVMErr::GlobalOpInitializerRegionBadReturn
2400 )
2401 })?;
2402 let Some(ret_val) = ret.retval(ctx) else {
2403 return input_err!(
2404 global_op.loc(ctx),
2405 ToLLVMErr::GlobalOpInitializerRegionBadReturn
2406 );
2407 };
2408 let initializer_val = convert_to_llvm_const(ctx, cctx, llvm_ctx, ret_val)?;
2409 return Ok(Some(initializer_val));
2410 }
2411
2412 Ok(None)
2413}
2414
2415pub fn convert_module(
2417 ctx: &Context,
2418 llvm_ctx: &LLVMContext,
2419 module: ModuleOp,
2420) -> Result<LLVMModule> {
2421 let mod_name = module.get_symbol_name(ctx);
2422 let llvm_module = LLVMModule::new(&mod_name, llvm_ctx);
2423 let cctx = &mut ConversionContext::new(llvm_ctx, &llvm_module);
2424
2425 let scratch_module = LLVMModule::new("__pliron_scratch_module", llvm_ctx);
2428 let scratch_function = llvm_add_function(
2429 &scratch_module,
2430 "scratch",
2431 llvm_function_type(llvm_void_type_in_context(llvm_ctx), &[], false),
2432 );
2433 let scratch_function_entry =
2434 llvm_append_basic_block_in_context(llvm_ctx, scratch_function, "entry");
2435 llvm_position_builder_at_end(&cctx.scratch_builder, scratch_function_entry);
2436
2437 for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
2439 if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx) {
2440 let func_ty = func_op.get_type(ctx).deref(ctx);
2441 let func_ty_to_llvm = type_cast::<dyn ToLLVMType>(&*func_ty).ok_or_else(|| {
2442 input_error_noloc!(ToLLVMErr::MissingTypeConversion(
2443 func_ty.disp(ctx).to_string()
2444 ))
2445 })?;
2446 let fn_ty_llvm = func_ty_to_llvm.convert(ctx, llvm_ctx, cctx)?;
2447 let name = func_op.get_symbol_name(ctx);
2448 let llvm_name = func_op.llvm_symbol_name(ctx).unwrap_or(name.clone().into());
2449 let func_llvm = llvm_add_function(&llvm_module, &llvm_name, fn_ty_llvm);
2450 cctx.function_map.insert(name, func_llvm);
2451 }
2452 if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
2453 let global_ty = global_op.get_type(ctx);
2454 let global_ty_llvm = convert_type(ctx, llvm_ctx, cctx, global_ty)?;
2455 let global_name = global_op.get_symbol_name(ctx);
2456 let llvm_global_name = global_op
2457 .llvm_symbol_name(ctx)
2458 .unwrap_or(global_name.clone().into());
2459 let global_addr_space = global_op.address_space(ctx);
2460 let global_llvm = llvm_add_global_in_address_space(
2461 &llvm_module,
2462 global_ty_llvm,
2463 &llvm_global_name,
2464 global_addr_space,
2465 );
2466 cctx.globals_map.insert(global_name, global_llvm);
2467 }
2468 }
2469
2470 for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
2471 if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx)
2472 && !func_op.is_declaration(ctx)
2473 {
2474 convert_function(ctx, llvm_ctx, cctx, func_op)?;
2475 }
2476 if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
2477 let global_name = global_op.get_symbol_name(ctx);
2478 let global_llvm = cctx.globals_map[&global_name];
2479 if !global_op.is_declaration(ctx)
2480 && let Some(initializer) =
2481 convert_global_initializer(ctx, llvm_ctx, cctx, global_op)?
2482 {
2483 llvm_set_initializer(global_llvm, initializer);
2484 }
2485 if let Some(linkage) = global_op.get_attr_llvm_global_linkage(ctx) {
2486 let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
2487 llvm_set_linkage(global_llvm, llvm_linkage);
2488 }
2489 if let Some(alignment) = global_op.alignment(ctx) {
2490 llvm_set_alignment(global_llvm, alignment);
2491 }
2492 }
2493 }
2494
2495 for (placeholder, (func_name, tag)) in cctx.pending_block_address_ops.iter() {
2497 let function_llvm = cctx
2498 .function_map
2499 .get(func_name)
2500 .ok_or_else(|| input_error_noloc!(ToLLVMErr::CannotEvaluateToConst))?;
2501 let block_llvm = cctx
2502 .block_tags
2503 .get(&(func_name.clone(), *tag))
2504 .ok_or_else(|| {
2505 input_error_noloc!(ToLLVMErr::MissingBlockTag(func_name.to_string(), *tag))
2506 })?;
2507 let block_addr = llvm_block_address(*function_llvm, *block_llvm);
2508 llvm_replace_all_uses_with(*placeholder, block_addr);
2509 llvm_delete_global(*placeholder);
2510 }
2511
2512 Ok(llvm_module)
2513}