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