315 auto app = lam->
body()->as<
App>();
318 if (app->callee() ==
root()->ret_var()) {
319 std::vector<std::string> values;
320 std::vector<const Def*> types;
322 for (
auto arg : app->args()) {
324 values.emplace_back(val);
325 types.emplace_back(arg->type());
329 switch (values.size()) {
330 case 0:
return bb.tail(
"ret void");
331 case 1:
return bb.tail(
"ret {} {}", convert(types[0]), values[0]);
333 std::string prev =
"undef";
334 auto type = convert(
world().sigma(types));
335 for (
size_t i = 0, n = values.size(); i != n; ++i) {
336 auto v_elem = values[i];
337 auto t_elem = convert(types[i]);
338 auto namei =
"%ret_val." + std::to_string(i);
339 bb.tail(
"{} = insertvalue {} {}, {} {}, {}", namei, type, prev, t_elem, v_elem, i);
343 bb.tail(
"ret {} {}", type, prev);
350 for (
auto callee_def : ex->tuple()->projs()) {
352 auto callee = callee_def->as_mut<
Lam>();
356 assert(callee->num_tvars() == app->num_targs());
357 size_t n = callee->num_tvars();
358 for (
size_t i = 0; i != n; ++i) {
360 if (
auto arg =
emit_unsafe(app->arg(n, i)); !arg.empty()) {
361 auto phi = callee->var(n, i);
363 lam2bb_[callee].phis[phi].emplace_back(arg,
id(lam,
true));
369 auto c =
emit(ex->index());
370 if (ex->tuple()->num_projs() == 2) {
371 auto [f, t] = ex->tuple()->projs<2>([
this](
auto def) {
return emit(def); });
372 return bb.tail(
"br i1 {}, label {}, label {}", c, t, f);
374 auto t_c = convert(ex->index()->type());
375 bb.tail(
"switch {} {}, label {} [ ", t_c, c,
emit(ex->tuple()->proj(0)));
376 for (
auto i = 1u; i < ex->tuple()->num_projs(); i++)
377 print(bb.tail().back(),
"{} {}, label {} ", t_c, std::to_string(i),
emit(ex->tuple()->proj(i)));
378 print(bb.tail().back(),
"]");
380 }
else if (app->callee()->isa<
Bot>()) {
381 return bb.tail(
"ret ; bottom: unreachable");
383 size_t n = callee->num_tvars();
384 for (
size_t i = 0; i != n; ++i) {
385 if (
auto arg =
emit_unsafe(app->arg(n, i)); !arg.empty()) {
386 auto phi = callee->var(n, i);
388 lam2bb_[callee].phis[phi].emplace_back(arg,
id(lam,
true));
392 return bb.tail(
"br label {}",
id(callee));
394 declare(
"void @longjmp(i8*, i32) noreturn");
396 auto [mem, jbuf, tag] = app->args<3>();
398 auto v_jb =
emit(jbuf);
399 auto v_tag =
emit(tag);
400 bb.tail(
"call void @longjmp(i8* {}, i32 {})", v_jb, v_tag);
401 return bb.tail(
"unreachable");
403 auto v_callee =
emit(app->callee());
405 std::vector<std::string> args;
406 auto app_args = app->args();
407 for (
auto arg : app_args.view().rsubspan(1))
408 if (
auto v_arg =
emit_unsafe(arg); !v_arg.empty()) args.emplace_back(convert(arg->type()) +
" " + v_arg);
410 if (app->args().back()->isa<
Bot>()) {
412 assert(convert_ret_pi(app->callee_type()->ret_pi()) ==
"void");
413 bb.tail(
"call void {}({, })", v_callee, args);
414 return bb.tail(
"unreachable");
417 auto ret_lam = app->args().back()->as_mut<
Lam>();
418 size_t num_vars = ret_lam->
num_vars();
422 for (
auto var : ret_lam->vars()) {
425 types[n] = var->type();
430 bb.tail(
"call void {}({, })", v_callee, args);
432 auto name =
"%" + app->unique_name() +
"ret";
433 auto t_ret = convert_ret_pi(ret_lam->type());
434 bb.tail(
"{} = call {} {}({, })",
name, t_ret, v_callee, args);
436 for (
size_t i = 0, e = ret_lam->num_vars(); i != e; ++i) {
437 auto phi = ret_lam->var(i);
442 namei +=
'.' + std::to_string(i - 1);
443 bb.tail(
"{} = extractvalue {} {}, {}", namei, t_ret,
name, i - 1);
446 lam2bb_[ret_lam].phis[phi].emplace_back(namei,
id(lam,
true));
451 return bb.tail(
"br label {}",
id(ret_lam));
456 if (
auto lam = def->isa<
Lam>())
return id(lam);
461 auto emit_tuple = [&](
const Def* tuple) {
462 if (isa_mem_sigma_2(tuple->type())) {
464 return emit(tuple->proj(2, 1));
467 if (is_const(tuple)) {
468 bool is_array = tuple->type()->isa<
Arr>();
471 s += is_array ?
"[" :
"{";
473 for (
size_t i = 0, n = tuple->num_projs(); i != n; ++i) {
474 auto e = tuple->proj(n, i);
475 if (
auto v_elem =
emit_unsafe(e); !v_elem.empty()) {
476 auto t_elem = convert(e->type());
477 s += sep + t_elem +
" " + v_elem;
482 return s += is_array ?
"]" :
"}";
485 std::string prev =
"undef";
486 auto t = convert(tuple->type());
487 for (
size_t src = 0, dst = 0, n = tuple->num_projs(); src != n; ++src) {
488 auto e = tuple->proj(n, src);
490 auto elem_t = convert(e->type());
492 auto namei =
name +
"." + std::to_string(dst);
493 prev = bb.
assign(namei,
"insertvalue {} {}, {} {}, {}", t, prev, elem_t, elem, dst);
500 if (def->isa<
Var>()) {
502 if (std::ranges::any_of(ts, [](
auto t) {
return Axm::isa<mem::M>(t); }))
return {};
503 return emit_tuple(def);
506 auto emit_gep_index = [&](
const Def* index) {
507 auto v_i =
emit(index);
508 auto t_i = convert(index->type());
510 if (
auto size =
Idx::isa(index->type())) {
513 "zext {} {} to i{} ; add one more bit for gep index as it is treated as signed value",
515 t_i =
"i" + std::to_string(*w + 1);
519 return std::pair(v_i, t_i);
522 if (
auto lit = def->isa<
Lit>()) {
523 if (lit->type()->isa<
Nat>() ||
Idx::isa(lit->type())) {
524 return std::to_string(lit->get());
525 }
else if (
auto w = math::isa_f(lit->type())) {
531 s <<
"0xH" << std::setfill(
'0') << std::setw(4) << std::right << std::hex << lit->get<
u16>();
534 hex = std::bit_cast<u64>(
f64(lit->get<
f32>()));
537 case 64: hex = lit->get<
u64>();
break;
538 default: fe::unreachable();
541 s <<
"0x" << std::setfill(
'0') << std::setw(16) << std::right << std::hex << hex;
545 }
else if (def->isa<
Bot>()) {
547 }
else if (
auto top = def->isa<
Top>()) {
550 }
else if (
auto tuple = def->isa<
Tuple>()) {
551 return emit_tuple(tuple);
552 }
else if (
auto pack = def->isa<
Pack>()) {
553 if (
auto lit =
Lit::isa(pack->body()); lit && *lit == 0)
return "zeroinitializer";
554 return emit_tuple(pack);
555 }
else if (
auto extract = def->isa<
Extract>()) {
556 auto tuple = extract->tuple();
557 auto index = extract->index();
562 if (
auto app = extract->type()->isa<
App>();
564 if (
auto arity =
Lit::isa(tuple->type()->arity()); arity && *arity == 2) {
565 auto t = convert(extract->type());
566 auto [elem_a, elem_b] = tuple->projs<2>([&](
auto e) {
return emit_unsafe(e); });
568 return bb.
assign(
name,
"select {} {}, {} {}, {} {}", convert(index->type()),
emit(index), t, elem_b, t,
579 auto t_tup = convert(tuple->type());
581 if (isa_mem_sigma_2(tuple->type()))
return v_tup;
583 auto v_i =
Axm::isa<mem::M>(tuple->proj(0)->type()) ? std::to_string(*li - 1) : std::to_string(*li);
584 return bb.
assign(
name,
"extractvalue {} {}, {}", t_tup, v_tup, v_i);
587 auto t_elem = convert(extract->type());
588 auto [v_i, t_i] = emit_gep_index(index);
591 "{}.alloca = alloca {} ; copy to alloca to emulate extract with store + gep + load",
name, t_tup);
592 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.alloca", t_tup, v_tup, t_tup,
name);
593 print(bb.
body().emplace_back(),
"{}.gep = getelementptr inbounds {}, {}* {}.alloca, i64 0, {} {}",
name, t_tup,
594 t_tup,
name, t_i, v_i);
595 return bb.
assign(
name,
"load {}, {}* {}.gep", t_elem, t_elem,
name);
596 }
else if (
auto insert = def->isa<
Insert>()) {
598 auto t_tup = convert(insert->tuple()->type());
599 auto t_val = convert(insert->value()->type());
600 auto v_tup =
emit(insert->tuple());
601 auto v_val =
emit(insert->value());
602 if (
auto idx =
Lit::isa(insert->index())) {
603 auto v_idx =
emit(insert->index());
604 return bb.
assign(
name,
"insertvalue {} {}, {} {}, {}", t_tup, v_tup, t_val, v_val, v_idx);
606 auto t_elem = convert(insert->value()->type());
607 auto [v_i, t_i] = emit_gep_index(insert->index());
609 "{}.alloca = alloca {} ; copy to alloca to emulate insert with store + gep + load",
name, t_tup);
610 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.alloca", t_tup, v_tup, t_tup,
name);
611 print(bb.
body().emplace_back(),
"{}.gep = getelementptr inbounds {}, {}* {}.alloca, i64 0, {} {}",
name,
612 t_tup, t_tup,
name, t_i, v_i);
613 print(bb.
body().emplace_back(),
"store {} {}, {}* {}.gep", t_val, v_val, t_val,
name);
614 return bb.
assign(
name,
"load {}, {}* {}.alloca", t_tup, t_tup,
name);
616 }
else if (
auto global = def->isa<
Global>()) {
617 auto v_init =
emit(global->init());
619 print(vars_decls_,
"{} = global {} {}\n",
name, convert(pointee), v_init);
622 auto [a, b] = nat->args<2>([
this](
auto def) {
return emit(def); });
625 case core::nat::add: op =
"add";
break;
626 case core::nat::sub: op =
"sub";
break;
627 case core::nat::mul: op =
"mul";
break;
630 return bb.
assign(
name,
"{} nsw nuw i64 {}, {}", op, a, b);
632 auto [a, b] = ncmp->args<2>([
this](
auto def) {
return emit(def); });
637 case core::ncmp::e: op +=
"eq" ;
break;
638 case core::ncmp::ne: op +=
"ne" ;
break;
639 case core::ncmp::g: op +=
"ugt";
break;
640 case core::ncmp::ge: op +=
"uge";
break;
641 case core::ncmp::l: op +=
"ult";
break;
642 case core::ncmp::le: op +=
"ule";
break;
644 default: fe::unreachable();
647 return bb.
assign(
name,
"{} i64 {}, {}", op, a, b);
649 auto x =
emit(idx->arg());
651 auto t = convert(idx->type());
652 if (s < 64)
return bb.
assign(
name,
"trunc i64 {} to {}", x, t);
655 assert(bit1.id() == core::bit1::neg);
656 auto x =
emit(bit1->arg());
657 auto t = convert(bit1->type());
658 return bb.
assign(
name,
"xor {} -1, {}", t, x);
660 auto [a, b] = bit2->args<2>([
this](
auto def) {
return emit(def); });
661 auto t = convert(bit2->type());
663 auto neg = [&](std::string_view x) {
return bb.
assign(
name +
".neg",
"xor {} -1, {}", t, x); };
667 case core::bit2::and_:
return bb.
assign(
name,
"and {} {}, {}", t, a, b);
668 case core::bit2:: or_:
return bb.
assign(
name,
"or {} {}, {}", t, a, b);
669 case core::bit2::xor_:
return bb.
assign(
name,
"xor {} {}, {}", t, a, b);
670 case core::bit2::nand:
return neg(bb.
assign(
name,
"and {} {}, {}", t, a, b));
671 case core::bit2:: nor:
return neg(bb.
assign(
name,
"or {} {}, {}", t, a, b));
672 case core::bit2::nxor:
return neg(bb.
assign(
name,
"xor {} {}, {}", t, a, b));
673 case core::bit2:: iff:
return bb.
assign(
name,
"and {} {}, {}", neg(a), b);
674 case core::bit2::niff:
return bb.
assign(
name,
"or {} {}, {}", neg(a), b);
676 default: fe::unreachable();
679 auto [a, b] = shr->args<2>([
this](
auto def) {
return emit(def); });
680 auto t = convert(shr->type());
683 case core::shr::a: op =
"ashr";
break;
684 case core::shr::l: op =
"lshr";
break;
687 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
689 auto [mode, ab] = wrap->uncurry_args<2>();
690 auto [a, b] = ab->projs<2>([
this](
auto def) {
return emit(def); });
691 auto t = convert(wrap->type());
695 case core::wrap::add: op =
"add";
break;
696 case core::wrap::sub: op =
"sub";
break;
697 case core::wrap::mul: op =
"mul";
break;
698 case core::wrap::shl: op =
"shl";
break;
701 if (lmode & core::Mode::nuw) op +=
" nuw";
702 if (lmode & core::Mode::nsw) op +=
" nsw";
704 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
706 auto [m, xy] = div->args<2>();
707 auto [x, y] = xy->projs<2>();
708 auto t = convert(x->type());
714 case core::div::sdiv: op =
"sdiv";
break;
715 case core::div::udiv: op =
"udiv";
break;
716 case core::div::srem: op =
"srem";
break;
717 case core::div::urem: op =
"urem";
break;
720 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
722 auto [a, b] = icmp->args<2>([
this](
auto def) {
return emit(def); });
723 auto t = convert(icmp->arg(0)->type());
728 case core::icmp::e: op +=
"eq" ;
break;
729 case core::icmp::ne: op +=
"ne" ;
break;
730 case core::icmp::sg: op +=
"sgt";
break;
731 case core::icmp::sge: op +=
"sge";
break;
732 case core::icmp::sl: op +=
"slt";
break;
733 case core::icmp::sle: op +=
"sle";
break;
734 case core::icmp::ug: op +=
"ugt";
break;
735 case core::icmp::uge: op +=
"uge";
break;
736 case core::icmp::ul: op +=
"ult";
break;
737 case core::icmp::ule: op +=
"ule";
break;
739 default: fe::unreachable();
742 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
744 auto [x, y] = extr->args<2>();
745 auto t = convert(x->type());
748 std::string f =
"llvm.";
750 case core::extrema::Sm: f +=
"smin.";
break;
751 case core::extrema::SM: f +=
"smax.";
break;
752 case core::extrema::sm: f +=
"umin.";
break;
753 case core::extrema::sM: f +=
"umax.";
break;
756 declare(
"{} @{}({}, {})", t, f, t, t);
757 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
759 auto [m, x] = abs->args<2>();
760 auto t = convert(x->type());
762 std::string f =
"llvm.abs." + t;
763 declare(
"{} @{}({}, {})", t, f, t,
"i1");
764 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a,
"i1",
"1");
766 auto v_src =
emit(conv->arg());
767 auto t_src = convert(conv->arg()->type());
768 auto t_dst = convert(conv->type());
773 if (w_src == w_dst)
return v_src;
776 case core::conv::s: op = w_src < w_dst ?
"sext" :
"trunc";
break;
777 case core::conv::u: op = w_src < w_dst ?
"zext" :
"trunc";
break;
780 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
785 auto t_src = convert(
bitcast->arg()->type());
786 auto t_dst = convert(
bitcast->type());
788 if (
auto lit =
Lit::isa(
bitcast->arg()); lit && *lit == 0)
return "zeroinitializer";
790 if (src_type_ptr && dst_type_ptr)
return bb.
assign(
name,
"bitcast {} {} to {}", t_src, v_src, t_dst);
791 if (src_type_ptr)
return bb.
assign(
name,
"ptrtoint {} {} to {}", t_src, v_src, t_dst);
792 if (dst_type_ptr)
return bb.
assign(
name,
"inttoptr {} {} to {}", t_src, v_src, t_dst);
795 auto size2width = [&](
const Def* type) {
796 if (type->isa<
Nat>())
return 64_n;
801 auto src_size = size2width(
bitcast->arg()->type());
802 auto dst_size = size2width(
bitcast->type());
805 if (src_size && dst_size) {
806 if (src_size == dst_size)
return v_src;
807 op = (src_size < dst_size) ?
"zext" :
"trunc";
809 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
811 auto [ptr, i] = lea->args<2>();
813 auto v_ptr =
emit(ptr);
814 auto t_pointee = convert(pointee);
815 auto t_ptr = convert(ptr->type());
816 if (pointee->isa<
Sigma>())
817 return bb.
assign(
name,
"getelementptr inbounds {}, {} {}, i64 0, i32 {}", t_pointee, t_ptr, v_ptr,
820 assert(pointee->isa<
Arr>());
821 auto [v_i, t_i] = emit_gep_index(i);
823 return bb.
assign(
name,
"getelementptr inbounds {}, {} {}, i64 0, {} {}", t_pointee, t_ptr, v_ptr, t_i, v_i);
828 auto size =
emit(malloc->arg(1));
830 bb.
assign(
name +
"i8",
"call i8* @malloc(i64 {})", size);
831 return bb.
assign(
name,
"bitcast i8* {} to {}",
name +
"i8", ptr_t);
835 auto ptr =
emit(free->arg(1));
838 bb.
assign(
name +
"i8",
"bitcast {} {} to i8*", ptr_t, ptr);
839 bb.
tail(
"call void @free(i8* {})",
name +
"i8");
842 auto [Ta, msi] = mslot->uncurry_args<2>();
843 auto [pointee, addr_space] = Ta->projs<2>();
844 auto [mem, _, __] = msi->projs<3>();
848 print(bb.
body().emplace_back(),
"{} = alloca {}",
name, convert(pointee));
854 auto v_ptr =
emit(free->arg(1));
857 bb.
assign(
name +
"i8",
"bitcast {} {} to i8*", t_ptr, v_ptr);
858 bb.
tail(
"call void @free(i8* {})",
name +
"i8");
862 auto v_ptr =
emit(load->arg(1));
863 auto t_ptr = convert(load->arg(1)->type());
865 return bb.
assign(
name,
"load {}, {} {}", t_pointee, t_ptr, v_ptr);
868 auto v_ptr =
emit(store->arg(1));
869 auto v_val =
emit(store->arg(2));
870 auto t_ptr = convert(store->arg(1)->type());
871 auto t_val = convert(store->arg(2)->type());
872 print(bb.
body().emplace_back(),
"store {} {}, {} {}", t_val, v_val, t_ptr, v_ptr);
878 auto size =
name +
".size";
879 bb.
assign(size,
"call i64 @jmpbuf_size()");
880 return bb.
assign(
name,
"alloca i8, i64 {}", size);
882 declare(
"i32 @_setjmp(i8*) returns_twice");
884 auto [mem, jmpbuf] = setjmp->arg()->projs<2>();
886 auto v_jb =
emit(jmpbuf);
887 return bb.
assign(
name,
"call i32 @_setjmp(i8* {})", v_jb);
889 auto [mode, ab] = arith->uncurry_args<2>();
890 auto [a, b] = ab->projs<2>([
this](
auto def) {
return emit(def); });
891 auto t = convert(arith->type());
894 switch (arith.id()) {
895 case math::arith::add: op =
"fadd";
break;
896 case math::arith::sub: op =
"fsub";
break;
897 case math::arith::mul: op =
"fmul";
break;
898 case math::arith::div: op =
"fdiv";
break;
899 case math::arith::rem: op =
"frem";
break;
902 if (lmode == math::Mode::fast)
906 if (lmode & math::Mode::nnan ) op +=
" nnan";
907 if (lmode & math::Mode::ninf ) op +=
" ninf";
908 if (lmode & math::Mode::nsz ) op +=
" nsz";
909 if (lmode & math::Mode::arcp ) op +=
" arcp";
910 if (lmode & math::Mode::contract) op +=
" contract";
911 if (lmode & math::Mode::afn ) op +=
" afn";
912 if (lmode & math::Mode::reassoc ) op +=
" reassoc";
916 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
918 auto a =
emit(tri->arg());
919 auto t = convert(tri->type());
923 if (tri.id() == math::tri::sin) {
924 f =
"llvm.sin"s + llvm_suffix(tri->type());
925 }
else if (tri.id() == math::tri::cos) {
926 f =
"llvm.cos"s + llvm_suffix(tri->type());
928 if (tri.sub() &
sub_t(math::tri::a)) f +=
"a";
931 case math::tri::sin: f +=
"sin";
break;
932 case math::tri::cos: f +=
"cos";
break;
933 case math::tri::tan: f +=
"tan";
break;
934 case math::tri::ahFF:
error(
"this axm is supposed to be unused");
935 default: fe::unreachable();
938 if (tri.sub() &
sub_t(math::tri::h)) f +=
"h";
939 f += math_suffix(tri->type());
942 declare(
"{} @{}({})", t, f, t);
943 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
945 auto [a, b] = extrema->args<2>([
this](
auto def) {
return emit(def); });
946 auto t = convert(extrema->type());
947 std::string f =
"llvm.";
948 switch (extrema.id()) {
949 case math::extrema::fmin: f +=
"minnum";
break;
950 case math::extrema::fmax: f +=
"maxnum";
break;
951 case math::extrema::ieee754min: f +=
"minimum";
break;
952 case math::extrema::ieee754max: f +=
"maximum";
break;
954 f += llvm_suffix(extrema->type());
956 declare(
"{} @{}({}, {})", t, f, t, t);
957 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
959 auto [a, b] = pow->args<2>([
this](
auto def) {
return emit(def); });
960 auto t = convert(pow->type());
961 std::string f =
"llvm.pow";
962 f += llvm_suffix(pow->type());
963 declare(
"{} @{}({}, {})", t, f, t, t);
964 return bb.
assign(
name,
"tail call {} @{}({} {}, {} {})", t, f, t, a, t, b);
966 auto a =
emit(rt->arg());
967 auto t = convert(rt->type());
969 if (rt.id() == math::rt::sq)
970 f =
"llvm.sqrt"s + llvm_suffix(rt->type());
972 f =
"cbrt"s += math_suffix(rt->type());
973 declare(
"{} @{}({})", t, f, t);
974 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
976 auto a =
emit(exp->arg());
977 auto t = convert(exp->type());
978 std::string f =
"llvm.";
979 f += (exp.sub() &
sub_t(math::exp::log)) ?
"log" :
"exp";
980 f += (exp.sub() &
sub_t(math::exp::bin)) ?
"2" : (exp.sub() &
sub_t(math::exp::dec)) ?
"10" :
"";
981 f += llvm_suffix(exp->type());
983 declare(
"{} @{}({})", t, f, t);
984 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
986 auto a =
emit(er->arg());
987 auto t = convert(er->type());
988 auto f = er.id() == math::er::f ?
"erf"s :
"erfc"s;
989 f += math_suffix(er->type());
990 declare(
"{} @{}({})", t, f, t);
991 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
993 auto a =
emit(gamma->arg());
994 auto t = convert(gamma->type());
995 std::string f = gamma.id() == math::gamma::t ?
"tgamma" :
"lgamma";
996 f += math_suffix(gamma->type());
997 declare(
"{} @{}({})", t, f, t);
998 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1000 auto [a, b] = cmp->args<2>([
this](
auto def) {
return emit(def); });
1001 auto t = convert(cmp->arg(0)->type());
1006 case math::cmp:: e: op +=
"oeq";
break;
1007 case math::cmp:: l: op +=
"olt";
break;
1008 case math::cmp:: le: op +=
"ole";
break;
1009 case math::cmp:: g: op +=
"ogt";
break;
1010 case math::cmp:: ge: op +=
"oge";
break;
1011 case math::cmp:: ne: op +=
"one";
break;
1012 case math::cmp:: o: op +=
"ord";
break;
1013 case math::cmp:: u: op +=
"uno";
break;
1014 case math::cmp:: ue: op +=
"ueq";
break;
1015 case math::cmp:: ul: op +=
"ult";
break;
1016 case math::cmp::ule: op +=
"ule";
break;
1017 case math::cmp:: ug: op +=
"ugt";
break;
1018 case math::cmp::uge: op +=
"uge";
break;
1019 case math::cmp::une: op +=
"une";
break;
1021 default: fe::unreachable();
1024 return bb.
assign(
name,
"{} {} {}, {}", op, t, a, b);
1026 auto v_src =
emit(conv->arg());
1027 auto t_src = convert(conv->arg()->type());
1028 auto t_dst = convert(conv->type());
1030 auto s_src = math::isa_f(conv->arg()->type());
1031 auto s_dst = math::isa_f(conv->type());
1033 switch (conv.id()) {
1034 case math::conv::f2f: op = s_src < s_dst ?
"fpext" :
"fptrunc";
break;
1035 case math::conv::s2f: op =
"sitofp";
break;
1036 case math::conv::u2f: op =
"uitofp";
break;
1037 case math::conv::f2s: op =
"fptosi";
break;
1038 case math::conv::f2u: op =
"fptoui";
break;
1041 return bb.
assign(
name,
"{} {} {} to {}", op, t_src, v_src, t_dst);
1043 auto a =
emit(abs->arg());
1044 auto t = convert(abs->type());
1045 std::string f =
"llvm.fabs";
1046 f += llvm_suffix(abs->type());
1047 declare(
"{} @{}({})", t, f, t);
1048 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1050 auto a =
emit(round->arg());
1051 auto t = convert(round->type());
1052 std::string f =
"llvm.";
1053 switch (round.id()) {
1054 case math::round::f: f +=
"floor";
break;
1055 case math::round::c: f +=
"ceil";
break;
1056 case math::round::r: f +=
"round";
break;
1057 case math::round::t: f +=
"trunc";
break;
1059 f += llvm_suffix(round->type());
1060 declare(
"{} @{}({})", t, f, t);
1061 return bb.
assign(
name,
"tail call {} @{}({} {})", t, f, t, a);
1063 error(
"unhandled def in LLVM backend: {} : {}", def, def->
type());