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