1use std::collections::hash_map;
4
5use llvm_sys::{LLVMIntPredicate, LLVMLinkage, LLVMRealPredicate};
6use pliron::{
7 attribute::{Attribute, attr_cast},
8 basic_block::BasicBlock,
9 builtin::{
10 attr_interfaces::FloatAttr,
11 attributes::{FPDoubleAttr, FPSingleAttr, IntegerAttr, StringAttr},
12 op_interfaces::{
13 AtMostOneRegionInterface, BranchOpInterface, CallOpCallable, CallOpInterface,
14 OneOpdInterface, OneResultInterface, SingleBlockRegionInterface, SymbolOpInterface,
15 },
16 ops::ModuleOp,
17 type_interfaces::FunctionTypeInterface,
18 types::{FP32Type, FP64Type, IntegerType},
19 },
20 common_traits::Named,
21 context::{Context, Ptr},
22 derive::{attr_interface, attr_interface_impl},
23 graph::traversals::region::topological_order,
24 identifier::Identifier,
25 input_err, input_err_noloc, input_error, input_error_noloc,
26 linked_list::{ContainsLinkedList, LinkedList},
27 location::Located,
28 op::{Op, op_cast},
29 operation::Operation,
30 printable::Printable,
31 result::Result,
32 r#type::{Type, TypeObj, Typed, type_cast},
33 utils::apint::APInt,
34 value::{DefiningEntity, Value},
35};
36
37use pliron::derive::{op_interface, op_interface_impl, type_interface, type_interface_impl};
38use rustc_hash::FxHashMap;
39use thiserror::Error;
40
41use crate::{
42 attributes::{FCmpPredicateAttr, ICmpPredicateAttr, LinkageAttr},
43 llvm_sys::core::{
44 LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue,
45 instruction_iter, llvm_add_case, llvm_add_function, llvm_add_global, llvm_add_incoming,
46 llvm_append_basic_block_in_context, llvm_array_type2, llvm_build_add, llvm_build_and,
47 llvm_build_array_alloca, llvm_build_ashr, llvm_build_bitcast, llvm_build_br,
48 llvm_build_call2, llvm_build_cond_br, llvm_build_extract_element, llvm_build_extract_value,
49 llvm_build_fadd, llvm_build_fcmp, llvm_build_fdiv, llvm_build_fmul, llvm_build_fpext,
50 llvm_build_fptosi, llvm_build_fptoui, llvm_build_fptrunc, llvm_build_freeze,
51 llvm_build_frem, llvm_build_fsub, llvm_build_gep2, llvm_build_icmp,
52 llvm_build_insert_element, llvm_build_insert_value, llvm_build_int_to_ptr,
53 llvm_build_load2, llvm_build_lshr, llvm_build_mul, llvm_build_or, llvm_build_phi,
54 llvm_build_ptr_to_int, llvm_build_ret, llvm_build_ret_void, llvm_build_sdiv,
55 llvm_build_select, llvm_build_sext, llvm_build_shl, llvm_build_shuffle_vector,
56 llvm_build_sitofp, llvm_build_srem, llvm_build_store, llvm_build_sub, llvm_build_switch,
57 llvm_build_trunc, llvm_build_udiv, llvm_build_uitofp, llvm_build_unreachable,
58 llvm_build_urem, llvm_build_va_arg, llvm_build_xor, llvm_build_zext,
59 llvm_can_value_use_fast_math_flags, llvm_clear_insertion_position, llvm_const_int,
60 llvm_const_null, llvm_const_real, llvm_const_vector, llvm_double_type_in_context,
61 llvm_float_type_in_context, llvm_function_type, llvm_get_named_function, llvm_get_param,
62 llvm_get_poison, llvm_get_undef, llvm_int_type_in_context, llvm_is_a,
63 llvm_lookup_intrinsic_id, llvm_pointer_type_in_context, llvm_position_builder_at_end,
64 llvm_scalable_vector_type, llvm_set_alignment, llvm_set_fast_math_flags,
65 llvm_set_initializer, llvm_set_linkage, llvm_set_nneg, llvm_struct_create_named,
66 llvm_struct_set_body, llvm_struct_type_in_context, llvm_vector_type,
67 llvm_void_type_in_context,
68 },
69 op_interfaces::{
70 AlignableOpInterface, FastMathFlags, IsDeclaration, LlvmSymbolName, NNegFlag,
71 PointerTypeResult,
72 },
73 ops::{
74 AShrOp, AddOp, AddressOfOp, AllocaOp, AndOp, BitcastOp, BrOp, CallIntrinsicOp, CallOp,
75 CondBrOp, ConstantOp, ExtractElementOp, ExtractValueOp, FAddOp, FCmpOp, FDivOp, FMulOp,
76 FPExtOp, FPToSIOp, FPToUIOp, FPTruncOp, FRemOp, FSubOp, FreezeOp, FuncOp, GetElementPtrOp,
77 GlobalOp, ICmpOp, InsertElementOp, InsertValueOp, IntToPtrOp, LShrOp, LoadOp, MulOp, OrOp,
78 PoisonOp, PtrToIntOp, ReturnOp, SDivOp, SExtOp, SIToFPOp, SRemOp, SelectOp, ShlOp,
79 ShuffleVectorOp, StoreOp, SubOp, SwitchOp, TruncOp, UDivOp, UIToFPOp, URemOp, UndefOp,
80 UnreachableOp, VAArgOp, XorOp, ZExtOp, ZeroOp,
81 },
82 types::{ArrayType, FuncType, PointerType, StructType, VectorType, VoidType},
83};
84
85pub struct ConversionContext<'a> {
87 cur_llvm_module: &'a LLVMModule,
89 value_map: FxHashMap<Value, LLVMValue>,
91 block_map: FxHashMap<Ptr<BasicBlock>, LLVMBasicBlock>,
93 function_map: FxHashMap<Identifier, LLVMValue>,
95 globals_map: FxHashMap<Identifier, LLVMValue>,
97 structs_map: FxHashMap<Identifier, LLVMType>,
99 type_cache: FxHashMap<Ptr<TypeObj>, LLVMType>,
101 builder: LLVMBuilder,
103 scratch_builder: LLVMBuilder,
105}
106
107impl<'a> ConversionContext<'a> {
108 pub fn new(llvm_ctx: &'a LLVMContext, cur_llvm_module: &'a LLVMModule) -> Self {
109 Self {
110 cur_llvm_module,
111 value_map: FxHashMap::default(),
112 block_map: FxHashMap::default(),
113 function_map: FxHashMap::default(),
114 globals_map: FxHashMap::default(),
115 structs_map: FxHashMap::default(),
116 type_cache: FxHashMap::default(),
117 builder: LLVMBuilder::new(llvm_ctx),
118 scratch_builder: LLVMBuilder::new(llvm_ctx),
119 }
120 }
121
122 pub fn clear_per_function_data(&mut self) {
123 self.value_map.clear();
124 self.block_map.clear();
125 llvm_clear_insertion_position(&self.builder);
126 }
127}
128
129#[derive(Error, Debug)]
130pub enum ToLLVMErr {
131 #[error("Type {0} does not have a conversion to LLVM type implemented")]
132 MissingTypeConversion(String),
133 #[error("Operation {0} does not have a conversion to LLVM instruction implemented")]
134 MissingOpConversion(String),
135 #[error("Definition for value {0} not seen yet")]
136 UndefinedValue(String),
137 #[error("Block definition {0} not seen yet")]
138 UndefinedBlock(String),
139 #[error("Number of block args in the source dialect equal the number of PHIs in target IR")]
140 NumBlockArgsNumPhisMismatch,
141 #[error("ConstantOp must have integer or float value")]
142 ConstOpNotIntOrFloat,
143 #[error(
144 "Insert/Extract value instructions must specify exactly one index, an LLVM-C API limitation"
145 )]
146 InsertExtractValueIndices,
147 #[error("GlobalOp Initializer region does not terminate with a return with value")]
148 GlobalOpInitializerRegionBadReturn,
149 #[error("Cannot evaluate value to a constant")]
150 CannotEvaluateToConst,
151}
152
153pub fn convert_ipredicate(pred: ICmpPredicateAttr) -> LLVMIntPredicate {
154 match pred {
155 ICmpPredicateAttr::EQ => LLVMIntPredicate::LLVMIntEQ,
156 ICmpPredicateAttr::NE => LLVMIntPredicate::LLVMIntNE,
157 ICmpPredicateAttr::UGT => LLVMIntPredicate::LLVMIntUGT,
158 ICmpPredicateAttr::UGE => LLVMIntPredicate::LLVMIntUGE,
159 ICmpPredicateAttr::ULT => LLVMIntPredicate::LLVMIntULT,
160 ICmpPredicateAttr::ULE => LLVMIntPredicate::LLVMIntULE,
161 ICmpPredicateAttr::SGT => LLVMIntPredicate::LLVMIntSGT,
162 ICmpPredicateAttr::SGE => LLVMIntPredicate::LLVMIntSGE,
163 ICmpPredicateAttr::SLT => LLVMIntPredicate::LLVMIntSLT,
164 ICmpPredicateAttr::SLE => LLVMIntPredicate::LLVMIntSLE,
165 }
166}
167
168pub fn convert_fpredicate(pred: FCmpPredicateAttr) -> LLVMRealPredicate {
169 match pred {
170 FCmpPredicateAttr::False => LLVMRealPredicate::LLVMRealPredicateFalse,
171 FCmpPredicateAttr::OEQ => LLVMRealPredicate::LLVMRealOEQ,
172 FCmpPredicateAttr::OGT => LLVMRealPredicate::LLVMRealOGT,
173 FCmpPredicateAttr::OGE => LLVMRealPredicate::LLVMRealOGE,
174 FCmpPredicateAttr::OLT => LLVMRealPredicate::LLVMRealOLT,
175 FCmpPredicateAttr::OLE => LLVMRealPredicate::LLVMRealOLE,
176 FCmpPredicateAttr::ONE => LLVMRealPredicate::LLVMRealONE,
177 FCmpPredicateAttr::ORD => LLVMRealPredicate::LLVMRealORD,
178 FCmpPredicateAttr::UNO => LLVMRealPredicate::LLVMRealUNO,
179 FCmpPredicateAttr::UEQ => LLVMRealPredicate::LLVMRealUEQ,
180 FCmpPredicateAttr::UGT => LLVMRealPredicate::LLVMRealUGT,
181 FCmpPredicateAttr::UGE => LLVMRealPredicate::LLVMRealUGE,
182 FCmpPredicateAttr::ULT => LLVMRealPredicate::LLVMRealULT,
183 FCmpPredicateAttr::ULE => LLVMRealPredicate::LLVMRealULE,
184 FCmpPredicateAttr::UNE => LLVMRealPredicate::LLVMRealUNE,
185 FCmpPredicateAttr::True => LLVMRealPredicate::LLVMRealPredicateTrue,
186 }
187}
188
189pub fn convert_linkage(linkage: LinkageAttr) -> LLVMLinkage {
190 match linkage {
191 LinkageAttr::ExternalLinkage => LLVMLinkage::LLVMExternalLinkage,
192 LinkageAttr::AvailableExternallyLinkage => LLVMLinkage::LLVMAvailableExternallyLinkage,
193 LinkageAttr::LinkOnceAnyLinkage => LLVMLinkage::LLVMLinkOnceAnyLinkage,
194 LinkageAttr::LinkOnceODRLinkage => LLVMLinkage::LLVMLinkOnceODRLinkage,
195 LinkageAttr::WeakAnyLinkage => LLVMLinkage::LLVMWeakAnyLinkage,
196 LinkageAttr::WeakODRLinkage => LLVMLinkage::LLVMWeakODRLinkage,
197 LinkageAttr::AppendingLinkage => LLVMLinkage::LLVMAppendingLinkage,
198 LinkageAttr::InternalLinkage => LLVMLinkage::LLVMInternalLinkage,
199 LinkageAttr::PrivateLinkage => LLVMLinkage::LLVMPrivateLinkage,
200 LinkageAttr::DLLImportLinkage => LLVMLinkage::LLVMDLLImportLinkage,
201 LinkageAttr::DLLExportLinkage => LLVMLinkage::LLVMDLLExportLinkage,
202 LinkageAttr::ExternalWeakLinkage => LLVMLinkage::LLVMExternalWeakLinkage,
203 LinkageAttr::GhostLinkage => LLVMLinkage::LLVMGhostLinkage,
204 LinkageAttr::CommonLinkage => LLVMLinkage::LLVMCommonLinkage,
205 LinkageAttr::LinkOnceODRAutoHideLinkage => LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage,
206 LinkageAttr::LinkerPrivateLinkage => LLVMLinkage::LLVMLinkerPrivateLinkage,
207 LinkageAttr::LinkerPrivateWeakLinkage => LLVMLinkage::LLVMLinkerPrivateWeakLinkage,
208 }
209}
210
211#[::pliron::linkme::distributed_slice]
212#[linkme(crate = pliron::linkme)]
213pub static TEST: [u64];
214
215#[attr_interface]
217trait FloatAttrToFP64: FloatAttr {
218 fn to_fp64(&self) -> f64;
219 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
220 where
221 Self: Sized,
222 {
223 Ok(())
224 }
225}
226
227#[attr_interface_impl]
228impl FloatAttrToFP64 for FPSingleAttr {
229 fn to_fp64(&self) -> f64 {
230 Into::<f32>::into(self.clone()) as f64
231 }
232}
233
234#[attr_interface_impl]
235impl FloatAttrToFP64 for FPDoubleAttr {
236 fn to_fp64(&self) -> f64 {
237 Into::<f64>::into(self.clone())
238 }
239}
240
241#[type_interface]
243trait ToLLVMType {
244 fn convert(
246 &self,
247 ctx: &Context,
248 llvm_ctx: &LLVMContext,
249 cctx: &mut ConversionContext,
250 ) -> Result<LLVMType>;
251
252 fn verify(_type: &dyn Type, _ctx: &Context) -> Result<()>
253 where
254 Self: Sized,
255 {
256 Ok(())
257 }
258}
259
260#[op_interface]
262trait ToLLVMValue {
263 fn convert(
265 &self,
266 ctx: &Context,
267 llvm_ctx: &LLVMContext,
268 cctx: &mut ConversionContext,
269 ) -> Result<LLVMValue>;
270
271 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
272 where
273 Self: Sized,
274 {
275 Ok(())
276 }
277}
278
279#[type_interface_impl]
280impl ToLLVMType for IntegerType {
281 fn convert(
282 &self,
283 _ctx: &Context,
284 llvm_ctx: &LLVMContext,
285 _cctx: &mut ConversionContext,
286 ) -> Result<LLVMType> {
287 Ok(llvm_int_type_in_context(llvm_ctx, self.width()))
288 }
289}
290
291#[type_interface_impl]
292impl ToLLVMType for ArrayType {
293 fn convert(
294 &self,
295 ctx: &Context,
296 llvm_ctx: &LLVMContext,
297 cctx: &mut ConversionContext,
298 ) -> Result<LLVMType> {
299 let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
300 Ok(llvm_array_type2(elem_ty, self.size()))
301 }
302}
303
304#[type_interface_impl]
305impl ToLLVMType for FuncType {
306 fn convert(
307 &self,
308 ctx: &Context,
309 llvm_ctx: &LLVMContext,
310 cctx: &mut ConversionContext,
311 ) -> Result<LLVMType> {
312 let args_tys: Vec<_> = self
313 .arg_types()
314 .iter()
315 .map(|ty| convert_type(ctx, llvm_ctx, cctx, *ty))
316 .collect::<Result<_>>()?;
317 let ret_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type())?;
318 Ok(llvm_function_type(ret_ty, &args_tys, self.is_var_arg()))
319 }
320}
321
322#[type_interface_impl]
323impl ToLLVMType for VoidType {
324 fn convert(
325 &self,
326 _ctx: &Context,
327 llvm_ctx: &LLVMContext,
328 _cctx: &mut ConversionContext,
329 ) -> Result<LLVMType> {
330 Ok(llvm_void_type_in_context(llvm_ctx))
331 }
332}
333
334#[type_interface_impl]
335impl ToLLVMType for PointerType {
336 fn convert(
337 &self,
338 _ctx: &Context,
339 llvm_ctx: &LLVMContext,
340 _cctx: &mut ConversionContext,
341 ) -> Result<LLVMType> {
342 Ok(llvm_pointer_type_in_context(llvm_ctx, 0))
343 }
344}
345
346#[type_interface_impl]
347impl ToLLVMType for StructType {
348 fn convert(
349 &self,
350 ctx: &Context,
351 llvm_ctx: &LLVMContext,
352 cctx: &mut ConversionContext,
353 ) -> Result<LLVMType> {
354 if self.is_opaque() {
355 let name = self.name().expect("Opaqaue struct must have a name");
356 Ok(llvm_struct_create_named(llvm_ctx, name.as_str()))
357 } else {
358 let field_types = self
359 .fields()
360 .map(|fty| convert_type(ctx, llvm_ctx, cctx, fty))
361 .collect::<Result<Vec<_>>>()?;
362 if let Some(name) = self.name() {
363 match cctx.structs_map.entry(name) {
364 hash_map::Entry::Occupied(entry) => Ok(*entry.get()),
365 hash_map::Entry::Vacant(entry) => {
366 let str_ty = llvm_struct_create_named(llvm_ctx, entry.key());
367 llvm_struct_set_body(str_ty, &field_types, false);
368 entry.insert(str_ty);
369 Ok(str_ty)
370 }
371 }
372 } else {
373 Ok(llvm_struct_type_in_context(llvm_ctx, &field_types, false))
374 }
375 }
376 }
377}
378
379#[type_interface_impl]
380impl ToLLVMType for VectorType {
381 fn convert(
382 &self,
383 ctx: &Context,
384 llvm_ctx: &LLVMContext,
385 cctx: &mut ConversionContext,
386 ) -> Result<LLVMType> {
387 let elem_ty = convert_type(ctx, llvm_ctx, cctx, self.elem_type())?;
388 let num_elems = self.num_elements();
389 if self.is_scalable() {
390 Ok(llvm_scalable_vector_type(elem_ty, num_elems))
391 } else {
392 Ok(llvm_vector_type(elem_ty, num_elems))
393 }
394 }
395}
396
397#[type_interface_impl]
398impl ToLLVMType for FP32Type {
399 fn convert(
400 &self,
401 _ctx: &Context,
402 llvm_ctx: &LLVMContext,
403 _cctx: &mut ConversionContext,
404 ) -> Result<LLVMType> {
405 Ok(llvm_float_type_in_context(llvm_ctx))
406 }
407}
408
409#[type_interface_impl]
410impl ToLLVMType for FP64Type {
411 fn convert(
412 &self,
413 _ctx: &Context,
414 llvm_ctx: &LLVMContext,
415 _cctx: &mut ConversionContext,
416 ) -> Result<LLVMType> {
417 Ok(llvm_double_type_in_context(llvm_ctx))
418 }
419}
420
421pub fn convert_type(
423 ctx: &Context,
424 llvm_ctx: &LLVMContext,
425 cctx: &mut ConversionContext,
426 ty: Ptr<TypeObj>,
427) -> Result<LLVMType> {
428 if let Some(cached) = cctx.type_cache.get(&ty) {
429 return Ok(*cached);
430 }
431 if let Some(converter) = type_cast::<dyn ToLLVMType>(&**ty.deref(ctx)) {
432 let llvm_ty = converter.convert(ctx, llvm_ctx, cctx)?;
433 cctx.type_cache.insert(ty, llvm_ty);
434 return Ok(llvm_ty);
435 }
436
437 input_err_noloc!(ToLLVMErr::MissingTypeConversion(
438 ty.deref(ctx).get_type_id().to_string()
439 ))
440}
441
442fn convert_value_operand(
443 cctx: &mut ConversionContext,
444 ctx: &Context,
445 value: &Value,
446) -> Result<LLVMValue> {
447 match cctx.value_map.get(value) {
448 Some(v) => Ok(*v),
449 None => {
450 input_err_noloc!(ToLLVMErr::UndefinedValue(value.unique_name(ctx).into()))
451 }
452 }
453}
454
455fn convert_block_operand(
456 cctx: &mut ConversionContext,
457 ctx: &Context,
458 block: Ptr<BasicBlock>,
459) -> Result<LLVMBasicBlock> {
460 match cctx.block_map.get(&block) {
461 Some(v) => Ok(*v),
462 None => {
463 input_err_noloc!(ToLLVMErr::UndefinedBlock(block.unique_name(ctx).into()))
464 }
465 }
466}
467
468macro_rules! to_llvm_value_int_bin_op {
469 (
470 $op_name:ident, $builder_function:ident
471 ) => {
472 #[pliron::derive::op_interface_impl]
473 impl ToLLVMValue for $op_name {
474 fn convert(
475 &self,
476 ctx: &Context,
477 _llvm_ctx: &LLVMContext,
478 cctx: &mut ConversionContext,
479 ) -> Result<LLVMValue> {
480 let op = self.get_operation().deref(ctx);
481 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
482 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
483 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
484 Ok($builder_function(
485 &cctx.builder,
486 lhs,
487 rhs,
488 &self.get_result(ctx).unique_name(ctx),
489 ))
490 }
491 }
492 };
493}
494
495to_llvm_value_int_bin_op!(AddOp, llvm_build_add);
496to_llvm_value_int_bin_op!(SubOp, llvm_build_sub);
497to_llvm_value_int_bin_op!(MulOp, llvm_build_mul);
498to_llvm_value_int_bin_op!(SDivOp, llvm_build_sdiv);
499to_llvm_value_int_bin_op!(UDivOp, llvm_build_udiv);
500to_llvm_value_int_bin_op!(URemOp, llvm_build_urem);
501to_llvm_value_int_bin_op!(SRemOp, llvm_build_srem);
502to_llvm_value_int_bin_op!(AndOp, llvm_build_and);
503to_llvm_value_int_bin_op!(OrOp, llvm_build_or);
504to_llvm_value_int_bin_op!(XorOp, llvm_build_xor);
505to_llvm_value_int_bin_op!(ShlOp, llvm_build_shl);
506to_llvm_value_int_bin_op!(LShrOp, llvm_build_lshr);
507to_llvm_value_int_bin_op!(AShrOp, llvm_build_ashr);
508
509#[op_interface_impl]
510impl ToLLVMValue for AllocaOp {
511 fn convert(
512 &self,
513 ctx: &Context,
514 llvm_ctx: &LLVMContext,
515 cctx: &mut ConversionContext,
516 ) -> Result<LLVMValue> {
517 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_pointee_type(ctx))?;
518 let size = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
519 let alloca_op = llvm_build_array_alloca(
520 &cctx.builder,
521 ty,
522 size,
523 &self.get_result(ctx).unique_name(ctx),
524 );
525 if let Some(alignment) = self.alignment(ctx) {
526 llvm_set_alignment(alloca_op, alignment);
527 }
528 Ok(alloca_op)
529 }
530}
531
532#[op_interface_impl]
533impl ToLLVMValue for BitcastOp {
534 fn convert(
535 &self,
536 ctx: &Context,
537 llvm_ctx: &LLVMContext,
538 cctx: &mut ConversionContext,
539 ) -> Result<LLVMValue> {
540 let arg = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
541 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
542 let bitcast_op = llvm_build_bitcast(
543 &cctx.builder,
544 arg,
545 ty,
546 &self.get_result(ctx).unique_name(ctx),
547 );
548 Ok(bitcast_op)
549 }
550}
551
552fn link_succ_operands_with_phis(
553 ctx: &Context,
554 cctx: &mut ConversionContext,
555 source_block: Ptr<BasicBlock>,
556 target_block: LLVMBasicBlock,
557 opds: Vec<Value>,
558) -> Result<()> {
559 let mut phis = vec![];
560 for inst in instruction_iter(target_block) {
561 if !llvm_is_a::phi_node(inst) {
562 break;
563 };
564 phis.push(inst);
565 }
566
567 if phis.len() != opds.len() {
568 return input_err!(
569 source_block.deref(ctx).loc(),
570 ToLLVMErr::NumBlockArgsNumPhisMismatch
571 );
572 }
573
574 let source_block = convert_block_operand(cctx, ctx, source_block)?;
575
576 for (idx, arg) in opds.iter().enumerate() {
577 let arg = convert_value_operand(cctx, ctx, arg)?;
578 llvm_add_incoming(phis[idx], &[arg], &[source_block]);
579 }
580 Ok(())
581}
582
583#[op_interface_impl]
584impl ToLLVMValue for BrOp {
585 fn convert(
586 &self,
587 ctx: &Context,
588 _llvm_ctx: &LLVMContext,
589 cctx: &mut ConversionContext,
590 ) -> Result<LLVMValue> {
591 let op = self.get_operation().deref(ctx);
592 let succ = op.get_successor(0);
593 let succ_llvm = convert_block_operand(cctx, ctx, succ)?;
594 let branch_op = llvm_build_br(&cctx.builder, succ_llvm);
595
596 link_succ_operands_with_phis(
598 ctx,
599 cctx,
600 op.get_container().expect("Unlinked operation"),
601 succ_llvm,
602 self.successor_operands(ctx, 0),
603 )?;
604
605 Ok(branch_op)
606 }
607}
608
609#[op_interface_impl]
610impl ToLLVMValue for CondBrOp {
611 fn convert(
612 &self,
613 ctx: &Context,
614 _llvm_ctx: &LLVMContext,
615 cctx: &mut ConversionContext,
616 ) -> Result<LLVMValue> {
617 let op = self.get_operation().deref(ctx);
618 let (true_succ, false_succ) = (op.get_successor(0), op.get_successor(1));
619 let true_succ_llvm = convert_block_operand(cctx, ctx, true_succ)?;
620 let false_succ_llvm = convert_block_operand(cctx, ctx, false_succ)?;
621 let cond = convert_value_operand(cctx, ctx, &self.condition(ctx))?;
622
623 let branch_op = llvm_build_cond_br(&cctx.builder, cond, true_succ_llvm, false_succ_llvm);
624
625 link_succ_operands_with_phis(
627 ctx,
628 cctx,
629 op.get_container().expect("Unlinked operation"),
630 true_succ_llvm,
631 self.successor_operands(ctx, 0),
632 )?;
633 link_succ_operands_with_phis(
634 ctx,
635 cctx,
636 op.get_container().expect("Unlinked operation"),
637 false_succ_llvm,
638 self.successor_operands(ctx, 1),
639 )?;
640
641 Ok(branch_op)
642 }
643}
644
645#[op_interface_impl]
646impl ToLLVMValue for SwitchOp {
647 fn convert(
648 &self,
649 ctx: &Context,
650 llvm_ctx: &LLVMContext,
651 cctx: &mut ConversionContext,
652 ) -> Result<LLVMValue> {
653 let op = self.get_operation().deref(ctx);
654 let cond = convert_value_operand(cctx, ctx, &self.condition(ctx))?;
655 let default_succ = convert_block_operand(cctx, ctx, self.default_dest(ctx))?;
656 let switch_op = llvm_build_switch(
657 &cctx.builder,
658 cond,
659 default_succ,
660 self.cases(ctx).len() as u32,
661 );
662
663 link_succ_operands_with_phis(
665 ctx,
666 cctx,
667 op.get_container().expect("Unlinked operation"),
668 default_succ,
669 self.default_dest_operands(ctx),
670 )?;
671 for case in self.cases(ctx) {
672 let succ_llvm = convert_block_operand(cctx, ctx, case.dest)?;
673 link_succ_operands_with_phis(
674 ctx,
675 cctx,
676 op.get_container().expect("Unlinked operation"),
677 succ_llvm,
678 case.dest_opds,
679 )?;
680
681 let int_ty = case.value.get_type();
682 let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
683 let ap_int_val: APInt = case.value.clone().into();
684 let case_const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
685
686 llvm_add_case(switch_op, case_const_val, succ_llvm);
687 }
688
689 Ok(switch_op)
690 }
691}
692
693#[op_interface_impl]
694impl ToLLVMValue for LoadOp {
695 fn convert(
696 &self,
697 ctx: &Context,
698 llvm_ctx: &LLVMContext,
699 cctx: &mut ConversionContext,
700 ) -> Result<LLVMValue> {
701 let pointee_ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
702 let ptr = convert_value_operand(cctx, ctx, &self.get_operand(ctx))?;
703 let load_op = llvm_build_load2(
704 &cctx.builder,
705 pointee_ty,
706 ptr,
707 &self.get_result(ctx).unique_name(ctx),
708 );
709 if let Some(alignment) = self.alignment(ctx) {
710 llvm_set_alignment(load_op, alignment);
711 }
712 Ok(load_op)
713 }
714}
715
716#[op_interface_impl]
717impl ToLLVMValue for StoreOp {
718 fn convert(
719 &self,
720 ctx: &Context,
721 _llvm_ctx: &LLVMContext,
722 cctx: &mut ConversionContext,
723 ) -> Result<LLVMValue> {
724 let value = convert_value_operand(cctx, ctx, &self.value_opd(ctx))?;
725 let ptr = convert_value_operand(cctx, ctx, &self.address_opd(ctx))?;
726 let store_op = llvm_build_store(&cctx.builder, value, ptr);
727 if let Some(alignment) = self.alignment(ctx) {
728 llvm_set_alignment(store_op, alignment);
729 }
730 Ok(store_op)
731 }
732}
733
734#[op_interface_impl]
735impl ToLLVMValue for ICmpOp {
736 fn convert(
737 &self,
738 ctx: &Context,
739 _llvm_ctx: &LLVMContext,
740 cctx: &mut ConversionContext,
741 ) -> Result<LLVMValue> {
742 let op = self.get_operation().deref(ctx);
743 let predicate = convert_ipredicate(self.predicate(ctx));
744 let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
745 let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
746 let icmp_op = llvm_build_icmp(
747 &cctx.builder,
748 predicate,
749 lhs,
750 rhs,
751 &self.get_result(ctx).unique_name(ctx),
752 );
753 Ok(icmp_op)
754 }
755}
756
757#[op_interface_impl]
758impl ToLLVMValue for ReturnOp {
759 fn convert(
760 &self,
761 ctx: &Context,
762 _llvm_ctx: &LLVMContext,
763 cctx: &mut ConversionContext,
764 ) -> Result<LLVMValue> {
765 let ret_op = if let Some(retval) = self.retval(ctx) {
766 let retval = convert_value_operand(cctx, ctx, &retval)?;
767 llvm_build_ret(&cctx.builder, retval)
768 } else {
769 llvm_build_ret_void(&cctx.builder)
770 };
771 Ok(ret_op)
772 }
773}
774
775#[op_interface_impl]
776impl ToLLVMValue for UnreachableOp {
777 fn convert(
778 &self,
779 _ctx: &Context,
780 _llvm_ctx: &LLVMContext,
781 cctx: &mut ConversionContext,
782 ) -> Result<LLVMValue> {
783 Ok(llvm_build_unreachable(&cctx.builder))
784 }
785}
786
787#[op_interface_impl]
788impl ToLLVMValue for ConstantOp {
789 fn convert(
790 &self,
791 ctx: &Context,
792 llvm_ctx: &LLVMContext,
793 cctx: &mut ConversionContext,
794 ) -> Result<LLVMValue> {
795 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
796 }
797}
798
799#[op_interface_impl]
800impl ToLLVMValue for ZeroOp {
801 fn convert(
802 &self,
803 ctx: &Context,
804 llvm_ctx: &LLVMContext,
805 cctx: &mut ConversionContext,
806 ) -> Result<LLVMValue> {
807 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
808 }
809}
810
811#[op_interface_impl]
812impl ToLLVMValue for IntToPtrOp {
813 fn convert(
814 &self,
815 ctx: &Context,
816 llvm_ctx: &LLVMContext,
817 cctx: &mut ConversionContext,
818 ) -> Result<LLVMValue> {
819 let op = self.get_operation().deref(ctx);
820 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
821 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
822 let inttoptr_op = llvm_build_int_to_ptr(
823 &cctx.builder,
824 arg,
825 ty,
826 &self.get_result(ctx).unique_name(ctx),
827 );
828 Ok(inttoptr_op)
829 }
830}
831
832#[op_interface_impl]
833impl ToLLVMValue for PtrToIntOp {
834 fn convert(
835 &self,
836 ctx: &Context,
837 llvm_ctx: &LLVMContext,
838 cctx: &mut ConversionContext,
839 ) -> Result<LLVMValue> {
840 let op = self.get_operation().deref(ctx);
841 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
842 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
843 let ptrtoint_op = llvm_build_ptr_to_int(
844 &cctx.builder,
845 arg,
846 ty,
847 &self.get_result(ctx).unique_name(ctx),
848 );
849 Ok(ptrtoint_op)
850 }
851}
852
853#[op_interface_impl]
854impl ToLLVMValue for UndefOp {
855 fn convert(
856 &self,
857 ctx: &Context,
858 llvm_ctx: &LLVMContext,
859 cctx: &mut ConversionContext,
860 ) -> Result<LLVMValue> {
861 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
862 }
863}
864
865#[op_interface_impl]
866impl ToLLVMValue for PoisonOp {
867 fn convert(
868 &self,
869 ctx: &Context,
870 llvm_ctx: &LLVMContext,
871 cctx: &mut ConversionContext,
872 ) -> Result<LLVMValue> {
873 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
874 }
875}
876
877#[op_interface_impl]
878impl ToLLVMValue for AddressOfOp {
879 fn convert(
880 &self,
881 ctx: &Context,
882 llvm_ctx: &LLVMContext,
883 cctx: &mut ConversionContext,
884 ) -> Result<LLVMValue> {
885 <Self as ToLLVMConstValue>::convert(self, ctx, llvm_ctx, cctx)
886 }
887}
888
889#[op_interface_impl]
890impl ToLLVMValue for FreezeOp {
891 fn convert(
892 &self,
893 ctx: &Context,
894 _llvm_ctx: &LLVMContext,
895 cctx: &mut ConversionContext,
896 ) -> Result<LLVMValue> {
897 let op = self.get_operation().deref(ctx);
898 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
899 let freeze_op =
900 llvm_build_freeze(&cctx.builder, arg, &self.get_result(ctx).unique_name(ctx));
901 Ok(freeze_op)
902 }
903}
904
905#[op_interface_impl]
906impl ToLLVMValue for CallOp {
907 fn convert(
908 &self,
909 ctx: &Context,
910 llvm_ctx: &LLVMContext,
911 cctx: &mut ConversionContext,
912 ) -> Result<LLVMValue> {
913 let args: Vec<_> = self
914 .args(ctx)
915 .into_iter()
916 .map(|v| convert_value_operand(cctx, ctx, &v))
917 .collect::<Result<_>>()?;
918 let ty = convert_type(ctx, llvm_ctx, cctx, self.callee_type(ctx))?;
919 let res = self.get_result(ctx);
920 let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
921 ""
922 } else {
923 &res.unique_name(ctx)
924 };
925 let callee = match self.callee(ctx) {
926 CallOpCallable::Direct(callee_sym) => {
927 *cctx.function_map.get(&callee_sym).ok_or_else(|| {
928 input_error_noloc!(ToLLVMErr::UndefinedValue(callee_sym.to_string()))
929 })?
930 }
931 CallOpCallable::Indirect(callee) => convert_value_operand(cctx, ctx, &callee)?,
932 };
933 let call_val = llvm_build_call2(&cctx.builder, ty, callee, &args, name);
934 if let Some(fmf) = self.get_attr_llvm_call_fastmath_flags(ctx)
935 && llvm_can_value_use_fast_math_flags(call_val)
936 {
937 llvm_set_fast_math_flags(call_val, (*fmf).into());
938 }
939 Ok(call_val)
940 }
941}
942
943#[op_interface_impl]
944impl ToLLVMValue for CallIntrinsicOp {
945 fn convert(
946 &self,
947 ctx: &Context,
948 llvm_ctx: &LLVMContext,
949 cctx: &mut ConversionContext,
950 ) -> Result<LLVMValue> {
951 let op = self.get_operation().deref(ctx);
952 let args: Vec<_> = (0..op.get_num_operands())
953 .map(|i| convert_value_operand(cctx, ctx, &op.get_operand(i)))
954 .collect::<Result<_>>()?;
955 let fn_ty = convert_type(
956 ctx,
957 llvm_ctx,
958 cctx,
959 self.get_attr_llvm_intrinsic_type(ctx)
960 .unwrap()
961 .get_type(ctx),
962 )?;
963
964 let intrinsic_name = <StringAttr as Into<String>>::into(
965 self.get_attr_llvm_intrinsic_name(ctx)
966 .expect("Intrinsic call does not name the intrinsic to be called")
967 .clone(),
968 );
969
970 let _intrinsic_id = llvm_lookup_intrinsic_id(&intrinsic_name).ok_or_else(|| {
971 input_error_noloc!(ToLLVMErr::UndefinedValue(intrinsic_name.to_string()))
972 })?;
973
974 let intrinsic_fn = llvm_get_named_function(cctx.cur_llvm_module, &intrinsic_name)
980 .unwrap_or_else(|| llvm_add_function(cctx.cur_llvm_module, &intrinsic_name, fn_ty));
981
982 let res = self.get_result(ctx);
983 let name = if res.get_type(ctx).deref(ctx).is::<VoidType>() {
984 ""
985 } else {
986 &res.unique_name(ctx)
987 };
988
989 let intrinsic_op = llvm_build_call2(&cctx.builder, fn_ty, intrinsic_fn, &args, name);
990
991 if let Some(fmf) = self.get_attr_llvm_intrinsic_fastmath_flags(ctx)
992 && llvm_can_value_use_fast_math_flags(intrinsic_op)
993 {
994 llvm_set_fast_math_flags(intrinsic_op, (*fmf).into());
995 }
996
997 Ok(intrinsic_op)
998 }
999}
1000
1001#[op_interface_impl]
1002impl ToLLVMValue for SExtOp {
1003 fn convert(
1004 &self,
1005 ctx: &Context,
1006 llvm_ctx: &LLVMContext,
1007 cctx: &mut ConversionContext,
1008 ) -> Result<LLVMValue> {
1009 let op = self.get_operation().deref(ctx);
1010 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1011 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1012 let sext_op = llvm_build_sext(
1013 &cctx.builder,
1014 arg,
1015 ty,
1016 &self.get_result(ctx).unique_name(ctx),
1017 );
1018 Ok(sext_op)
1019 }
1020}
1021
1022#[op_interface_impl]
1023impl ToLLVMValue for ZExtOp {
1024 fn convert(
1025 &self,
1026 ctx: &Context,
1027 llvm_ctx: &LLVMContext,
1028 cctx: &mut ConversionContext,
1029 ) -> Result<LLVMValue> {
1030 let op = self.get_operation().deref(ctx);
1031 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1032 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1033 let zext_op = llvm_build_zext(
1034 &cctx.builder,
1035 arg,
1036 ty,
1037 &self.get_result(ctx).unique_name(ctx),
1038 );
1039 if llvm_is_a::instruction(zext_op) {
1041 let nneg = self.nneg(ctx);
1042 llvm_set_nneg(zext_op, nneg);
1043 }
1044 Ok(zext_op)
1045 }
1046}
1047
1048#[op_interface_impl]
1049impl ToLLVMValue for TruncOp {
1050 fn convert(
1051 &self,
1052 ctx: &Context,
1053 llvm_ctx: &LLVMContext,
1054 cctx: &mut ConversionContext,
1055 ) -> Result<LLVMValue> {
1056 let op = self.get_operation().deref(ctx);
1057 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1058 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1059 let trunc_op = llvm_build_trunc(
1060 &cctx.builder,
1061 arg,
1062 ty,
1063 &self.get_result(ctx).unique_name(ctx),
1064 );
1065 Ok(trunc_op)
1066 }
1067}
1068
1069#[op_interface_impl]
1070impl ToLLVMValue for GetElementPtrOp {
1071 fn convert(
1072 &self,
1073 ctx: &Context,
1074 llvm_ctx: &LLVMContext,
1075 cctx: &mut ConversionContext,
1076 ) -> Result<LLVMValue> {
1077 let indices = self
1078 .indices(ctx)
1079 .iter()
1080 .map(|v| match v {
1081 crate::ops::GepIndex::Constant(c) => Ok(llvm_const_int(
1082 llvm_int_type_in_context(llvm_ctx, 32),
1083 Into::<u64>::into(*c),
1084 false,
1085 )),
1086 crate::ops::GepIndex::Value(value) => convert_value_operand(cctx, ctx, value),
1087 })
1088 .collect::<Result<Vec<_>>>()?;
1089
1090 let base = convert_value_operand(cctx, ctx, &self.src_ptr(ctx))?;
1091
1092 let src_elem_type = convert_type(ctx, llvm_ctx, cctx, self.src_elem_type(ctx))?;
1093 let gep_op = llvm_build_gep2(
1094 &cctx.builder,
1095 src_elem_type,
1096 base,
1097 &indices,
1098 &self.get_result(ctx).unique_name(ctx),
1099 );
1100 Ok(gep_op)
1101 }
1102}
1103
1104#[op_interface_impl]
1105impl ToLLVMValue for InsertValueOp {
1106 fn convert(
1107 &self,
1108 ctx: &Context,
1109 _llvm_ctx: &LLVMContext,
1110 cctx: &mut ConversionContext,
1111 ) -> Result<LLVMValue> {
1112 let op = self.get_operation().deref(ctx);
1113 let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1114 let value = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1115 let indices = self.indices(ctx);
1116 if indices.len() != 1 {
1117 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1118 }
1119 let insert_op = llvm_build_insert_value(
1120 &cctx.builder,
1121 base,
1122 value,
1123 indices[0],
1124 &self.get_result(ctx).unique_name(ctx),
1125 );
1126 Ok(insert_op)
1127 }
1128}
1129
1130#[op_interface_impl]
1131impl ToLLVMValue for ExtractValueOp {
1132 fn convert(
1133 &self,
1134 ctx: &Context,
1135 _llvm_ctx: &LLVMContext,
1136 cctx: &mut ConversionContext,
1137 ) -> Result<LLVMValue> {
1138 let op = self.get_operation().deref(ctx);
1139 let base = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1140 let indices = self.indices(ctx);
1141 if indices.len() != 1 {
1142 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1143 }
1144 let extract_op = llvm_build_extract_value(
1145 &cctx.builder,
1146 base,
1147 indices[0],
1148 &self.get_result(ctx).unique_name(ctx),
1149 );
1150 Ok(extract_op)
1151 }
1152}
1153
1154#[op_interface_impl]
1155impl ToLLVMValue for InsertElementOp {
1156 fn convert(
1157 &self,
1158 ctx: &Context,
1159 _llvm_ctx: &LLVMContext,
1160 cctx: &mut ConversionContext,
1161 ) -> Result<LLVMValue> {
1162 let base = convert_value_operand(cctx, ctx, &self.vector_operand(ctx))?;
1163 let value = convert_value_operand(cctx, ctx, &self.element_operand(ctx))?;
1164 let index = convert_value_operand(cctx, ctx, &self.index_operand(ctx))?;
1165 let insert_op = llvm_build_insert_element(
1166 &cctx.builder,
1167 base,
1168 value,
1169 index,
1170 &self.get_result(ctx).unique_name(ctx),
1171 );
1172 Ok(insert_op)
1173 }
1174}
1175
1176#[op_interface_impl]
1177impl ToLLVMValue for ExtractElementOp {
1178 fn convert(
1179 &self,
1180 ctx: &Context,
1181 _llvm_ctx: &LLVMContext,
1182 cctx: &mut ConversionContext,
1183 ) -> Result<LLVMValue> {
1184 let base = convert_value_operand(cctx, ctx, &self.vector_operand(ctx))?;
1185 let index = convert_value_operand(cctx, ctx, &self.index_operand(ctx))?;
1186 let extract_op = llvm_build_extract_element(
1187 &cctx.builder,
1188 base,
1189 index,
1190 &self.get_result(ctx).unique_name(ctx),
1191 );
1192 Ok(extract_op)
1193 }
1194}
1195
1196#[op_interface_impl]
1197impl ToLLVMValue for ShuffleVectorOp {
1198 fn convert(
1199 &self,
1200 ctx: &Context,
1201 llvm_ctx: &LLVMContext,
1202 cctx: &mut ConversionContext,
1203 ) -> Result<LLVMValue> {
1204 let mask = &self
1205 .get_attr_llvm_shuffle_vector_mask(ctx)
1206 .expect("ShuffleVectorOp missing mask attribute")
1207 .0;
1208 let op = self.get_operation().deref(ctx);
1209 let vec1 = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1210 let vec2 = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1211 let int_ty = llvm_int_type_in_context(llvm_ctx, 32);
1212
1213 let mask = mask
1214 .iter()
1215 .map(|&i| llvm_const_int(int_ty, i as u64, true))
1216 .collect::<Vec<LLVMValue>>();
1217 let mask = llvm_const_vector(&mask);
1218
1219 let shuffle_op = llvm_build_shuffle_vector(
1220 &cctx.builder,
1221 vec1,
1222 vec2,
1223 mask,
1224 &self.get_result(ctx).unique_name(ctx),
1225 );
1226 Ok(shuffle_op)
1227 }
1228}
1229
1230#[op_interface_impl]
1231impl ToLLVMValue for SelectOp {
1232 fn convert(
1233 &self,
1234 ctx: &Context,
1235 _llvm_ctx: &LLVMContext,
1236 cctx: &mut ConversionContext,
1237 ) -> Result<LLVMValue> {
1238 let op = self.get_operation().deref(ctx);
1239 let cond = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1240 let true_val = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1241 let false_val = convert_value_operand(cctx, ctx, &op.get_operand(2))?;
1242 let select_op = llvm_build_select(
1243 &cctx.builder,
1244 cond,
1245 true_val,
1246 false_val,
1247 &self.get_result(ctx).unique_name(ctx),
1248 );
1249 Ok(select_op)
1250 }
1251}
1252
1253#[op_interface_impl]
1254impl ToLLVMValue for FAddOp {
1255 fn convert(
1256 &self,
1257 ctx: &Context,
1258 _llvm_ctx: &LLVMContext,
1259 cctx: &mut ConversionContext,
1260 ) -> Result<LLVMValue> {
1261 let op = self.get_operation().deref(ctx);
1262 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1263 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1264 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1265 let inst = llvm_build_fadd(
1266 &cctx.builder,
1267 lhs,
1268 rhs,
1269 &self.get_result(ctx).unique_name(ctx),
1270 );
1271 if llvm_can_value_use_fast_math_flags(inst) {
1273 let fastmath = self.fast_math_flags(ctx);
1274 llvm_set_fast_math_flags(inst, fastmath.into());
1275 }
1276 Ok(inst)
1277 }
1278}
1279
1280#[op_interface_impl]
1281impl ToLLVMValue for FSubOp {
1282 fn convert(
1283 &self,
1284 ctx: &Context,
1285 _llvm_ctx: &LLVMContext,
1286 cctx: &mut ConversionContext,
1287 ) -> Result<LLVMValue> {
1288 let op = self.get_operation().deref(ctx);
1289 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1290 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1291 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1292 let inst = llvm_build_fsub(
1293 &cctx.builder,
1294 lhs,
1295 rhs,
1296 &self.get_result(ctx).unique_name(ctx),
1297 );
1298 if llvm_can_value_use_fast_math_flags(inst) {
1300 let fastmath = self.fast_math_flags(ctx);
1301 llvm_set_fast_math_flags(inst, fastmath.into());
1302 }
1303 Ok(inst)
1304 }
1305}
1306
1307#[op_interface_impl]
1308impl ToLLVMValue for FMulOp {
1309 fn convert(
1310 &self,
1311 ctx: &Context,
1312 _llvm_ctx: &LLVMContext,
1313 cctx: &mut ConversionContext,
1314 ) -> Result<LLVMValue> {
1315 let op = self.get_operation().deref(ctx);
1316 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1317 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1318 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1319 let inst = llvm_build_fmul(
1320 &cctx.builder,
1321 lhs,
1322 rhs,
1323 &self.get_result(ctx).unique_name(ctx),
1324 );
1325 if llvm_can_value_use_fast_math_flags(inst) {
1327 let fastmath = self.fast_math_flags(ctx);
1328 llvm_set_fast_math_flags(inst, fastmath.into());
1329 }
1330 Ok(inst)
1331 }
1332}
1333
1334#[op_interface_impl]
1335impl ToLLVMValue for FDivOp {
1336 fn convert(
1337 &self,
1338 ctx: &Context,
1339 _llvm_ctx: &LLVMContext,
1340 cctx: &mut ConversionContext,
1341 ) -> Result<LLVMValue> {
1342 let op = self.get_operation().deref(ctx);
1343 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1344 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1345 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1346 let inst = llvm_build_fdiv(
1347 &cctx.builder,
1348 lhs,
1349 rhs,
1350 &self.get_result(ctx).unique_name(ctx),
1351 );
1352 if llvm_can_value_use_fast_math_flags(inst) {
1354 let fastmath = self.fast_math_flags(ctx);
1355 llvm_set_fast_math_flags(inst, fastmath.into());
1356 }
1357 Ok(inst)
1358 }
1359}
1360
1361#[op_interface_impl]
1362impl ToLLVMValue for FRemOp {
1363 fn convert(
1364 &self,
1365 ctx: &Context,
1366 _llvm_ctx: &LLVMContext,
1367 cctx: &mut ConversionContext,
1368 ) -> Result<LLVMValue> {
1369 let op = self.get_operation().deref(ctx);
1370 let (lhs, rhs) = (op.get_operand(0), op.get_operand(1));
1371 let lhs = convert_value_operand(cctx, ctx, &lhs)?;
1372 let rhs = convert_value_operand(cctx, ctx, &rhs)?;
1373 let inst = llvm_build_frem(
1374 &cctx.builder,
1375 lhs,
1376 rhs,
1377 &self.get_result(ctx).unique_name(ctx),
1378 );
1379 if llvm_can_value_use_fast_math_flags(inst) {
1381 let fastmath = self.fast_math_flags(ctx);
1382 llvm_set_fast_math_flags(inst, fastmath.into());
1383 }
1384 Ok(inst)
1385 }
1386}
1387
1388#[op_interface_impl]
1389impl ToLLVMValue for FCmpOp {
1390 fn convert(
1391 &self,
1392 ctx: &Context,
1393 _llvm_ctx: &LLVMContext,
1394 cctx: &mut ConversionContext,
1395 ) -> Result<LLVMValue> {
1396 let op = self.get_operation().deref(ctx);
1397 let predicate = convert_fpredicate(self.predicate(ctx));
1398 let lhs = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1399 let rhs = convert_value_operand(cctx, ctx, &op.get_operand(1))?;
1400 let fcmp_op = llvm_build_fcmp(
1401 &cctx.builder,
1402 predicate,
1403 lhs,
1404 rhs,
1405 &self.get_result(ctx).unique_name(ctx),
1406 );
1407 if llvm_can_value_use_fast_math_flags(fcmp_op) {
1409 let fastmath = self.fast_math_flags(ctx);
1410 llvm_set_fast_math_flags(fcmp_op, fastmath.into());
1411 }
1412 Ok(fcmp_op)
1413 }
1414}
1415
1416#[op_interface_impl]
1417impl ToLLVMValue for FPExtOp {
1418 fn convert(
1419 &self,
1420 ctx: &Context,
1421 llvm_ctx: &LLVMContext,
1422 cctx: &mut ConversionContext,
1423 ) -> Result<LLVMValue> {
1424 let op = self.get_operation().deref(ctx);
1425 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1426 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1427 let fpext_op = llvm_build_fpext(
1428 &cctx.builder,
1429 arg,
1430 ty,
1431 &self.get_result(ctx).unique_name(ctx),
1432 );
1433 if llvm_can_value_use_fast_math_flags(fpext_op) {
1435 let fastmath = self.fast_math_flags(ctx);
1436 llvm_set_fast_math_flags(fpext_op, fastmath.into());
1437 }
1438 Ok(fpext_op)
1439 }
1440}
1441
1442#[op_interface_impl]
1443impl ToLLVMValue for FPTruncOp {
1444 fn convert(
1445 &self,
1446 ctx: &Context,
1447 llvm_ctx: &LLVMContext,
1448 cctx: &mut ConversionContext,
1449 ) -> Result<LLVMValue> {
1450 let op = self.get_operation().deref(ctx);
1451 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1452 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1453 let fptrunc_op = llvm_build_fptrunc(
1454 &cctx.builder,
1455 arg,
1456 ty,
1457 &self.get_result(ctx).unique_name(ctx),
1458 );
1459 if llvm_can_value_use_fast_math_flags(fptrunc_op) {
1461 llvm_set_fast_math_flags(fptrunc_op, self.fast_math_flags(ctx).into());
1462 }
1463 Ok(fptrunc_op)
1464 }
1465}
1466
1467#[op_interface_impl]
1468impl ToLLVMValue for FPToSIOp {
1469 fn convert(
1470 &self,
1471 ctx: &Context,
1472 llvm_ctx: &LLVMContext,
1473 cctx: &mut ConversionContext,
1474 ) -> Result<LLVMValue> {
1475 let op = self.get_operation().deref(ctx);
1476 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1477 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1478 let fptosi_op = llvm_build_fptosi(
1479 &cctx.builder,
1480 arg,
1481 ty,
1482 &self.get_result(ctx).unique_name(ctx),
1483 );
1484 Ok(fptosi_op)
1485 }
1486}
1487
1488#[op_interface_impl]
1489impl ToLLVMValue for SIToFPOp {
1490 fn convert(
1491 &self,
1492 ctx: &Context,
1493 llvm_ctx: &LLVMContext,
1494 cctx: &mut ConversionContext,
1495 ) -> Result<LLVMValue> {
1496 let op = self.get_operation().deref(ctx);
1497 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1498 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1499 let sitofp_op = llvm_build_sitofp(
1500 &cctx.builder,
1501 arg,
1502 ty,
1503 &self.get_result(ctx).unique_name(ctx),
1504 );
1505 Ok(sitofp_op)
1506 }
1507}
1508
1509#[op_interface_impl]
1510impl ToLLVMValue for FPToUIOp {
1511 fn convert(
1512 &self,
1513 ctx: &Context,
1514 llvm_ctx: &LLVMContext,
1515 cctx: &mut ConversionContext,
1516 ) -> Result<LLVMValue> {
1517 let op = self.get_operation().deref(ctx);
1518 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1519 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1520 let fptoui_op = llvm_build_fptoui(
1521 &cctx.builder,
1522 arg,
1523 ty,
1524 &self.get_result(ctx).unique_name(ctx),
1525 );
1526 Ok(fptoui_op)
1527 }
1528}
1529
1530#[op_interface_impl]
1531impl ToLLVMValue for UIToFPOp {
1532 fn convert(
1533 &self,
1534 ctx: &Context,
1535 llvm_ctx: &LLVMContext,
1536 cctx: &mut ConversionContext,
1537 ) -> Result<LLVMValue> {
1538 let op = self.get_operation().deref(ctx);
1539 let arg = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1540 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1541 let uitofp_op = llvm_build_uitofp(
1542 &cctx.builder,
1543 arg,
1544 ty,
1545 &self.get_result(ctx).unique_name(ctx),
1546 );
1547 if llvm_is_a::instruction(uitofp_op) {
1549 let nneg = self.nneg(ctx);
1550 llvm_set_nneg(uitofp_op, nneg);
1551 }
1552 Ok(uitofp_op)
1553 }
1554}
1555
1556#[op_interface_impl]
1557impl ToLLVMValue for VAArgOp {
1558 fn convert(
1559 &self,
1560 ctx: &Context,
1561 llvm_ctx: &LLVMContext,
1562 cctx: &mut ConversionContext,
1563 ) -> Result<LLVMValue> {
1564 let op = self.get_operation().deref(ctx);
1565 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1566 let opd = convert_value_operand(cctx, ctx, &op.get_operand(0))?;
1567 log::warn!("Generating va_arg instruction: It is poorly supported by LLVM");
1568 let vaarg_op = llvm_build_va_arg(
1569 &cctx.builder,
1570 opd,
1571 ty,
1572 &self.get_result(ctx).unique_name(ctx),
1573 );
1574 Ok(vaarg_op)
1575 }
1576}
1577
1578fn convert_block(
1580 ctx: &Context,
1581 llvm_ctx: &LLVMContext,
1582 cctx: &mut ConversionContext,
1583 block: Ptr<BasicBlock>,
1584) -> Result<()> {
1585 let block_llvm = cctx.block_map[&block];
1586 llvm_position_builder_at_end(&cctx.builder, block_llvm);
1587
1588 for opr in block.deref(ctx).iter(ctx) {
1589 let op = Operation::get_op_dyn(opr, ctx);
1590 let op = op.as_ref();
1591 let Some(op_conv) = op_cast::<dyn ToLLVMValue>(op) else {
1592 let loc = op.loc(ctx);
1593 return input_err!(
1594 loc,
1595 ToLLVMErr::MissingOpConversion(op.get_opid().to_string())
1596 );
1597 };
1598 let op_llvm = op_conv.convert(ctx, llvm_ctx, cctx)?;
1599 let opr_ref = opr.deref(ctx);
1600 if opr_ref.get_num_results() == 1 {
1602 cctx.value_map.insert(opr_ref.get_result(0), op_llvm);
1603 }
1604 }
1605
1606 Ok(())
1607}
1608
1609fn convert_function(
1611 ctx: &Context,
1612 llvm_ctx: &LLVMContext,
1613 cctx: &mut ConversionContext,
1614 func_op: FuncOp,
1615) -> Result<LLVMValue> {
1616 cctx.clear_per_function_data();
1617 let func_llvm = cctx.function_map[&func_op.get_symbol_name(ctx)];
1618
1619 if let Some(linkage) = func_op.get_attr_llvm_function_linkage(ctx) {
1620 let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
1621 llvm_set_linkage(func_llvm, llvm_linkage);
1622 }
1623
1624 let f_region = func_op.get_region(ctx).expect("Function missing region");
1625
1626 let mut block_iter = f_region.deref(ctx).iter(ctx);
1628 {
1629 let entry = block_iter.next().expect("Missing entry block");
1630 for (arg_idx, arg) in entry.deref(ctx).arguments().enumerate() {
1632 cctx.value_map
1633 .insert(arg, llvm_get_param(func_llvm, arg_idx.try_into().unwrap()));
1634 }
1635 let llvm_entry_block = llvm_append_basic_block_in_context(
1636 llvm_ctx,
1637 func_llvm,
1638 &entry.deref(ctx).unique_name(ctx),
1639 );
1640 cctx.block_map.insert(entry, llvm_entry_block);
1641 }
1642 for block in block_iter {
1643 let llvm_block = llvm_append_basic_block_in_context(
1644 llvm_ctx,
1645 func_llvm,
1646 &block.deref(ctx).unique_name(ctx),
1647 );
1648 llvm_position_builder_at_end(&cctx.builder, llvm_block);
1649 for arg in block.deref(ctx).arguments() {
1650 let arg_type = convert_type(ctx, llvm_ctx, cctx, arg.get_type(ctx))?;
1651 let phi = llvm_build_phi(&cctx.builder, arg_type, &arg.unique_name(ctx));
1652 cctx.value_map.insert(arg, phi);
1653 }
1654 cctx.block_map.insert(block, llvm_block);
1655 }
1656
1657 for block in topological_order(ctx, &f_region) {
1659 convert_block(ctx, llvm_ctx, cctx, block)?;
1660 }
1661
1662 Ok(func_llvm)
1663}
1664
1665#[op_interface]
1666trait ToLLVMConstValue {
1667 fn convert(
1669 &self,
1670 ctx: &Context,
1671 llvm_ctx: &LLVMContext,
1672 cctx: &mut ConversionContext,
1673 ) -> Result<LLVMValue>;
1674
1675 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
1676 where
1677 Self: Sized,
1678 {
1679 Ok(())
1680 }
1681}
1682
1683#[op_interface_impl]
1684impl ToLLVMConstValue for ConstantOp {
1685 fn convert(
1686 &self,
1687 ctx: &Context,
1688 llvm_ctx: &LLVMContext,
1689 cctx: &mut ConversionContext,
1690 ) -> Result<LLVMValue> {
1691 let op = self.get_operation().deref(ctx);
1692 let value = self.get_value(ctx);
1693 if let Some(int_val) = value.downcast_ref::<IntegerAttr>() {
1694 let int_ty = int_val.get_type();
1695 let int_ty_llvm = convert_type(ctx, llvm_ctx, cctx, int_ty.into())?;
1696 let ap_int_val: APInt = int_val.clone().into();
1697 let const_val = llvm_const_int(int_ty_llvm, ap_int_val.to_u64(), false);
1698 Ok(const_val)
1699 } else if let Some(float_val) = attr_cast::<dyn FloatAttrToFP64>(&*value) {
1700 let float_ty = float_val.get_type(ctx);
1701 let float_ty_llvm = convert_type(ctx, llvm_ctx, cctx, float_ty)?;
1702 let const_val = llvm_const_real(float_ty_llvm, float_val.to_fp64());
1703 Ok(const_val)
1704 } else {
1705 input_err!(op.loc(), ToLLVMErr::ConstOpNotIntOrFloat)
1706 }
1707 }
1708}
1709
1710#[op_interface_impl]
1711impl ToLLVMConstValue for UndefOp {
1712 fn convert(
1713 &self,
1714 ctx: &Context,
1715 llvm_ctx: &LLVMContext,
1716 cctx: &mut ConversionContext,
1717 ) -> Result<LLVMValue> {
1718 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1719 Ok(llvm_get_undef(ty))
1720 }
1721}
1722
1723#[op_interface_impl]
1724impl ToLLVMConstValue for PoisonOp {
1725 fn convert(
1726 &self,
1727 ctx: &Context,
1728 llvm_ctx: &LLVMContext,
1729 cctx: &mut ConversionContext,
1730 ) -> Result<LLVMValue> {
1731 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1732 Ok(llvm_get_poison(ty))
1733 }
1734}
1735
1736#[op_interface_impl]
1737impl ToLLVMConstValue for ZeroOp {
1738 fn convert(
1739 &self,
1740 ctx: &Context,
1741 llvm_ctx: &LLVMContext,
1742 cctx: &mut ConversionContext,
1743 ) -> Result<LLVMValue> {
1744 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1745 let zero_val = llvm_const_null(ty);
1746 Ok(zero_val)
1747 }
1748}
1749
1750#[op_interface_impl]
1751impl ToLLVMConstValue for AddressOfOp {
1752 fn convert(
1753 &self,
1754 ctx: &Context,
1755 _llvm_ctx: &LLVMContext,
1756 cctx: &mut ConversionContext,
1757 ) -> Result<LLVMValue> {
1758 let sym = self.get_global_name(ctx);
1759 cctx.globals_map
1760 .get(&sym)
1761 .or_else(|| cctx.function_map.get(&sym))
1762 .cloned()
1763 .ok_or_else(|| input_error_noloc!(ToLLVMErr::CannotEvaluateToConst))
1764 }
1765}
1766#[op_interface_impl]
1767impl ToLLVMConstValue for InsertValueOp {
1768 fn convert(
1769 &self,
1770 ctx: &Context,
1771 llvm_ctx: &LLVMContext,
1772 cctx: &mut ConversionContext,
1773 ) -> Result<LLVMValue> {
1774 let op = self.get_operation().deref(ctx);
1775 let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1776 let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1777 let indices = self.indices(ctx);
1778 if indices.len() != 1 {
1779 return input_err!(op.loc(), ToLLVMErr::InsertExtractValueIndices);
1780 }
1781
1782 let insert_op = llvm_build_insert_value(
1784 &cctx.scratch_builder,
1785 base,
1786 value,
1787 indices[0],
1788 &self.get_result(ctx).unique_name(ctx),
1789 );
1790 if !llvm_is_a::constant(insert_op) {
1791 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1792 }
1793 Ok(insert_op)
1794 }
1795}
1796
1797#[op_interface_impl]
1798impl ToLLVMConstValue for InsertElementOp {
1799 fn convert(
1800 &self,
1801 ctx: &Context,
1802 llvm_ctx: &LLVMContext,
1803 cctx: &mut ConversionContext,
1804 ) -> Result<LLVMValue> {
1805 let op = self.get_operation().deref(ctx);
1806 let base = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1807 let value = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1808 let index = self.index_operand(ctx);
1809 let index = convert_to_llvm_const(ctx, cctx, llvm_ctx, index)?;
1810
1811 let insert_op = llvm_build_insert_element(
1813 &cctx.scratch_builder,
1814 base,
1815 value,
1816 index,
1817 &self.get_result(ctx).unique_name(ctx),
1818 );
1819 if !llvm_is_a::constant(insert_op) {
1820 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1821 }
1822 Ok(insert_op)
1823 }
1824}
1825
1826#[op_interface_impl]
1827impl ToLLVMConstValue for TruncOp {
1828 fn convert(
1829 &self,
1830 ctx: &Context,
1831 llvm_ctx: &LLVMContext,
1832 cctx: &mut ConversionContext,
1833 ) -> Result<LLVMValue> {
1834 let op = self.get_operation().deref(ctx);
1835 let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1836 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1837
1838 let trunc_op = llvm_build_trunc(
1840 &cctx.scratch_builder,
1841 arg,
1842 ty,
1843 &self.get_result(ctx).unique_name(ctx),
1844 );
1845 if !llvm_is_a::constant(trunc_op) {
1846 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1847 }
1848 Ok(trunc_op)
1849 }
1850}
1851
1852#[op_interface_impl]
1853impl ToLLVMConstValue for SubOp {
1854 fn convert(
1855 &self,
1856 ctx: &Context,
1857 llvm_ctx: &LLVMContext,
1858 cctx: &mut ConversionContext,
1859 ) -> Result<LLVMValue> {
1860 let op = self.get_operation().deref(ctx);
1861 let lhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1862 let rhs = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(1))?;
1863
1864 let sub_op = llvm_build_sub(
1866 &cctx.scratch_builder,
1867 lhs,
1868 rhs,
1869 &self.get_result(ctx).unique_name(ctx),
1870 );
1871 if !llvm_is_a::constant(sub_op) {
1872 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1873 }
1874 Ok(sub_op)
1875 }
1876}
1877
1878#[op_interface_impl]
1879impl ToLLVMConstValue for PtrToIntOp {
1880 fn convert(
1881 &self,
1882 ctx: &Context,
1883 llvm_ctx: &LLVMContext,
1884 cctx: &mut ConversionContext,
1885 ) -> Result<LLVMValue> {
1886 let op = self.get_operation().deref(ctx);
1887 let arg = convert_to_llvm_const(ctx, cctx, llvm_ctx, op.get_operand(0))?;
1888 let ty = convert_type(ctx, llvm_ctx, cctx, self.result_type(ctx))?;
1889
1890 let ptoi_op = llvm_build_ptr_to_int(
1892 &cctx.scratch_builder,
1893 arg,
1894 ty,
1895 &self.get_result(ctx).unique_name(ctx),
1896 );
1897 if !llvm_is_a::constant(ptoi_op) {
1898 return input_err!(op.loc(), ToLLVMErr::CannotEvaluateToConst);
1899 }
1900 Ok(ptoi_op)
1901 }
1902}
1903
1904fn convert_to_llvm_const(
1905 ctx: &Context,
1906 cctx: &mut ConversionContext,
1907 llvm_ctx: &LLVMContext,
1908 value: Value,
1909) -> Result<LLVMValue> {
1910 match value.defining_entity() {
1911 DefiningEntity::Op(op) => {
1912 let op = Operation::get_op_dyn(op, ctx);
1913 if let Some(const_trans) = op_cast::<dyn ToLLVMConstValue>(op.as_ref()) {
1914 const_trans.convert(ctx, llvm_ctx, cctx)
1915 } else {
1916 input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
1917 }
1918 }
1919 DefiningEntity::Block(_) => {
1920 input_err!(value.loc(ctx), ToLLVMErr::CannotEvaluateToConst)
1921 }
1922 }
1923}
1924
1925fn convert_global_initializer(
1926 ctx: &Context,
1927 llvm_ctx: &LLVMContext,
1928 cctx: &mut ConversionContext,
1929 global_op: GlobalOp,
1930) -> Result<Option<LLVMValue>> {
1931 if let Some(_initializer) = global_op.get_initializer_value(ctx) {
1932 todo!()
1933 }
1934
1935 if let Some(init_block) = global_op.get_initializer_block(ctx) {
1936 let ret =
1937 Operation::get_op::<ReturnOp>(init_block.deref(ctx).get_terminator(ctx).unwrap(), ctx);
1938 let ret = ret.ok_or_else(|| {
1939 input_error!(
1940 global_op.loc(ctx),
1941 ToLLVMErr::GlobalOpInitializerRegionBadReturn
1942 )
1943 })?;
1944 let Some(ret_val) = ret.retval(ctx) else {
1945 return input_err!(
1946 global_op.loc(ctx),
1947 ToLLVMErr::GlobalOpInitializerRegionBadReturn
1948 );
1949 };
1950 let initializer_val = convert_to_llvm_const(ctx, cctx, llvm_ctx, ret_val)?;
1951 return Ok(Some(initializer_val));
1952 }
1953
1954 Ok(None)
1955}
1956
1957pub fn convert_module(
1959 ctx: &Context,
1960 llvm_ctx: &LLVMContext,
1961 module: ModuleOp,
1962) -> Result<LLVMModule> {
1963 let mod_name = module.get_symbol_name(ctx);
1964 let llvm_module = LLVMModule::new(&mod_name, llvm_ctx);
1965 let cctx = &mut ConversionContext::new(llvm_ctx, &llvm_module);
1966
1967 let scratch_module = LLVMModule::new("__pliron_scratch_module", llvm_ctx);
1970 let scratch_function = llvm_add_function(
1971 &scratch_module,
1972 "scratch",
1973 llvm_function_type(llvm_void_type_in_context(llvm_ctx), &[], false),
1974 );
1975 let scratch_function_entry =
1976 llvm_append_basic_block_in_context(llvm_ctx, scratch_function, "entry");
1977 llvm_position_builder_at_end(&cctx.scratch_builder, scratch_function_entry);
1978
1979 for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
1981 if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx) {
1982 let func_ty = func_op.get_type(ctx).deref(ctx);
1983 let func_ty_to_llvm = type_cast::<dyn ToLLVMType>(&*func_ty).ok_or_else(|| {
1984 input_error_noloc!(ToLLVMErr::MissingTypeConversion(
1985 func_ty.disp(ctx).to_string()
1986 ))
1987 })?;
1988 let fn_ty_llvm = func_ty_to_llvm.convert(ctx, llvm_ctx, cctx)?;
1989 let name = func_op.get_symbol_name(ctx);
1990 let llvm_name = func_op.llvm_symbol_name(ctx).unwrap_or(name.clone().into());
1991 let func_llvm = llvm_add_function(&llvm_module, &llvm_name, fn_ty_llvm);
1992 cctx.function_map.insert(name, func_llvm);
1993 }
1994 if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
1995 let global_ty = global_op.get_type(ctx);
1996 let global_ty_llvm = convert_type(ctx, llvm_ctx, cctx, global_ty)?;
1997 let global_name = global_op.get_symbol_name(ctx);
1998 let llvm_global_name = global_op
1999 .llvm_symbol_name(ctx)
2000 .unwrap_or(global_name.clone().into());
2001 let global_llvm = llvm_add_global(&llvm_module, global_ty_llvm, &llvm_global_name);
2002 cctx.globals_map.insert(global_name, global_llvm);
2003 }
2004 }
2005
2006 for op in module.get_body(ctx, 0).deref(ctx).iter(ctx) {
2007 if let Some(func_op) = Operation::get_op::<FuncOp>(op, ctx)
2008 && !func_op.is_declaration(ctx)
2009 {
2010 convert_function(ctx, llvm_ctx, cctx, func_op)?;
2011 }
2012 if let Some(global_op) = Operation::get_op::<GlobalOp>(op, ctx) {
2013 let global_name = global_op.get_symbol_name(ctx);
2014 let global_llvm = cctx.globals_map[&global_name];
2015 if !global_op.is_declaration(ctx)
2016 && let Some(initializer) =
2017 convert_global_initializer(ctx, llvm_ctx, cctx, global_op)?
2018 {
2019 llvm_set_initializer(global_llvm, initializer);
2020 }
2021 if let Some(linkage) = global_op.get_attr_llvm_global_linkage(ctx) {
2022 let llvm_linkage: LLVMLinkage = convert_linkage(linkage.clone());
2023 llvm_set_linkage(global_llvm, llvm_linkage);
2024 }
2025 if let Some(alignment) = global_op.alignment(ctx) {
2026 llvm_set_alignment(global_llvm, alignment);
2027 }
2028 }
2029 }
2030
2031 Ok(llvm_module)
2032}