Skip to main content

melior/dialect/
llvm.rs

1//! `llvm` dialect.
2
3use crate::{
4    ir::{
5        attribute::{
6            DenseI32ArrayAttribute, DenseI64ArrayAttribute, IntegerAttribute, StringAttribute,
7            TypeAttribute,
8        },
9        operation::OperationBuilder,
10        r#type::IntegerType,
11        Attribute, Identifier, Location, Operation, Region, Type, Value,
12    },
13    Context,
14};
15pub use alloca_options::*;
16pub use load_store_options::*;
17
18mod alloca_options;
19pub mod attributes;
20mod load_store_options;
21pub mod r#type;
22
23// spell-checker: disable
24
25/// Creates a `llvm.extractvalue` operation.
26pub fn extract_value<'c>(
27    context: &'c Context,
28    container: Value<'c, '_>,
29    position: DenseI64ArrayAttribute<'c>,
30    result_type: Type<'c>,
31    location: Location<'c>,
32) -> Operation<'c> {
33    OperationBuilder::new("llvm.extractvalue", location)
34        .add_attributes(&[(Identifier::new(context, "position"), position.into())])
35        .add_operands(&[container])
36        .add_results(&[result_type])
37        .build()
38        .expect("valid operation")
39}
40
41/// Creates a `llvm.getelementptr` operation.
42pub fn get_element_ptr<'c>(
43    context: &'c Context,
44    ptr: Value<'c, '_>,
45    indices: DenseI32ArrayAttribute<'c>,
46    element_type: Type<'c>,
47    result_type: Type<'c>,
48    location: Location<'c>,
49) -> Operation<'c> {
50    OperationBuilder::new("llvm.getelementptr", location)
51        .add_attributes(&[
52            (
53                Identifier::new(context, "rawConstantIndices"),
54                indices.into(),
55            ),
56            (
57                Identifier::new(context, "elem_type"),
58                TypeAttribute::new(element_type).into(),
59            ),
60        ])
61        .add_operands(&[ptr])
62        .add_results(&[result_type])
63        .build()
64        .expect("valid operation")
65}
66
67/// Creates a `llvm.getelementptr` operation with dynamic indices.
68pub fn get_element_ptr_dynamic<'c, const N: usize>(
69    context: &'c Context,
70    ptr: Value<'c, '_>,
71    indices: &[Value<'c, '_>; N],
72    element_type: Type<'c>,
73    result_type: Type<'c>,
74    location: Location<'c>,
75) -> Operation<'c> {
76    OperationBuilder::new("llvm.getelementptr", location)
77        .add_attributes(&[
78            (
79                Identifier::new(context, "rawConstantIndices"),
80                DenseI32ArrayAttribute::new(context, &[i32::MIN; N]).into(),
81            ),
82            (
83                Identifier::new(context, "elem_type"),
84                TypeAttribute::new(element_type).into(),
85            ),
86        ])
87        .add_operands(&[ptr])
88        .add_operands(indices)
89        .add_results(&[result_type])
90        .build()
91        .expect("valid operation")
92}
93
94/// Creates a `llvm.insertvalue` operation.
95pub fn insert_value<'c>(
96    context: &'c Context,
97    container: Value<'c, '_>,
98    position: DenseI64ArrayAttribute<'c>,
99    value: Value<'c, '_>,
100    location: Location<'c>,
101) -> Operation<'c> {
102    OperationBuilder::new("llvm.insertvalue", location)
103        .add_attributes(&[(Identifier::new(context, "position"), position.into())])
104        .add_operands(&[container, value])
105        .enable_result_type_inference()
106        .build()
107        .expect("valid operation")
108}
109
110/// Creates a `llvm.mlir.undef` operation.
111pub fn undef<'c>(result_type: Type<'c>, location: Location<'c>) -> Operation<'c> {
112    OperationBuilder::new("llvm.mlir.undef", location)
113        .add_results(&[result_type])
114        .build()
115        .expect("valid operation")
116}
117
118/// Creates a `llvm.mlir.poison` operation.
119pub fn poison<'c>(result_type: Type<'c>, location: Location<'c>) -> Operation<'c> {
120    OperationBuilder::new("llvm.mlir.poison", location)
121        .add_results(&[result_type])
122        .build()
123        .expect("valid operation")
124}
125
126/// Creates a zero value.
127pub fn zero<'c>(r#type: Type<'c>, location: Location<'c>) -> Operation<'c> {
128    OperationBuilder::new("llvm.mlir.zero", location)
129        .add_results(&[r#type])
130        .build()
131        .expect("valid operation")
132}
133
134/// Creates a null pointer.
135#[deprecated]
136pub fn nullptr<'c>(ptr_type: Type<'c>, location: Location<'c>) -> Operation<'c> {
137    zero(ptr_type, location)
138}
139
140/// Creates a `llvm.unreachable` operation.
141pub fn unreachable(location: Location) -> Operation {
142    OperationBuilder::new("llvm.unreachable", location)
143        .build()
144        .expect("valid operation")
145}
146
147/// Creates a `llvm.bitcast` operation.
148pub fn bitcast<'c>(
149    argument: Value<'c, '_>,
150    result: Type<'c>,
151    location: Location<'c>,
152) -> Operation<'c> {
153    OperationBuilder::new("llvm.bitcast", location)
154        .add_operands(&[argument])
155        .add_results(&[result])
156        .build()
157        .expect("valid operation")
158}
159
160/// Creates a `llvm.alloca` operation.
161pub fn alloca<'c>(
162    context: &'c Context,
163    array_size: Value<'c, '_>,
164    ptr_type: Type<'c>,
165    location: Location<'c>,
166    extra_options: AllocaOptions<'c>,
167) -> Operation<'c> {
168    OperationBuilder::new("llvm.alloca", location)
169        .add_operands(&[array_size])
170        .add_attributes(&extra_options.into_attributes(context))
171        .add_results(&[ptr_type])
172        .build()
173        .expect("valid operation")
174}
175
176/// Creates a `llvm.store` operation.
177pub fn store<'c>(
178    context: &'c Context,
179    value: Value<'c, '_>,
180    addr: Value<'c, '_>,
181    location: Location<'c>,
182    extra_options: LoadStoreOptions<'c>,
183) -> Operation<'c> {
184    OperationBuilder::new("llvm.store", location)
185        .add_operands(&[value, addr])
186        .add_attributes(&extra_options.into_attributes(context))
187        .build()
188        .expect("valid operation")
189}
190
191/// Creates a `llvm.load` operation.
192pub fn load<'c>(
193    context: &'c Context,
194    addr: Value<'c, '_>,
195    r#type: Type<'c>,
196    location: Location<'c>,
197    extra_options: LoadStoreOptions<'c>,
198) -> Operation<'c> {
199    OperationBuilder::new("llvm.load", location)
200        .add_operands(&[addr])
201        .add_attributes(&extra_options.into_attributes(context))
202        .add_results(&[r#type])
203        .build()
204        .expect("valid operation")
205}
206
207/// Create a `llvm.func` operation.
208pub fn func<'c>(
209    context: &'c Context,
210    name: StringAttribute<'c>,
211    r#type: TypeAttribute<'c>,
212    region: Region<'c>,
213    attributes: &[(Identifier<'c>, Attribute<'c>)],
214    location: Location<'c>,
215) -> Operation<'c> {
216    OperationBuilder::new("llvm.func", location)
217        .add_attributes(&[
218            (Identifier::new(context, "sym_name"), name.into()),
219            (Identifier::new(context, "function_type"), r#type.into()),
220        ])
221        .add_attributes(attributes)
222        .add_regions([region])
223        .build()
224        .expect("valid operation")
225}
226
227// Creates a `llvm.return` operation.
228pub fn r#return<'c>(value: Option<Value<'c, '_>>, location: Location<'c>) -> Operation<'c> {
229    let mut builder = OperationBuilder::new("llvm.return", location);
230
231    if let Some(value) = value {
232        builder = builder.add_operands(&[value]);
233    }
234
235    builder.build().expect("valid operation")
236}
237
238/// Creates a `llvm.call_intrinsic` operation.
239pub fn call_intrinsic<'c>(
240    context: &'c Context,
241    intrin: StringAttribute<'c>,
242    args: &[Value<'c, '_>],
243    results: &[Type<'c>],
244    location: Location<'c>,
245) -> Operation<'c> {
246    OperationBuilder::new("llvm.call_intrinsic", location)
247        .add_operands(args)
248        .add_attributes(&[(Identifier::new(context, "intrin"), intrin.into())])
249        .add_results(results)
250        .build()
251        .expect("valid operation")
252}
253
254/// Creates a `llvm.intr.ctlz` operation.
255pub fn intr_ctlz<'c>(
256    context: &'c Context,
257    value: Value<'c, '_>,
258    is_zero_poison: bool,
259    result_type: Type<'c>,
260    location: Location<'c>,
261) -> Operation<'c> {
262    OperationBuilder::new("llvm.intr.ctlz", location)
263        .add_attributes(&[(
264            Identifier::new(context, "is_zero_poison"),
265            IntegerAttribute::new(IntegerType::new(context, 1).into(), is_zero_poison.into())
266                .into(),
267        )])
268        .add_operands(&[value])
269        .add_results(&[result_type])
270        .build()
271        .expect("valid operation")
272}
273
274/// Creates a `llvm.intr.ctlz` operation.
275pub fn intr_cttz<'c>(
276    context: &'c Context,
277    value: Value<'c, '_>,
278    is_zero_poison: bool,
279    result_type: Type<'c>,
280    location: Location<'c>,
281) -> Operation<'c> {
282    OperationBuilder::new("llvm.intr.cttz", location)
283        .add_attributes(&[(
284            Identifier::new(context, "is_zero_poison"),
285            IntegerAttribute::new(IntegerType::new(context, 1).into(), is_zero_poison.into())
286                .into(),
287        )])
288        .add_operands(&[value])
289        .add_results(&[result_type])
290        .build()
291        .expect("valid operation")
292}
293
294/// Creates a `llvm.intr.ctlz` operation.
295pub fn intr_ctpop<'c>(
296    value: Value<'c, '_>,
297    result_type: Type<'c>,
298    location: Location<'c>,
299) -> Operation<'c> {
300    OperationBuilder::new("llvm.intr.ctpop", location)
301        .add_operands(&[value])
302        .add_results(&[result_type])
303        .build()
304        .expect("valid operation")
305}
306
307/// Creates a `llvm.intr.bswap` operation.
308pub fn intr_bswap<'c>(
309    value: Value<'c, '_>,
310    result_type: Type<'c>,
311    location: Location<'c>,
312) -> Operation<'c> {
313    OperationBuilder::new("llvm.intr.bswap", location)
314        .add_operands(&[value])
315        .add_results(&[result_type])
316        .build()
317        .expect("valid operation")
318}
319
320/// Creates a `llvm.intr.bitreverse` operation.
321pub fn intr_bitreverse<'c>(
322    value: Value<'c, '_>,
323    result_type: Type<'c>,
324    location: Location<'c>,
325) -> Operation<'c> {
326    OperationBuilder::new("llvm.intr.bitreverse", location)
327        .add_operands(&[value])
328        .add_results(&[result_type])
329        .build()
330        .expect("valid operation")
331}
332
333/// Creates a `llvm.intr.abs` operation.
334pub fn intr_abs<'c>(
335    context: &'c Context,
336    value: Value<'c, '_>,
337    is_int_min_poison: bool,
338    result_type: Type<'c>,
339    location: Location<'c>,
340) -> Operation<'c> {
341    OperationBuilder::new("llvm.intr.abs", location)
342        .add_attributes(&[(
343            Identifier::new(context, "is_int_min_poison"),
344            IntegerAttribute::new(
345                IntegerType::new(context, 1).into(),
346                is_int_min_poison.into(),
347            )
348            .into(),
349        )])
350        .add_operands(&[value])
351        .add_results(&[result_type])
352        .build()
353        .expect("valid operation")
354}
355
356/// Creates a `llvm.zext` operation.
357pub fn zext<'c>(
358    value: Value<'c, '_>,
359    result_type: Type<'c>,
360    location: Location<'c>,
361) -> Operation<'c> {
362    OperationBuilder::new("llvm.zext", location)
363        .add_operands(&[value])
364        .add_results(&[result_type])
365        .build()
366        .expect("valid operation")
367}
368
369#[cfg(test)]
370mod tests {
371    use tests::r#type::pointer;
372
373    use super::*;
374    use crate::{
375        dialect::{
376            arith, func,
377            llvm::{
378                attributes::{linkage, Linkage},
379                r#type::function,
380            },
381        },
382        ir::{
383            attribute::{IntegerAttribute, StringAttribute, TypeAttribute},
384            r#type::{FunctionType, IntegerType},
385            Block, Module, Region,
386        },
387        pass::{self, PassManager},
388        test::create_test_context,
389    };
390
391    fn convert_module<'c>(context: &'c Context, module: &mut Module<'c>) {
392        let pass_manager = PassManager::new(context);
393
394        pass_manager.add_pass(pass::conversion::create_func_to_llvm());
395        pass_manager
396            .nested_under("func.func")
397            .add_pass(pass::conversion::create_arith_to_llvm());
398        pass_manager
399            .nested_under("func.func")
400            .add_pass(pass::conversion::create_index_to_llvm());
401        pass_manager.add_pass(pass::conversion::create_scf_to_control_flow());
402        pass_manager.add_pass(pass::conversion::create_control_flow_to_llvm());
403        pass_manager.add_pass(pass::conversion::create_finalize_mem_ref_to_llvm());
404
405        assert_eq!(pass_manager.run(module), Ok(()));
406        assert!(module.as_operation().verify());
407    }
408
409    #[test]
410    fn compile_extract_value() {
411        let context = create_test_context();
412
413        let location = Location::unknown(&context);
414        let mut module = Module::new(location);
415        let integer_type = IntegerType::new(&context, 64).into();
416        let struct_type = r#type::r#struct(&context, &[integer_type], false);
417
418        module.body().append_operation(func::func(
419            &context,
420            StringAttribute::new(&context, "foo"),
421            TypeAttribute::new(FunctionType::new(&context, &[struct_type], &[]).into()),
422            {
423                let block = Block::new(&[(struct_type, location)]);
424
425                block.append_operation(extract_value(
426                    &context,
427                    block.argument(0).unwrap().into(),
428                    DenseI64ArrayAttribute::new(&context, &[0]),
429                    integer_type,
430                    location,
431                ));
432
433                block.append_operation(func::r#return(&[], location));
434
435                let region = Region::new();
436                region.append_block(block);
437                region
438            },
439            &[],
440            location,
441        ));
442
443        convert_module(&context, &mut module);
444
445        assert!(module.as_operation().verify());
446        insta::assert_snapshot!(module.as_operation());
447    }
448
449    #[test]
450    fn compile_get_element_ptr() {
451        let context = create_test_context();
452
453        let location = Location::unknown(&context);
454        let mut module = Module::new(location);
455        let integer_type = IntegerType::new(&context, 64).into();
456        let ptr_type = r#type::pointer(&context, 0);
457
458        module.body().append_operation(func::func(
459            &context,
460            StringAttribute::new(&context, "foo"),
461            TypeAttribute::new(FunctionType::new(&context, &[ptr_type], &[]).into()),
462            {
463                let block = Block::new(&[(ptr_type, location)]);
464
465                block.append_operation(get_element_ptr(
466                    &context,
467                    block.argument(0).unwrap().into(),
468                    DenseI32ArrayAttribute::new(&context, &[42]),
469                    integer_type,
470                    ptr_type,
471                    location,
472                ));
473
474                block.append_operation(func::r#return(&[], location));
475
476                let region = Region::new();
477                region.append_block(block);
478                region
479            },
480            &[],
481            location,
482        ));
483
484        convert_module(&context, &mut module);
485
486        assert!(module.as_operation().verify());
487        insta::assert_snapshot!(module.as_operation());
488    }
489
490    #[test]
491    fn compile_get_element_ptr_dynamic() {
492        let context = create_test_context();
493
494        let location = Location::unknown(&context);
495        let mut module = Module::new(location);
496        let integer_type = IntegerType::new(&context, 64).into();
497        let ptr_type = r#type::pointer(&context, 0);
498
499        module.body().append_operation(func::func(
500            &context,
501            StringAttribute::new(&context, "foo"),
502            TypeAttribute::new(FunctionType::new(&context, &[ptr_type], &[]).into()),
503            {
504                let block = Block::new(&[(ptr_type, location)]);
505
506                let index = block
507                    .append_operation(arith::constant(
508                        &context,
509                        IntegerAttribute::new(integer_type, 42).into(),
510                        location,
511                    ))
512                    .result(0)
513                    .unwrap()
514                    .into();
515
516                block.append_operation(get_element_ptr_dynamic(
517                    &context,
518                    block.argument(0).unwrap().into(),
519                    &[index],
520                    integer_type,
521                    ptr_type,
522                    location,
523                ));
524
525                block.append_operation(func::r#return(&[], location));
526
527                let region = Region::new();
528                region.append_block(block);
529                region
530            },
531            &[],
532            location,
533        ));
534
535        convert_module(&context, &mut module);
536
537        assert!(module.as_operation().verify());
538        insta::assert_snapshot!(module.as_operation());
539    }
540
541    #[test]
542    fn compile_insert_value() {
543        let context = create_test_context();
544
545        let location = Location::unknown(&context);
546        let mut module = Module::new(location);
547        let integer_type = IntegerType::new(&context, 64).into();
548        let struct_type = r#type::r#struct(&context, &[integer_type], false);
549
550        module.body().append_operation(func::func(
551            &context,
552            StringAttribute::new(&context, "foo"),
553            TypeAttribute::new(FunctionType::new(&context, &[struct_type], &[]).into()),
554            {
555                let block = Block::new(&[(struct_type, location)]);
556                let value = block
557                    .append_operation(arith::constant(
558                        &context,
559                        IntegerAttribute::new(integer_type, 42).into(),
560                        location,
561                    ))
562                    .result(0)
563                    .unwrap()
564                    .into();
565
566                block.append_operation(insert_value(
567                    &context,
568                    block.argument(0).unwrap().into(),
569                    DenseI64ArrayAttribute::new(&context, &[0]),
570                    value,
571                    location,
572                ));
573
574                block.append_operation(func::r#return(&[], location));
575
576                let region = Region::new();
577                region.append_block(block);
578                region
579            },
580            &[],
581            location,
582        ));
583
584        convert_module(&context, &mut module);
585
586        assert!(module.as_operation().verify());
587        insta::assert_snapshot!(module.as_operation());
588    }
589
590    #[test]
591    fn compile_zero() {
592        let context = create_test_context();
593
594        let location = Location::unknown(&context);
595        let mut module = Module::new(location);
596        let integer_type = IntegerType::new(&context, 64).into();
597
598        module.body().append_operation(func::func(
599            &context,
600            StringAttribute::new(&context, "foo"),
601            TypeAttribute::new(FunctionType::new(&context, &[], &[integer_type]).into()),
602            {
603                let block = Block::new(&[]);
604
605                let operation = block.append_operation(zero(integer_type, location));
606
607                block.append_operation(func::r#return(
608                    &[operation.result(0).unwrap().into()],
609                    location,
610                ));
611
612                let region = Region::new();
613                region.append_block(block);
614                region
615            },
616            &[],
617            location,
618        ));
619
620        convert_module(&context, &mut module);
621
622        assert!(module.as_operation().verify());
623        insta::assert_snapshot!(module.as_operation());
624    }
625
626    #[test]
627    fn compile_null_ptr() {
628        let context = create_test_context();
629
630        let location = Location::unknown(&context);
631        let mut module = Module::new(location);
632        let ptr_type = r#type::pointer(&context, 0);
633
634        module.body().append_operation(func::func(
635            &context,
636            StringAttribute::new(&context, "foo"),
637            TypeAttribute::new(FunctionType::new(&context, &[], &[ptr_type]).into()),
638            {
639                let block = Block::new(&[]);
640
641                let operation = block.append_operation(zero(ptr_type, location));
642
643                block.append_operation(func::r#return(
644                    &[operation.result(0).unwrap().into()],
645                    location,
646                ));
647
648                let region = Region::new();
649                region.append_block(block);
650                region
651            },
652            &[],
653            location,
654        ));
655
656        convert_module(&context, &mut module);
657
658        assert!(module.as_operation().verify());
659        insta::assert_snapshot!(module.as_operation());
660    }
661
662    #[test]
663    fn compile_undefined() {
664        let context = create_test_context();
665
666        let location = Location::unknown(&context);
667        let mut module = Module::new(location);
668        let struct_type =
669            r#type::r#struct(&context, &[IntegerType::new(&context, 64).into()], false);
670
671        module.body().append_operation(func::func(
672            &context,
673            StringAttribute::new(&context, "foo"),
674            TypeAttribute::new(FunctionType::new(&context, &[struct_type], &[]).into()),
675            {
676                let block = Block::new(&[(struct_type, location)]);
677
678                block.append_operation(undef(struct_type, location));
679
680                block.append_operation(func::r#return(&[], location));
681
682                let region = Region::new();
683                region.append_block(block);
684                region
685            },
686            &[],
687            location,
688        ));
689
690        convert_module(&context, &mut module);
691
692        assert!(module.as_operation().verify());
693        insta::assert_snapshot!(module.as_operation());
694    }
695
696    #[test]
697    fn compile_poison() {
698        let context = create_test_context();
699
700        let location = Location::unknown(&context);
701        let mut module = Module::new(location);
702        let struct_type =
703            r#type::r#struct(&context, &[IntegerType::new(&context, 64).into()], false);
704
705        module.body().append_operation(func::func(
706            &context,
707            StringAttribute::new(&context, "foo"),
708            TypeAttribute::new(FunctionType::new(&context, &[struct_type], &[]).into()),
709            {
710                let block = Block::new(&[(struct_type, location)]);
711
712                block.append_operation(poison(struct_type, location));
713
714                block.append_operation(func::r#return(&[], location));
715
716                let region = Region::new();
717                region.append_block(block);
718                region
719            },
720            &[],
721            location,
722        ));
723
724        convert_module(&context, &mut module);
725
726        assert!(module.as_operation().verify());
727        insta::assert_snapshot!(module.as_operation());
728    }
729
730    #[test]
731    fn compile_alloca() {
732        let context = create_test_context();
733
734        let location = Location::unknown(&context);
735        let mut module = Module::new(location);
736        let integer_type = IntegerType::new(&context, 64).into();
737        let ptr_type = r#type::pointer(&context, 0);
738
739        module.body().append_operation(func::func(
740            &context,
741            StringAttribute::new(&context, "foo"),
742            TypeAttribute::new(FunctionType::new(&context, &[integer_type], &[]).into()),
743            {
744                let block = Block::new(&[(integer_type, location)]);
745
746                block.append_operation(alloca(
747                    &context,
748                    block.argument(0).unwrap().into(),
749                    ptr_type,
750                    location,
751                    AllocaOptions::new().elem_type(Some(TypeAttribute::new(integer_type))),
752                ));
753
754                block.append_operation(func::r#return(&[], location));
755
756                let region = Region::new();
757                region.append_block(block);
758                region
759            },
760            &[],
761            location,
762        ));
763
764        convert_module(&context, &mut module);
765
766        assert!(module.as_operation().verify());
767        insta::assert_snapshot!(module.as_operation());
768    }
769
770    #[test]
771    fn compile_store() {
772        let context = create_test_context();
773
774        let location = Location::unknown(&context);
775        let mut module = Module::new(location);
776        let integer_type = IntegerType::new(&context, 64).into();
777        let ptr_type = r#type::pointer(&context, 0);
778
779        module.body().append_operation(func::func(
780            &context,
781            StringAttribute::new(&context, "foo"),
782            TypeAttribute::new(FunctionType::new(&context, &[ptr_type, integer_type], &[]).into()),
783            {
784                let block = Block::new(&[(ptr_type, location), (integer_type, location)]);
785
786                block.append_operation(store(
787                    &context,
788                    block.argument(1).unwrap().into(),
789                    block.argument(0).unwrap().into(),
790                    location,
791                    Default::default(),
792                ));
793
794                block.append_operation(func::r#return(&[], location));
795
796                let region = Region::new();
797                region.append_block(block);
798                region
799            },
800            &[],
801            location,
802        ));
803
804        convert_module(&context, &mut module);
805
806        assert!(module.as_operation().verify());
807        insta::assert_snapshot!(module.as_operation());
808    }
809
810    #[test]
811    fn compile_load() {
812        let context = create_test_context();
813
814        let location = Location::unknown(&context);
815        let mut module = Module::new(location);
816        let integer_type = IntegerType::new(&context, 64).into();
817        let ptr_type = r#type::pointer(&context, 0);
818
819        module.body().append_operation(func::func(
820            &context,
821            StringAttribute::new(&context, "foo"),
822            TypeAttribute::new(FunctionType::new(&context, &[ptr_type], &[]).into()),
823            {
824                let block = Block::new(&[(ptr_type, location)]);
825
826                block.append_operation(load(
827                    &context,
828                    block.argument(0).unwrap().into(),
829                    integer_type,
830                    location,
831                    Default::default(),
832                ));
833
834                block.append_operation(func::r#return(&[], location));
835
836                let region = Region::new();
837                region.append_block(block);
838                region
839            },
840            &[],
841            location,
842        ));
843
844        convert_module(&context, &mut module);
845
846        assert!(module.as_operation().verify());
847        insta::assert_snapshot!(module.as_operation());
848    }
849
850    #[test]
851    fn compile_store_extra() {
852        let context = create_test_context();
853
854        let location = Location::unknown(&context);
855        let mut module = Module::new(location);
856        let integer_type = IntegerType::new(&context, 64).into();
857        let ptr_type = r#type::pointer(&context, 0);
858
859        module.body().append_operation(func::func(
860            &context,
861            StringAttribute::new(&context, "foo"),
862            TypeAttribute::new(FunctionType::new(&context, &[ptr_type, integer_type], &[]).into()),
863            {
864                let block = Block::new(&[(ptr_type, location), (integer_type, location)]);
865
866                block.append_operation(store(
867                    &context,
868                    block.argument(1).unwrap().into(),
869                    block.argument(0).unwrap().into(),
870                    location,
871                    LoadStoreOptions::new()
872                        .align(Some(IntegerAttribute::new(integer_type, 4)))
873                        .volatile(true)
874                        .nontemporal(true),
875                ));
876
877                block.append_operation(func::r#return(&[], location));
878
879                let region = Region::new();
880                region.append_block(block);
881                region
882            },
883            &[],
884            location,
885        ));
886
887        convert_module(&context, &mut module);
888
889        assert!(module.as_operation().verify());
890        insta::assert_snapshot!(module.as_operation());
891    }
892
893    #[test]
894    fn compile_func() {
895        let context = create_test_context();
896
897        let location = Location::unknown(&context);
898        let mut module = Module::new(location);
899        let integer_type = IntegerType::new(&context, 32).into();
900
901        module.body().append_operation(func(
902            &context,
903            StringAttribute::new(&context, "printf"),
904            TypeAttribute::new(function(integer_type, &[pointer(&context, 0)], true)),
905            Region::new(),
906            &[(
907                Identifier::new(&context, "linkage"),
908                linkage(&context, Linkage::External),
909            )],
910            location,
911        ));
912
913        convert_module(&context, &mut module);
914
915        assert!(module.as_operation().verify());
916        insta::assert_snapshot!(module.as_operation());
917    }
918
919    #[test]
920    fn compile_return() {
921        let context = create_test_context();
922
923        let location = Location::unknown(&context);
924        let mut module = Module::new(location);
925        let integer_type = IntegerType::new(&context, 64).into();
926        let struct_type = r#type::r#struct(&context, &[integer_type], false);
927
928        module.body().append_operation(func::func(
929            &context,
930            StringAttribute::new(&context, "foo_none"),
931            TypeAttribute::new(FunctionType::new(&context, &[], &[]).into()),
932            {
933                let block = Block::new(&[]);
934
935                block.append_operation(r#return(None, location));
936
937                let region = Region::new();
938                region.append_block(block);
939                region
940            },
941            &[],
942            location,
943        ));
944
945        module.body().append_operation(func::func(
946            &context,
947            StringAttribute::new(&context, "foo"),
948            TypeAttribute::new(FunctionType::new(&context, &[struct_type], &[struct_type]).into()),
949            {
950                let block = Block::new(&[(struct_type, location)]);
951
952                block.append_operation(r#return(Some(block.argument(0).unwrap().into()), location));
953
954                let region = Region::new();
955                region.append_block(block);
956                region
957            },
958            &[],
959            location,
960        ));
961
962        convert_module(&context, &mut module);
963
964        assert!(module.as_operation().verify());
965        insta::assert_snapshot!(module.as_operation());
966    }
967
968    #[test]
969    fn compile_intr_ctlz() {
970        let context = create_test_context();
971
972        let location = Location::unknown(&context);
973        let mut module = Module::new(location);
974        let integer_type = IntegerType::new(&context, 64).into();
975
976        module.body().append_operation(func::func(
977            &context,
978            StringAttribute::new(&context, "foo"),
979            TypeAttribute::new(
980                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
981            ),
982            {
983                let block = Block::new(&[(integer_type, location)]);
984
985                let res = block
986                    .append_operation(intr_ctlz(
987                        &context,
988                        block.argument(0).unwrap().into(),
989                        true,
990                        integer_type,
991                        location,
992                    ))
993                    .result(0)
994                    .unwrap()
995                    .into();
996
997                block.append_operation(func::r#return(&[res], location));
998
999                let region = Region::new();
1000                region.append_block(block);
1001                region
1002            },
1003            &[],
1004            location,
1005        ));
1006
1007        convert_module(&context, &mut module);
1008
1009        assert!(module.as_operation().verify());
1010        insta::assert_snapshot!(module.as_operation());
1011    }
1012
1013    #[test]
1014    fn compile_intr_cttz() {
1015        let context = create_test_context();
1016
1017        let location = Location::unknown(&context);
1018        let mut module = Module::new(location);
1019        let integer_type = IntegerType::new(&context, 64).into();
1020
1021        module.body().append_operation(func::func(
1022            &context,
1023            StringAttribute::new(&context, "foo"),
1024            TypeAttribute::new(
1025                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
1026            ),
1027            {
1028                let block = Block::new(&[(integer_type, location)]);
1029
1030                let res = block
1031                    .append_operation(intr_cttz(
1032                        &context,
1033                        block.argument(0).unwrap().into(),
1034                        true,
1035                        integer_type,
1036                        location,
1037                    ))
1038                    .result(0)
1039                    .unwrap()
1040                    .into();
1041
1042                block.append_operation(func::r#return(&[res], location));
1043
1044                let region = Region::new();
1045                region.append_block(block);
1046                region
1047            },
1048            &[],
1049            location,
1050        ));
1051
1052        convert_module(&context, &mut module);
1053
1054        assert!(module.as_operation().verify());
1055        insta::assert_snapshot!(module.as_operation());
1056    }
1057
1058    #[test]
1059    fn compile_intr_ctpop() {
1060        let context = create_test_context();
1061
1062        let location = Location::unknown(&context);
1063        let mut module = Module::new(location);
1064        let integer_type = IntegerType::new(&context, 64).into();
1065
1066        module.body().append_operation(func::func(
1067            &context,
1068            StringAttribute::new(&context, "foo"),
1069            TypeAttribute::new(
1070                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
1071            ),
1072            {
1073                let block = Block::new(&[(integer_type, location)]);
1074
1075                let res = block
1076                    .append_operation(intr_ctpop(
1077                        block.argument(0).unwrap().into(),
1078                        integer_type,
1079                        location,
1080                    ))
1081                    .result(0)
1082                    .unwrap()
1083                    .into();
1084
1085                block.append_operation(func::r#return(&[res], location));
1086
1087                let region = Region::new();
1088                region.append_block(block);
1089                region
1090            },
1091            &[],
1092            location,
1093        ));
1094
1095        convert_module(&context, &mut module);
1096
1097        assert!(module.as_operation().verify());
1098        insta::assert_snapshot!(module.as_operation());
1099    }
1100
1101    #[test]
1102    fn compile_intr_bswap() {
1103        let context = create_test_context();
1104
1105        let location = Location::unknown(&context);
1106        let mut module = Module::new(location);
1107        let integer_type = IntegerType::new(&context, 64).into();
1108
1109        module.body().append_operation(func::func(
1110            &context,
1111            StringAttribute::new(&context, "foo"),
1112            TypeAttribute::new(
1113                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
1114            ),
1115            {
1116                let block = Block::new(&[(integer_type, location)]);
1117
1118                let res = block
1119                    .append_operation(intr_bswap(
1120                        block.argument(0).unwrap().into(),
1121                        integer_type,
1122                        location,
1123                    ))
1124                    .result(0)
1125                    .unwrap()
1126                    .into();
1127
1128                block.append_operation(func::r#return(&[res], location));
1129
1130                let region = Region::new();
1131                region.append_block(block);
1132                region
1133            },
1134            &[],
1135            location,
1136        ));
1137
1138        convert_module(&context, &mut module);
1139
1140        assert!(module.as_operation().verify());
1141        insta::assert_snapshot!(module.as_operation());
1142    }
1143
1144    #[test]
1145    fn compile_intr_bitreverse() {
1146        let context = create_test_context();
1147
1148        let location = Location::unknown(&context);
1149        let mut module = Module::new(location);
1150        let integer_type = IntegerType::new(&context, 64).into();
1151
1152        module.body().append_operation(func::func(
1153            &context,
1154            StringAttribute::new(&context, "foo"),
1155            TypeAttribute::new(
1156                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
1157            ),
1158            {
1159                let block = Block::new(&[(integer_type, location)]);
1160
1161                let res = block
1162                    .append_operation(intr_bitreverse(
1163                        block.argument(0).unwrap().into(),
1164                        integer_type,
1165                        location,
1166                    ))
1167                    .result(0)
1168                    .unwrap()
1169                    .into();
1170
1171                block.append_operation(func::r#return(&[res], location));
1172
1173                let region = Region::new();
1174                region.append_block(block);
1175                region
1176            },
1177            &[],
1178            location,
1179        ));
1180
1181        convert_module(&context, &mut module);
1182
1183        assert!(module.as_operation().verify());
1184        insta::assert_snapshot!(module.as_operation());
1185    }
1186
1187    #[test]
1188    fn compile_intr_abs() {
1189        let context = create_test_context();
1190
1191        let location = Location::unknown(&context);
1192        let mut module = Module::new(location);
1193        let integer_type = IntegerType::new(&context, 64).into();
1194
1195        module.body().append_operation(func::func(
1196            &context,
1197            StringAttribute::new(&context, "foo"),
1198            TypeAttribute::new(
1199                FunctionType::new(&context, &[integer_type], &[integer_type]).into(),
1200            ),
1201            {
1202                let block = Block::new(&[(integer_type, location)]);
1203
1204                let res = block
1205                    .append_operation(intr_abs(
1206                        &context,
1207                        block.argument(0).unwrap().into(),
1208                        true,
1209                        integer_type,
1210                        location,
1211                    ))
1212                    .result(0)
1213                    .unwrap()
1214                    .into();
1215
1216                block.append_operation(func::r#return(&[res], location));
1217
1218                let region = Region::new();
1219                region.append_block(block);
1220                region
1221            },
1222            &[],
1223            location,
1224        ));
1225
1226        convert_module(&context, &mut module);
1227
1228        assert!(module.as_operation().verify());
1229        insta::assert_snapshot!(module.as_operation());
1230    }
1231
1232    #[test]
1233    fn compile_zext() {
1234        let context = create_test_context();
1235
1236        let location = Location::unknown(&context);
1237        let mut module = Module::new(location);
1238        let integer_type = IntegerType::new(&context, 64).into();
1239        let integer_double_type = IntegerType::new(&context, 128).into();
1240
1241        module.body().append_operation(func::func(
1242            &context,
1243            StringAttribute::new(&context, "foo"),
1244            TypeAttribute::new(
1245                FunctionType::new(&context, &[integer_type], &[integer_double_type]).into(),
1246            ),
1247            {
1248                let block = Block::new(&[(integer_type, location)]);
1249
1250                let res = block
1251                    .append_operation(zext(
1252                        block.argument(0).unwrap().into(),
1253                        integer_double_type,
1254                        location,
1255                    ))
1256                    .result(0)
1257                    .unwrap()
1258                    .into();
1259
1260                block.append_operation(func::r#return(&[res], location));
1261
1262                let region = Region::new();
1263                region.append_block(block);
1264                region
1265            },
1266            &[],
1267            location,
1268        ));
1269
1270        convert_module(&context, &mut module);
1271
1272        assert!(module.as_operation().verify());
1273        insta::assert_snapshot!(module.as_operation());
1274    }
1275}