diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index ee1a384ae..649898bfb 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1691,6 +1691,14 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return res; } + // integer -> boolean + if (is_type_integer(src) && is_type_boolean(dst)) { + lbValue res = {}; + res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); + res.type = t_llvm_bool; + return lb_emit_conv(p, res, t); + } + if (is_type_cstring(src) && is_type_u8_ptr(dst)) { return lb_emit_transmute(p, value, dst); } @@ -1721,14 +1729,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } - // integer -> boolean - if (is_type_integer(src) && is_type_boolean(dst)) { - lbValue res = {}; - res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); - res.type = t_llvm_bool; - return lb_emit_conv(p, res, t); - } - // float -> float if (is_type_float(src) && is_type_float(dst)) { i64 sz = type_size_of(src); diff --git a/src/tilde.hpp b/src/tilde.hpp index bc0fff6f6..e8efca75d 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -375,6 +375,9 @@ gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_val gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value); +gb_internal cgValue cg_builtin_mem_zero(cgProcedure *p, cgValue const &ptr, cgValue const &len); +gb_internal cgValue cg_builtin_mem_copy(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len); +gb_internal cgValue cg_builtin_mem_copy_non_overlapping(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len); gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x); gb_internal cgValue cg_builtin_map_info(cgProcedure *p, Type *map_type); gb_internal cgValue cg_builtin_map_cell_info(cgProcedure *p, Type *type); diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 636bf8fd4..34c8d4ad1 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -15,6 +15,11 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { return value; } +gb_internal void cg_emit_if(cgProcedure *p, cgValue const &cond, TB_Node *true_region, TB_Node *false_region) { + GB_ASSERT(cond.kind == cgValue_Value); + tb_inst_if(p->func, cond.node, true_region, false_region); +} + gb_internal cgValue cg_emit_select(cgProcedure *p, cgValue const &cond, cgValue const &x, cgValue const &y) { GB_ASSERT(x.kind == y.kind); GB_ASSERT(cond.kind == cgValue_Value); @@ -487,7 +492,27 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left } if (is_type_string(a)) { - if (is_type_cstring(a)) { + if (is_type_cstring(a) && is_type_cstring(b)) { + left = cg_emit_conv(p, left, t_cstring); + right = cg_emit_conv(p, right, t_cstring); + char const *runtime_procedure = nullptr; + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "cstring_eq"; break; + case Token_NotEq: runtime_procedure = "cstring_ne"; break; + case Token_Lt: runtime_procedure = "cstring_lt"; break; + case Token_Gt: runtime_procedure = "cstring_gt"; break; + case Token_LtEq: runtime_procedure = "cstring_le"; break; + case Token_GtEq: runtime_procedure = "cstring_gt"; break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = slice_make(permanent_allocator(), 2); + args[0] = left; + args[1] = right; + return cg_emit_runtime_call(p, runtime_procedure, args); + } + + if (is_type_cstring(a) ^ is_type_cstring(b)) { left = cg_emit_conv(p, left, t_string); right = cg_emit_conv(p, right, t_string); } @@ -534,11 +559,10 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left } GB_ASSERT(runtime_procedure != nullptr); - GB_PANIC("TODO(bill): cg_emit_runtime_call"); - // auto args = array_make(permanent_allocator(), 2); - // args[0] = left; - // args[1] = right; - // return lb_emit_runtime_call(p, runtime_procedure, args); + auto args = slice_make(permanent_allocator(), 2); + args[0] = left; + args[1] = right; + return cg_emit_runtime_call(p, runtime_procedure, args); } if (is_type_quaternion(a)) { @@ -566,11 +590,10 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left } GB_ASSERT(runtime_procedure != nullptr); - GB_PANIC("TODO(bill): cg_emit_runtime_call"); - // auto args = array_make(permanent_allocator(), 2); - // args[0] = left; - // args[1] = right; - // return lb_emit_runtime_call(p, runtime_procedure, args); + auto args = slice_make(permanent_allocator(), 2); + args[0] = left; + args[1] = right; + return cg_emit_runtime_call(p, runtime_procedure, args); } if (is_type_bit_set(a)) { @@ -824,57 +847,104 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, } break; case Type_Struct: - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // if (is_type_soa_struct(t)) { - // Type *bt = base_type(t); - // if (bt->Struct.soa_kind == StructSoa_Slice) { - // LLVMValueRef the_value = {}; - // if (bt->Struct.fields.count == 0) { - // cgValue len = cg_soa_struct_len(p, x); - // the_value = len.value; - // } else { - // cgValue first_field = cg_emit_struct_ev(p, x, 0); - // the_value = first_field.value; - // } - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, the_value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - // return res; - // } - // } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { - // LLVMValueRef the_value = {}; - // if (bt->Struct.fields.count == 0) { - // cgValue cap = cg_soa_struct_cap(p, x); - // the_value = cap.value; - // } else { - // cgValue first_field = cg_emit_struct_ev(p, x, 0); - // the_value = first_field.value; - // } - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, the_value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - // return res; - // } - // } - // } else if (is_type_struct(t) && type_has_nil(t)) { - // auto args = array_make(permanent_allocator(), 2); - // cgValue lhs = cg_address_from_load_or_generate_local(p, x); - // args[0] = cg_emit_conv(p, lhs, t_rawptr); - // args[1] = cg_const_int(p->module, t_int, type_size_of(t)); - // cgValue val = cg_emit_runtime_call(p, "memory_compare_zero", args); - // cgValue res = cg_emit_comp(p, op_kind, val, cg_const_int(p->module, t_int, 0)); - // return res; - // } + if (is_type_soa_struct(t)) { + GB_PANIC("TODO(bill): #soa cg_emit_comp_against_nil"); + // Type *bt = base_type(t); + // if (bt->Struct.soa_kind == StructSoa_Slice) { + // LLVMValueRef the_value = {}; + // if (bt->Struct.fields.count == 0) { + // cgValue len = cg_soa_struct_len(p, x); + // the_value = len.value; + // } else { + // cgValue first_field = cg_emit_struct_ev(p, x, 0); + // the_value = first_field.value; + // } + // if (op_kind == Token_CmpEq) { + // res.value = LLVMBuildIsNull(p->builder, the_value, ""); + // return res; + // } else if (op_kind == Token_NotEq) { + // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); + // return res; + // } + // } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { + // LLVMValueRef the_value = {}; + // if (bt->Struct.fields.count == 0) { + // cgValue cap = cg_soa_struct_cap(p, x); + // the_value = cap.value; + // } else { + // cgValue first_field = cg_emit_struct_ev(p, x, 0); + // the_value = first_field.value; + // } + // if (op_kind == Token_CmpEq) { + // res.value = LLVMBuildIsNull(p->builder, the_value, ""); + // return res; + // } else if (op_kind == Token_NotEq) { + // res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); + // return res; + // } + // } + } else if (is_type_struct(t) && type_has_nil(t)) { + auto args = slice_make(permanent_allocator(), 2); + cgValue lhs = cg_address_from_load_or_generate_local(p, x); + args[0] = cg_emit_conv(p, lhs, t_rawptr); + args[1] = cg_const_int(p, t_int, type_size_of(t)); + cgValue val = cg_emit_runtime_call(p, "memory_compare_zero", args); + cgValue res = cg_emit_comp(p, op_kind, val, cg_const_int(p, t_int, 0)); + return res; + } break; } GB_PANIC("Unknown handled type: %s -> %s", type_to_string(t), type_to_string(bt)); return {}; } +gb_internal void cg_emit_store_union_variant_tag(cgProcedure *p, cgValue parent, Type *variant_type) { + Type *t = type_deref(parent.type); + GB_ASSERT(is_type_union(t)); + + if (is_type_union_maybe_pointer(t) || type_size_of(t) == 0) { + // No tag needed! + } else { + cgValue tag_ptr = cg_emit_union_tag_ptr(p, parent); + cg_emit_store(p, tag_ptr, cg_const_union_tag(p, t, variant_type)); + } +} + +gb_internal void cg_emit_store_union_variant(cgProcedure *p, cgValue parent, cgValue variant, Type *variant_type) { + Type *pt = base_type(type_deref(parent.type)); + GB_ASSERT(pt->kind == Type_Union); + if (pt->Union.kind == UnionType_shared_nil) { + GB_ASSERT(type_size_of(variant_type)); + + TB_Node *if_nil = cg_control_region(p, "shared_nil.if_nil"); + TB_Node *if_not_nil = cg_control_region(p, "shared_nil.if_not_nil"); + TB_Node *done = cg_control_region(p, "shared_nil.done"); + + cgValue cond_is_nil = cg_emit_comp_against_nil(p, Token_CmpEq, variant); + cg_emit_if(p, cond_is_nil, if_nil, if_not_nil); + + tb_inst_set_control(p->func, if_nil); + cg_emit_store(p, parent, cg_const_nil(p, type_deref(parent.type))); + cg_emit_goto(p, done); + + tb_inst_set_control(p->func, if_not_nil); + cgValue underlying = cg_emit_conv(p, parent, alloc_type_pointer(variant_type)); + cg_emit_store(p, underlying, variant); + cg_emit_store_union_variant_tag(p, parent, variant_type); + cg_emit_goto(p, done); + + tb_inst_set_control(p->func, done); + } else { + if (type_size_of(variant_type) == 0) { + cg_builtin_mem_zero(p, parent, cg_const_int(p, t_uint, pt->Union.variant_block_size)); + } else { + cgValue underlying = cg_emit_conv(p, parent, alloc_type_pointer(variant_type)); + cg_emit_store(p, underlying, variant); + } + cg_emit_store_union_variant_tag(p, parent, variant_type); + } +} + gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { t = reduce_tuple_to_single_type(t); @@ -899,7 +969,11 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { GB_ASSERT(dst != nullptr); if (are_types_identical(src, dst)) { - return cg_emit_transmute(p, value, t); + if (!are_types_identical(src_type, t)) { + return cg_emit_transmute(p, value, t); + } + value.type = t; + return value; } TB_DataType st = cg_data_type(src); @@ -1028,27 +1102,75 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { } if (is_type_complex(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): complex -> complex"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, false); + cgValue ptr = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, cg_emit_struct_ev(p, value, 0), ft); + cgValue imag = cg_emit_conv(p, cg_emit_struct_ev(p, value, 1), ft); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 0), real); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 1), imag); + return cg_addr_load(p, gen); } if (is_type_quaternion(src) && is_type_quaternion(dst)) { // @QuaternionLayout - GB_PANIC("TODO(bill): quaternion -> quaternion"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, false); + cgValue ptr = cg_addr_get_ptr(p, gen); + cgValue q0 = cg_emit_conv(p, cg_emit_struct_ev(p, value, 0), ft); + cgValue q1 = cg_emit_conv(p, cg_emit_struct_ev(p, value, 1), ft); + cgValue q2 = cg_emit_conv(p, cg_emit_struct_ev(p, value, 2), ft); + cgValue q3 = cg_emit_conv(p, cg_emit_struct_ev(p, value, 3), ft); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 0), q0); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 1), q1); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 2), q2); + cg_emit_store(p, cg_emit_struct_ep(p, ptr, 3), q3); + return cg_addr_load(p, gen); } if (is_type_integer(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): int -> complex"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, true); + cgValue gp = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, value, ft); + cg_emit_store(p, cg_emit_struct_ep(p, gp, 0), real); + return cg_addr_load(p, gen); } if (is_type_float(src) && is_type_complex(dst)) { - GB_PANIC("TODO(bill): float -> complex"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, true); + cgValue gp = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, value, ft); + cg_emit_store(p, cg_emit_struct_ep(p, gp, 0), real); + return cg_addr_load(p, gen); } if (is_type_integer(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): int -> quaternion"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, true); + cgValue gp = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, value, ft); + // @QuaternionLayout + cg_emit_store(p, cg_emit_struct_ep(p, gp, 3), real); + return cg_addr_load(p, gen); } if (is_type_float(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): float -> quaternion"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, true); + cgValue gp = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, value, ft); + // @QuaternionLayout + cg_emit_store(p, cg_emit_struct_ep(p, gp, 3), real); + return cg_addr_load(p, gen); } if (is_type_complex(src) && is_type_quaternion(dst)) { - GB_PANIC("TODO(bill): complex -> quaternion"); + Type *ft = base_complex_elem_type(dst); + cgAddr gen = cg_add_local(p, t, nullptr, true); + cgValue gp = cg_addr_get_ptr(p, gen); + cgValue real = cg_emit_conv(p, cg_emit_struct_ev(p, value, 0), ft); + cgValue imag = cg_emit_conv(p, cg_emit_struct_ev(p, value, 1), ft); + // @QuaternionLayout + cg_emit_store(p, cg_emit_struct_ep(p, gp, 3), real); + cg_emit_store(p, cg_emit_struct_ep(p, gp, 0), imag); + return cg_addr_load(p, gen); } @@ -1063,18 +1185,18 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { return cg_emit_conv(p, res, t); } - // if (is_type_integer_128bit(dst)) { - // TEMPORARY_ALLOCATOR_GUARD(); + if (is_type_integer_128bit(dst)) { + TEMPORARY_ALLOCATOR_GUARD(); - // auto args = array_make(temporary_allocator(), 1); - // args[0] = value; - // char const *call = "fixunsdfdi"; - // if (is_type_unsigned(dst)) { - // call = "fixunsdfti"; - // } - // lbValue res_i128 = lb_emit_runtime_call(p, call, args); - // return lb_emit_conv(p, res_i128, t); - // } + auto args = slice_make(temporary_allocator(), 1); + args[0] = value; + char const *call = "fixunsdfdi"; + if (is_type_unsigned(dst)) { + call = "fixunsdfti"; + } + cgValue res_i128 = cg_emit_runtime_call(p, call, args); + return cg_emit_conv(p, res_i128, t); + } bool is_signed = !is_type_unsigned(dst); return cg_value(tb_inst_float2int(p->func, value.node, dt, is_signed), t); @@ -1092,18 +1214,18 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { return cg_emit_conv(p, res, t); } - // if (is_type_integer_128bit(src)) { - // TEMPORARY_ALLOCATOR_GUARD(); + if (is_type_integer_128bit(src)) { + TEMPORARY_ALLOCATOR_GUARD(); - // auto args = array_make(temporary_allocator(), 1); - // args[0] = value; - // char const *call = "floattidf"; - // if (is_type_unsigned(src)) { - // call = "floattidf_unsigned"; - // } - // lbValue res_f64 = lb_emit_runtime_call(p, call, args); - // return lb_emit_conv(p, res_f64, t); - // } + auto args = slice_make(temporary_allocator(), 1); + args[0] = value; + char const *call = "floattidf"; + if (is_type_unsigned(src)) { + call = "floattidf_unsigned"; + } + cgValue res_f64 = cg_emit_runtime_call(p, call, args); + return cg_emit_conv(p, res_f64, t); + } bool is_signed = !is_type_unsigned(dst); return cg_value(tb_inst_int2float(p->func, value.node, dt, is_signed), t); @@ -1113,6 +1235,22 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { GB_PANIC("TODO(bill): ? -> #simd vector"); } + // bit_field <-> backing type + if (is_type_bit_field(src)) { + if (are_types_identical(src->BitField.backing_type, dst)) { + cgValue res = value; + res.type = t; + return res; + } + } + if (is_type_bit_field(dst)) { + if (are_types_identical(src, dst->BitField.backing_type)) { + cgValue res = value; + res.type = t; + return res; + } + } + // Pointer <-> uintptr if (is_type_pointer(src) && is_type_uintptr(dst)) { @@ -1129,13 +1267,66 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { } if (is_type_union(dst)) { - GB_PANIC("TODO(bill): ? -> union"); + for (Type *vt : dst->Union.variants) { + if (are_types_identical(vt, src_type)) { + cgAddr parent = cg_add_local(p, t, nullptr, true); + cg_emit_store_union_variant(p, parent.addr, value, vt); + return cg_addr_load(p, parent); + } + } + if (dst->Union.variants.count == 1) { + Type *vt = dst->Union.variants[0]; + if (internal_check_is_assignable_to(src_type, vt)) { + value = cg_emit_conv(p, value, vt); + cgAddr parent = cg_add_local(p, t, nullptr, true); + cg_emit_store_union_variant(p, parent.addr, value, vt); + return cg_addr_load(p, parent); + } + } } // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's // subtype polymorphism casting if (check_is_assignable_to_using_subtype(src_type, t)) { - GB_PANIC("TODO(bill): ? -> subtyping"); + Type *st = type_deref(src_type); + st = type_deref(st); + + bool st_is_ptr = is_type_pointer(src_type); + st = base_type(st); + + Type *dt = t; + + GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); + Selection sel = {}; + sel.index.allocator = heap_allocator(); + defer (array_free(&sel.index)); + if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) { + if (sel.entity == nullptr) { + GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t)); + } + if (st_is_ptr) { + cgValue res = cg_emit_deep_field_gep(p, value, sel); + Type *rt = res.type; + if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { + res = cg_emit_load(p, res); + } + return res; + } else { + if (is_type_pointer(value.type)) { + Type *rt = value.type; + if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { + value = cg_emit_load(p, value); + } else { + value = cg_emit_deep_field_gep(p, value, sel); + return cg_emit_load(p, value); + } + } + + cgValue ptr = cg_address_from_load_or_generate_local(p, value); + cgValue res = cg_emit_deep_field_gep(p, ptr, sel); + return cg_emit_load(p, res); + } + } } // Pointer <-> Pointer @@ -1174,6 +1365,10 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { return cg_emit_transmute(p, value, t); } + if (is_type_array_like(dst)) { + GB_PANIC("TODO(bill): ??? -> array-like"); + } + if (is_type_matrix(dst) && !is_type_matrix(src)) { GB_PANIC("TODO(bill): !matrix -> matrix"); } @@ -1197,9 +1392,6 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { GB_ASSERT(is_type_typed(st)); data = cg_emit_conv(p, data, t_rawptr); - if (p->name == "main@main") { - GB_PANIC("HERE %s %llu", type_to_string(st), cg_typeid_as_u64(p->module, value.type)); - } cgValue id = cg_typeid(p, st); cgValue data_ptr = cg_emit_struct_ep(p, result.addr, 0); @@ -1781,11 +1973,6 @@ gb_internal cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, return res; } -gb_internal void cg_emit_if(cgProcedure *p, cgValue const &cond, TB_Node *true_region, TB_Node *false_region) { - GB_ASSERT(cond.kind == cgValue_Value); - tb_inst_if(p->func, cond.node, true_region, false_region); -} - struct cgLoopData { cgAddr index_addr; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index afee977de..d3791c571 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -392,9 +392,11 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { // feature_set.x64 |= TB_FEATURE_X64_LZCNT; } +#if 0 bool emit_asm = false; TB_FunctionOutput *output = tb_codegen(p->func, cg_worklist(), cg_arena(), &feature_set, emit_asm); gb_unused(output); +#endif // tb_print(p->func, cg_arena()); // fprintf(stdout, "\n");