382 auto app = lam->
body()->as<
App>();
384 if (app->callee() ==
root()->ret_var()) {
385 std::vector<std::string> values;
386 std::vector<const Def*> types;
387 for (
auto arg : app->args()) {
389 values.emplace_back(val);
390 types.emplace_back(arg->type());
394 switch (values.size()) {
395 case 0:
return bb.tail(
"ret void");
396 case 1:
return bb.tail(
"ret {} {}", convert(types[0]), values[0]);
404 auto v_src =
emit(common_src);
405 auto t = convert(common_src->type());
406 return bb.tail(
"ret {} {}", t, v_src);
408 auto [size, elem] = *se;
409 auto val_t = convert(elem);
411 type = std::format(
"<{} x {}>", size, val_t);
412 for (
auto val : values) {
417 prev += std::format(
"{} {}", val_t, val);
422 type = convert(
world().sigma(types));
423 for (
size_t i = 0, n = values.size(); i != n; ++i) {
424 auto v_elem = values[i];
425 auto t_elem = convert(types[i]);
426 auto namei =
"%ret_val." + std::to_string(i);
427 bb.tail(
"{} = insertvalue {} {}, {} {}, {}", namei, type, prev, t_elem, v_elem, i);
431 bb.tail(
"ret {} {}", type, prev);
435 }
else if (
auto dispatch =
Dispatch(app)) {
436 for (
auto callee : dispatch.tuple()->projs([](
const Def* def) { return def->isa_mut<Lam>(); })) {
437 size_t n = callee->num_tvars();
438 if (n == 1 &&
is_simd(callee->var(0)->type())) {
439 auto phi = callee->var(0);
440 auto arg =
emit(app->arg(n, 0));
441 lam2bb_[callee].phis[phi].emplace_back(arg,
id(lam,
true));
444 for (
size_t i = 0; i != n; ++i) {
445 if (
auto arg =
emit_unsafe(app->arg(n, i)); !arg.empty()) {
446 auto phi = callee->var(n, i);
448 lam2bb_[callee].phis[phi].emplace_back(arg,
id(lam,
true));
455 auto v_index =
emit(dispatch.index());
456 size_t n = dispatch.num_targets();
457 auto bbs = absl::FixedArray<std::string>(n);
458 for (
size_t i = 0; i != n; ++i)
459 bbs[i] =
emit(dispatch.target(i));
461 if (
auto branch =
Branch(app))
return bb.tail(
"br i1 {}, label {}, label {}", v_index, bbs[1], bbs[0]);
463 auto t_index = convert(dispatch.index()->type());
464 bb.tail(
"switch {} {}, label {} [ ", t_index, v_index, bbs[0]);
465 for (
size_t i = 1; i != n; ++i)
466 print(bb.tail().back(),
"{} {}, label {} ", t_index, std::to_string(i), bbs[i]);
467 print(bb.tail().back(),
"]");
468 }
else if (app->callee()->isa<
Bot>()) {
469 return bb.tail(
"ret ; bottom: unreachable");
474 auto v_src =
emit(common_src);
475 auto callee_var = callee->var();
476 if (simd_phi_.find(callee) == simd_phi_.end()) simd_phi_[callee] = callee_var;
477 auto key = simd_phi_[callee];
478 lam2bb_[callee].phis[key].emplace_back(v_src,
id(lam,
true));
480 for (
auto var : callee->vars())
484 size_t n = callee->num_tvars();
485 for (
size_t i = 0; i != n; ++i) {
486 if (
auto arg =
emit_unsafe(app->arg(n, i)); !arg.empty()) {
487 auto phi = callee->var(n, i);
489 lam2bb_[callee].phis[phi].emplace_back(arg,
id(lam,
true));
494 return bb.tail(
"br label {}",
id(callee));
497 declare(
"void @longjmp(i8*, i32) noreturn");
499 auto [mem, jbuf, tag] = app->args<3>();
501 auto v_jb =
emit(jbuf);
502 auto v_tag =
emit(tag);
503 bb.tail(
"call void @longjmp(i8* {}, i32 {})", v_jb, v_tag);
504 return bb.tail(
"unreachable");
506 auto v_callee =
emit(app->callee());
508 std::vector<std::string> args;
509 auto app_args = app->args();
510 for (
auto arg : app_args.view().rsubspan(1))
511 if (
auto v_arg =
emit_unsafe(arg); !v_arg.empty()) args.emplace_back(convert(arg->type()) +
" " + v_arg);
513 if (app->args().back()->isa<
Bot>()) {
515 assert(convert_ret_pi(app->callee_type()->ret_pi()) ==
"void");
516 bb.tail(
"call void {}({, })", v_callee, args);
517 return bb.tail(
"unreachable");
520 auto ret_lam = app->args().back()->as_mut<
Lam>();
521 size_t num_vars = ret_lam->
num_vars();
525 for (
auto var : ret_lam->vars()) {
528 types[n] = var->type();
533 bb.tail(
"call void {}({, })", v_callee, args);
535 auto name =
"%" + app->unique_name() +
"ret";
536 auto t_ret = convert_ret_pi(ret_lam->type());
537 bb.tail(
"{} = call {} {}({, })",
name, t_ret, v_callee, args);
538 auto phi = ret_lam->
var();
539 lam2bb_[ret_lam].phis[phi].emplace_back(
name,
id(lam,
true));
543 return bb.tail(
"br label {}",
id(ret_lam));
548 if (
auto lam = def->isa<
Lam>())
return id(lam);
553 auto emit_tuple = [&](
const Def* tuple) {
554 if (isa_mem_sigma_2(tuple->type())) {
556 return emit(tuple->proj(2, 1));
559 if (tuple->is_closed()) {
560 bool is_array = tuple->type()->isa<
Arr>();
561 auto simd_array = convert(tuple->type()).front() ==
'<';
563 s += simd_array ?
"<" : is_array ?
"[" :
"{";
565 for (
size_t i = 0, n = tuple->num_projs(); i != n; ++i) {
566 auto e = tuple->proj(n, i);
567 if (
auto v_elem =
emit_unsafe(e); !v_elem.empty()) {
568 auto t_elem = convert(e->type());
569 s += sep + t_elem +
" " + v_elem;
574 return s += simd_array ?
">" : is_array ?
"]" :
"}";
577 std::string prev =
"undef";
578 auto t = convert(tuple->type());
579 for (
size_t src = 0, dst = 0, n = tuple->num_projs(); src != n; ++src) {
580 auto e = tuple->proj(n, src);
582 auto elem_t = convert(e->type());
584 auto namei =
name +
"." + std::to_string(dst);
585 if (t.front() ==
'<')
586 prev = bb.
assign(namei,
"insertelement {} {}, {} {}, {} {}", t, prev, elem_t, elem, elem_t, dst);
588 prev = bb.
assign(namei,
"insertvalue {} {}, {} {}, {}", t, prev, elem_t, elem, dst);
595 if (def->isa<
Var>()) {
598 if (std::ranges::any_of(ts, [](
auto t) {
return Axm::isa<mem::M>(t); }))
return {};
599 return emit_tuple(def);
602 auto emit_gep_index = [&](
const Def* index) {
603 auto v_i =
emit(index);
604 auto t_i = convert(index->type());
606 if (
auto size =
Idx::isa(index->type())) {
609 "zext {} {} to i{} ; add one more bit for gep index as it is treated as signed value",
611 t_i =
"i" + std::to_string(*w + 1);
615 return std::pair(v_i, t_i);
618 if (
auto lit = def->isa<
Lit>()) {
619 if (lit->type()->isa<
Nat>() ||
Idx::isa(lit->type())) {
620 return std::to_string(lit->get());
621 }
else if (
auto w = math::isa_f(lit->type())) {
627 s <<
"0xH" << std::setfill(
'0') << std::setw(4) << std::right << std::hex << lit->get<
u16>();
630 hex = std::bit_cast<u64>(
f64(lit->get<
f32>()));
633 case 64: hex = lit->get<
u64>();
break;
634 default: fe::unreachable();
637 s <<
"0x" << std::setfill(
'0') << std::setw(16) << std::right << std::hex << hex;
641 }
else if (def->isa<
Bot>()) {
643 }
else if (
auto top = def->isa<
Top>()) {
646 }
else if (
auto tuple = def->isa<
Tuple>()) {
647 return emit_tuple(tuple);
648 }
else if (
auto pack = def->isa<
Pack>()) {
649 if (
auto lit =
Lit::isa(pack->body()); lit && *lit == 0)
return "zeroinitializer";
650 return emit_tuple(pack);
651 }
else if (
auto sel =
Select(def)) {
652 auto t = convert(sel.extract()->type());
653 auto [elem_a, elem_b] = sel.pair()->projs<2>([&](
auto e) {
return emit_unsafe(e); });
654 auto cond_t = convert(sel.cond()->type());
655 auto cond =
emit(sel.cond());
656 return bb.
assign(
name,
"select {} {}, {} {}, {} {}", cond_t, cond, t, elem_b, t, elem_a);
657 }
else if (
auto extract = def->isa<
Extract>()) {
658 auto tuple = extract->tuple();
659 auto index = extract->index();
667 auto t_tup = convert(tuple->type());
669 if (isa_mem_sigma_2(tuple->type()))
return v_tup;
671 auto v_i =
Axm::isa<mem::M>(tuple->proj(0)->type()) ? std::to_string(*li - 1) : std::to_string(*li);
673 return bb.
assign(
name,
"extractvalue {} {}, {}", t_tup, v_tup, v_i);
676 auto t_elem = convert(extract->type());
677 auto [v_i, t_i] = emit_gep_index(index);
680 "{}.alloca = alloca {} ; copy to alloca to emulate extract with store + gep + load",
name, t_tup);
681 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.alloca", t_tup, v_tup, t_tup,
name);
682 print(bb.
body().emplace_back(),
"{}.gep = getelementptr inbounds {}, {}* {}.alloca, i64 0, {} {}",
name, t_tup,
683 t_tup,
name, t_i, v_i);
684 return bb.
assign(
name,
"load {}, {}* {}.gep", t_elem, t_elem,
name);
685 }
else if (
auto insert = def->isa<
Insert>()) {
687 auto t_tup = convert(insert->tuple()->type());
688 auto t_val = convert(insert->value()->type());
689 auto v_tup =
emit(insert->tuple());
690 auto v_val =
emit(insert->value());
691 if (
auto idx =
Lit::isa(insert->index())) {
692 auto v_idx =
emit(insert->index());
693 if (
is_simd(insert->tuple()->type()))
695 return bb.
assign(
name,
"insertelement {} {}, {} {}, i32 {}", t_tup, v_tup, t_val, v_val, v_idx);
698 return bb.
assign(
name,
" insertvalue {} {}, {} {}, {}", t_tup, v_tup, t_val, v_val, v_idx);
700 if (
is_simd(insert->tuple()->type())) {
701 auto v_i =
emit(insert->index());
702 auto t_i = convert(insert->index()->type());
705 v_i = bb.
assign(
name +
".idx",
"{} {} {} to i32", w_src < 32 ?
"zext" :
"trunc", t_i, v_i);
707 return bb.
assign(
name,
"insertelement {} {}, {} {}, i32 {}", t_tup, v_tup, t_val, v_val, v_i);
709 auto t_elem = convert(insert->value()->type());
710 auto [v_i, t_i] = emit_gep_index(insert->index());
712 "{}.alloca = alloca {} ; copy to alloca to emulate insert with store + gep + load",
name, t_tup);
713 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.alloca", t_tup, v_tup, t_tup,
name);
714 print(bb.
body().emplace_back(),
"{}.gep = getelementptr inbounds {}, {}* {}.alloca, i64 0, {} {}",
name,
715 t_tup, t_tup,
name, t_i, v_i);
716 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.gep", t_val, v_val, t_val,
name);
717 return bb.
assign(
name,
"load {}, {}* {}.alloca", t_tup, t_tup,
name);
719 }
else if (
auto global = def->isa<
Global>()) {
720 auto v_init =
emit(global->init());
722 print(vars_decls_,
"{} = global {} {}\n",
name, convert(pointee), v_init);
725 auto [a, b] = nat->args<2>([
this](
auto def) {
return emit(def); });
728 case core::nat::add: op =
"add";
break;
729 case core::nat::sub: op =
"sub";
break;
730 case core::nat::mul: op =
"mul";
break;
733 return bb.
assign(
name,
"{} nsw nuw i64 {}, {}", op, a, b);
735 auto [a, b] = ncmp->args<2>([
this](
auto def) {
return emit(def); });
740 case core::ncmp::e: op +=
"eq" ;
break;
741 case core::ncmp::ne: op +=
"ne" ;
break;
742 case core::ncmp::g: op +=
"ugt";
break;
743 case core::ncmp::ge: op +=
"uge";
break;
744 case core::ncmp::l: op +=
"ult";
break;
745 case core::ncmp::le: op +=
"ule";
break;
747 default: fe::unreachable();
750 return bb.
assign(
name,
"{} i64 {}, {}", op, a, b);
752 auto x =
emit(idx->arg());
754 auto t = convert(idx->type());
755 if (s < 64)
return bb.
assign(
name,
"trunc i64 {} to {}", x, t);
758 assert(bit1.id() == core::bit1::neg);
759 auto x =
emit(bit1->arg());
760 auto t = convert(bit1->type());
761 return bb.
assign(
name,
"xor {} -1, {}", t, x);
763 auto [a, b] = bit2->args<2>([
this](
auto def) {
return emit(def); });
764 auto t = convert(bit2->type());
766 auto neg = [&](std::string_view x) {
return bb.
assign(
name +
".neg",
"xor {} -1, {}", t, x); };
770 case core::bit2::and_:
return bb.
assign(
name,
"and {} {}, {}", t, a, b);
771 case core::bit2:: or_:
return bb.
assign(
name,
"or {} {}, {}", t, a, b);
772 case core::bit2::xor_:
return bb.
assign(
name,
"xor {} {}, {}", t, a, b);
773 case core::bit2::nand:
return neg(bb.
assign(
name,
"and {} {}, {}", t, a, b));
774 case core::bit2:: nor:
return neg(bb.
assign(
name,
"or {} {}, {}", t, a, b));
775 case core::bit2::nxor:
return neg(bb.
assign(
name,
"xor {} {}, {}", t, a, b));
776 case core::bit2:: iff:
return bb.
assign(
name,
"and {} {}, {}", neg(a), b);
777 case core::bit2::niff:
return bb.
assign(
name,
"or {} {}, {}", neg(a), b);
779 default: fe::unreachable();
782 auto [a, b] = shr->args<2>([
this](
auto def) {
return emit(def); });
783 auto t = convert(shr->type());
786 case core::shr::a: op =
"ashr";
break;
787 case core::shr::l: op =
"lshr";
break;
790 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
792 auto [mode, ab] = wrap->uncurry_args<2>();
793 auto [a, b] = ab->projs<2>([
this](
auto def) {
return emit(def); });
794 auto t = convert(wrap->type());
798 case core::wrap::add: op =
"add";
break;
799 case core::wrap::sub: op =
"sub";
break;
800 case core::wrap::mul: op =
"mul";
break;
801 case core::wrap::shl: op =
"shl";
break;
804 if (lmode & core::Mode::nuw) op +=
" nuw";
805 if (lmode & core::Mode::nsw) op +=
" nsw";
807 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
809 auto [m, xy] = div->args<2>();
810 auto [x, y] = xy->projs<2>();
811 auto t = convert(x->type());
817 case core::div::sdiv: op =
"sdiv";
break;
818 case core::div::udiv: op =
"udiv";
break;
819 case core::div::srem: op =
"srem";
break;
820 case core::div::urem: op =
"urem";
break;
823 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
825 auto [a, b] = icmp->args<2>([
this](
auto def) {
return emit(def); });
826 auto t = convert(icmp->arg(0)->type());
831 case core::icmp::e: op +=
"eq" ;
break;
832 case core::icmp::ne: op +=
"ne" ;
break;
833 case core::icmp::sg: op +=
"sgt";
break;
834 case core::icmp::sge: op +=
"sge";
break;
835 case core::icmp::sl: op +=
"slt";
break;
836 case core::icmp::sle: op +=
"sle";
break;
837 case core::icmp::ug: op +=
"ugt";
break;
838 case core::icmp::uge: op +=
"uge";
break;
839 case core::icmp::ul: op +=
"ult";
break;
840 case core::icmp::ule: op +=
"ule";
break;
842 default: fe::unreachable();
845 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
847 auto [x, y] = extr->args<2>();
848 auto t = convert(x->type());
851 std::string f =
"llvm.";
853 case core::extrema::Sm: f +=
"smin.";
break;
854 case core::extrema::SM: f +=
"smax.";
break;
855 case core::extrema::sm: f +=
"umin.";
break;
856 case core::extrema::sM: f +=
"umax.";
break;
859 declare(
"{} @{}({}, {})", t, f, t, t);
860 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
862 auto [m, x] = abs->args<2>();
863 auto t = convert(x->type());
865 std::string f =
"llvm.abs." + t;
866 declare(
"{} @{}({}, {})", t, f, t,
"i1");
867 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a,
"i1",
"1");
869 auto v_src =
emit(conv->arg());
870 auto t_src = convert(conv->arg()->type());
871 auto t_dst = convert(conv->type());
876 if (w_src == w_dst)
return v_src;
879 case core::conv::s: op = w_src < w_dst ?
"sext" :
"trunc";
break;
880 case core::conv::u: op = w_src < w_dst ?
"zext" :
"trunc";
break;
883 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
888 auto t_src = convert(
bitcast->arg()->type());
889 auto t_dst = convert(
bitcast->type());
891 if (
auto lit =
Lit::isa(
bitcast->arg()); lit && *lit == 0)
return "zeroinitializer";
893 if (src_type_ptr && dst_type_ptr)
return bb.
assign(
name,
"bitcast {} {} to {}", t_src, v_src, t_dst);
894 if (src_type_ptr)
return bb.
assign(
name,
"ptrtoint {} {} to {}", t_src, v_src, t_dst);
895 if (dst_type_ptr)
return bb.
assign(
name,
"inttoptr {} {} to {}", t_src, v_src, t_dst);
898 auto size2width = [&](
const Def* type) {
899 if (type->isa<
Nat>())
return 64_n;
904 auto src_size = size2width(
bitcast->arg()->type());
905 auto dst_size = size2width(
bitcast->type());
908 if (src_size && dst_size) {
909 if (src_size == dst_size)
return v_src;
910 op = (src_size < dst_size) ?
"zext" :
"trunc";
912 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
914 auto [ptr, i] = lea->args<2>();
916 auto v_ptr =
emit(ptr);
917 auto t_pointee = convert(pointee);
918 auto t_ptr = convert(ptr->type());
919 if (pointee->isa<
Sigma>())
920 return bb.
assign(
name,
"getelementptr inbounds {}, {} {}, i64 0, i32 {}", t_pointee, t_ptr, v_ptr,
923 assert(pointee->isa<
Arr>());
924 auto [v_i, t_i] = emit_gep_index(i);
926 return bb.
assign(
name,
"getelementptr inbounds {}, {} {}, i64 0, {} {}", t_pointee, t_ptr, v_ptr, t_i, v_i);
931 auto size =
emit(malloc->arg(1));
933 bb.
assign(
name +
"i8",
"call i8* @malloc(i64 {})", size);
934 return bb.
assign(
name,
"bitcast i8* {} to {}",
name +
"i8", ptr_t);
938 auto ptr =
emit(free->arg(1));
941 bb.
assign(
name +
"i8",
"bitcast {} {} to i8*", ptr_t, ptr);
942 bb.
tail(
"call void @free(i8* {})",
name +
"i8");
945 auto [Ta, msi] = mslot->uncurry_args<2>();
946 auto [pointee, addr_space] = Ta->projs<2>();
947 auto [mem, _, __] = msi->projs<3>();
951 print(bb.
body().emplace_back(),
"{} = alloca {}",
name, convert(pointee,
false));
955 auto v_ptr =
emit(load->arg(1));
956 auto t_ptr = convert(load->arg(1)->type());
957 auto t_pointee = convert(
Axm::as<mem::Ptr>(load->arg(1)->type())->arg(0),
false);
958 return bb.
assign(
name,
"load {}, {} {}", t_pointee, t_ptr, v_ptr);
961 auto v_ptr =
emit(store->arg(1));
962 auto v_val =
emit(store->arg(2));
963 auto t_ptr = convert(store->arg(1)->type());
964 auto t_val = convert(store->arg(2)->type(),
false);
965 print(bb.
body().emplace_back(),
"store {} {}, {} {}", t_val, v_val, t_ptr, v_ptr);
971 auto size =
name +
".size";
972 bb.
assign(size,
"call i64 @jmpbuf_size()");
973 return bb.
assign(
name,
"alloca i8, i64 {}", size);
975 declare(
"i32 @_setjmp(i8*) returns_twice");
977 auto [mem, jmpbuf] = setjmp->arg()->projs<2>();
979 auto v_jb =
emit(jmpbuf);
980 return bb.
assign(
name,
"call i32 @_setjmp(i8* {})", v_jb);
982 auto [mode, ab] = arith->uncurry_args<2>();
983 auto [a, b] = ab->projs<2>([
this](
auto def) {
return emit(def); });
984 auto t = convert(arith->type());
987 switch (arith.id()) {
988 case math::arith::add: op =
"fadd";
break;
989 case math::arith::sub: op =
"fsub";
break;
990 case math::arith::mul: op =
"fmul";
break;
991 case math::arith::div: op =
"fdiv";
break;
992 case math::arith::rem: op =
"frem";
break;
995 if (lmode == math::Mode::fast)
999 if (lmode & math::Mode::nnan ) op +=
" nnan";
1000 if (lmode & math::Mode::ninf ) op +=
" ninf";
1001 if (lmode & math::Mode::nsz ) op +=
" nsz";
1002 if (lmode & math::Mode::arcp ) op +=
" arcp";
1003 if (lmode & math::Mode::contract) op +=
" contract";
1004 if (lmode & math::Mode::afn ) op +=
" afn";
1005 if (lmode & math::Mode::reassoc ) op +=
" reassoc";
1009 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
1011 auto a =
emit(tri->arg());
1012 auto t = convert(tri->type());
1016 if (tri.id() == math::tri::sin) {
1017 f = std::string(
"llvm.sin") + llvm_suffix(tri->type());
1018 }
else if (tri.id() == math::tri::cos) {
1019 f = std::string(
"llvm.cos") + llvm_suffix(tri->type());
1021 if (tri.sub() &
sub_t(math::tri::a)) f +=
"a";
1024 case math::tri::sin: f +=
"sin";
break;
1025 case math::tri::cos: f +=
"cos";
break;
1026 case math::tri::tan: f +=
"tan";
break;
1027 case math::tri::ahFF:
error(
"this axm is supposed to be unused");
1028 default: fe::unreachable();
1031 if (tri.sub() &
sub_t(math::tri::h)) f +=
"h";
1032 f += math_suffix(tri->type());
1035 declare(
"{} @{}({})", t, f, t);
1036 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1038 auto [a, b] = extrema->args<2>([
this](
auto def) {
return emit(def); });
1039 auto t = convert(extrema->type());
1040 std::string f =
"llvm.";
1041 switch (extrema.id()) {
1042 case math::extrema::fmin: f +=
"minnum";
break;
1043 case math::extrema::fmax: f +=
"maxnum";
break;
1044 case math::extrema::ieee754min: f +=
"minimum";
break;
1045 case math::extrema::ieee754max: f +=
"maximum";
break;
1047 f += llvm_suffix(extrema->type());
1049 declare(
"{} @{}({}, {})", t, f, t, t);
1050 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
1052 auto [a, b] = pow->args<2>([
this](
auto def) {
return emit(def); });
1053 auto t = convert(pow->type());
1054 std::string f =
"llvm.pow";
1055 f += llvm_suffix(pow->type());
1056 declare(
"{} @{}({}, {})", t, f, t, t);
1057 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
1059 auto a =
emit(rt->arg());
1060 auto t = convert(rt->type());
1062 if (rt.id() == math::rt::sq)
1063 f = std::string(
"llvm.sqrt") + llvm_suffix(rt->type());
1065 f = std::string(
"cbrt") += math_suffix(rt->type());
1066 declare(
"{} @{}({})", t, f, t);
1067 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1069 auto a =
emit(exp->arg());
1070 auto t = convert(exp->type());
1071 std::string f =
"llvm.";
1072 f += (exp.sub() &
sub_t(math::exp::log)) ?
"log" :
"exp";
1073 f += (exp.sub() &
sub_t(math::exp::bin)) ?
"2" : (exp.sub() &
sub_t(math::exp::dec)) ?
"10" :
"";
1074 f += llvm_suffix(exp->type());
1076 declare(
"{} @{}({})", t, f, t);
1077 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1079 auto a =
emit(er->arg());
1080 auto t = convert(er->type());
1081 auto f = er.id() == math::er::f ? std::string(
"erf") : std::string(
"erfc");
1082 f += math_suffix(er->type());
1083 declare(
"{} @{}({})", t, f, t);
1084 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1086 auto a =
emit(gamma->arg());
1087 auto t = convert(gamma->type());
1088 std::string f = gamma.id() == math::gamma::t ?
"tgamma" :
"lgamma";
1089 f += math_suffix(gamma->type());
1090 declare(
"{} @{}({})", t, f, t);
1091 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1093 auto [a, b] = cmp->args<2>([
this](
auto def) {
return emit(def); });
1094 auto t = convert(cmp->arg(0)->type());
1099 case math::cmp:: e: op +=
"oeq";
break;
1100 case math::cmp:: l: op +=
"olt";
break;
1101 case math::cmp:: le: op +=
"ole";
break;
1102 case math::cmp:: g: op +=
"ogt";
break;
1103 case math::cmp:: ge: op +=
"oge";
break;
1104 case math::cmp:: ne: op +=
"one";
break;
1105 case math::cmp:: o: op +=
"ord";
break;
1106 case math::cmp:: u: op +=
"uno";
break;
1107 case math::cmp:: ue: op +=
"ueq";
break;
1108 case math::cmp:: ul: op +=
"ult";
break;
1109 case math::cmp::ule: op +=
"ule";
break;
1110 case math::cmp:: ug: op +=
"ugt";
break;
1111 case math::cmp::uge: op +=
"uge";
break;
1112 case math::cmp::une: op +=
"une";
break;
1114 default: fe::unreachable();
1117 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
1119 auto v_src =
emit(conv->arg());
1120 auto t_src = convert(conv->arg()->type());
1121 auto t_dst = convert(conv->type());
1123 auto s_src = math::isa_f(conv->arg()->type());
1124 auto s_dst = math::isa_f(conv->type());
1126 switch (conv.id()) {
1127 case math::conv::f2f: op = s_src < s_dst ?
"fpext" :
"fptrunc";
break;
1128 case math::conv::s2f: op =
"sitofp";
break;
1129 case math::conv::u2f: op =
"uitofp";
break;
1130 case math::conv::f2s: op =
"fptosi";
break;
1131 case math::conv::f2u: op =
"fptoui";
break;
1134 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
1136 auto a =
emit(abs->arg());
1137 auto t = convert(abs->type());
1138 std::string f =
"llvm.fabs";
1139 f += llvm_suffix(abs->type());
1140 declare(
"{} @{}({})", t, f, t);
1141 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1143 auto a =
emit(round->arg());
1144 auto t = convert(round->type());
1145 std::string f =
"llvm.";
1146 switch (round.id()) {
1147 case math::round::f: f +=
"floor";
break;
1148 case math::round::c: f +=
"ceil";
break;
1149 case math::round::r: f +=
"round";
break;
1150 case math::round::t: f +=
"trunc";
break;
1152 f += llvm_suffix(round->type());
1153 declare(
"{} @{}({})", t, f, t);
1154 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1156 auto ni_n = zip->decurry()->decurry()->decurry()->arg();
1157 auto nat_ni = *
Lit::isa(ni_n->proj(2, 0));
1158 auto f = zip->decurry()->arg();
1159 auto inputs = zip->arg();
1160 auto t_in = convert(inputs->proj(nat_ni, 0)->type());
1161 auto t_out = convert(def->
type());
1167 switch (nat_op.id()) {
1168 case core::nat::add: op =
"add nuw nsw";
break;
1169 case core::nat::sub: op =
"sub nuw nsw";
break;
1170 case core::nat::mul: op =
"mul nuw nsw";
break;
1174 switch (arith_op.id()) {
1175 case math::arith::add: op =
"fadd";
break;
1176 case math::arith::sub: op =
"fsub";
break;
1177 case math::arith::mul: op =
"fmul";
break;
1178 case math::arith::div: op =
"fdiv";
break;
1179 case math::arith::rem: op =
"frem";
break;
1182 if (lmode == math::Mode::fast)
1185 if (lmode & math::Mode::nnan) op +=
" nnan";
1186 if (lmode & math::Mode::ninf) op +=
" ninf";
1187 if (lmode & math::Mode::nsz) op +=
" nsz";
1188 if (lmode & math::Mode::arcp) op +=
" arcp";
1189 if (lmode & math::Mode::contract) op +=
" contract";
1190 if (lmode & math::Mode::afn) op +=
" afn";
1191 if (lmode & math::Mode::reassoc) op +=
" reassoc";
1195 switch (ncmp_op.id()) {
1196 case core::ncmp::e: op +=
"eq";
break;
1197 case core::ncmp::ne: op +=
"ne";
break;
1198 case core::ncmp::g: op +=
"ugt";
break;
1199 case core::ncmp::ge: op +=
"uge";
break;
1200 case core::ncmp::l: op +=
"ult";
break;
1201 case core::ncmp::le: op +=
"ule";
break;
1202 default: fe::unreachable();
1206 switch (icmp_op.id()) {
1207 case core::icmp::e: op +=
"eq";
break;
1208 case core::icmp::ne: op +=
"ne";
break;
1209 case core::icmp::sg: op +=
"sgt";
break;
1210 case core::icmp::sge: op +=
"sge";
break;
1211 case core::icmp::sl: op +=
"slt";
break;
1212 case core::icmp::sle: op +=
"sle";
break;
1213 case core::icmp::ug: op +=
"ugt";
break;
1214 case core::icmp::uge: op +=
"uge";
break;
1215 case core::icmp::ul: op +=
"ult";
break;
1216 case core::icmp::ule: op +=
"ule";
break;
1217 default: fe::unreachable();
1221 switch (mcmp_op.id()) {
1222 case math::cmp::e: op +=
"oeq";
break;
1223 case math::cmp::l: op +=
"olt";
break;
1224 case math::cmp::le: op +=
"ole";
break;
1225 case math::cmp::g: op +=
"ogt";
break;
1226 case math::cmp::ge: op +=
"oge";
break;
1227 case math::cmp::ne: op +=
"one";
break;
1228 case math::cmp::o: op +=
"ord";
break;
1229 case math::cmp::u: op +=
"uno";
break;
1230 case math::cmp::ue: op +=
"ueq";
break;
1231 case math::cmp::ul: op +=
"ult";
break;
1232 case math::cmp::ule: op +=
"ule";
break;
1233 case math::cmp::ug: op +=
"ugt";
break;
1234 case math::cmp::uge: op +=
"uge";
break;
1235 case math::cmp::une: op +=
"une";
break;
1236 default: fe::unreachable();
1239 error(
"unhandled vec.zip operation: {}", f);
1242 auto v1 =
emit(inputs->proj(nat_ni, 0));
1243 auto v2 =
emit(inputs->proj(nat_ni, 1));
1244 prev = bb.
assign(
name,
"{} {} {}, {}", op, t_in, v1, v2);
1249 error(
"unhandled def in LLVM backend: {} : {}", def, def->
type());