From 7f4efa90c8259d119e177c58fa150977136b4e86 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Jul 2023 16:51:37 +0100 Subject: Mock out `cg_emit_comp` --- src/tilde_expr.cpp | 575 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 574 insertions(+), 1 deletion(-) (limited to 'src/tilde_expr.cpp') diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 7fd943347..63b1feb6e 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -2,7 +2,15 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { GB_ASSERT(value.kind != cgValue_Multi); if (value.kind == cgValue_Symbol) { GB_ASSERT(is_type_internally_pointer_like(value.type)); - value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); + return cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); + } else if (value.kind == cgValue_Addr) { + // TODO(bill): Is this a good idea? + // this converts an lvalue to an rvalue if trivially possible + TB_DataType dt = cg_data_type(value.type); + if (!TB_IS_VOID_TYPE(dt)) { + TB_CharUnits align = cast(TB_CharUnits)type_align_of(value.type); + return cg_value(tb_inst_load(p->func, dt, value.node, align, false), value.type); + } } return value; } @@ -198,6 +206,571 @@ gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_t return cg_emit_transmute(p, value, end_type); } +gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right) { + GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); + + Type *a = core_type(left.type); + Type *b = core_type(right.type); + + cgValue nil_check = {}; + if (is_type_array_like(left.type) || is_type_array_like(right.type)) { + // don't do `nil` check if it is array-like + } else if (is_type_untyped_nil(left.type)) { + nil_check = cg_emit_comp_against_nil(p, op_kind, right); + } else if (is_type_untyped_nil(right.type)) { + nil_check = cg_emit_comp_against_nil(p, op_kind, left); + } + if (nil_check.node != nullptr) { + return nil_check; + } + + if (are_types_identical(a, b)) { + // NOTE(bill): No need for a conversion + } /*else if (cg_is_const(left) || cg_is_const_nil(left)) { + left = cg_emit_conv(p, left, right.type); + } else if (cg_is_const(right) || cg_is_const_nil(right)) { + right = cg_emit_conv(p, right, left.type); + }*/ else { + Type *lt = left.type; + Type *rt = right.type; + + lt = left.type; + rt = right.type; + i64 ls = type_size_of(lt); + i64 rs = type_size_of(rt); + + // NOTE(bill): Quick heuristic, larger types are usually the target type + if (ls < rs) { + left = cg_emit_conv(p, left, rt); + } else if (ls > rs) { + right = cg_emit_conv(p, right, lt); + } else { + if (is_type_union(rt)) { + left = cg_emit_conv(p, left, rt); + } else { + right = cg_emit_conv(p, right, lt); + } + } + } + + a = core_type(left.type); + b = core_type(right.type); + left = cg_flatten_value(p, left); + right = cg_flatten_value(p, right); + + + if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + GB_PANIC("TODO(bill): cg_emit_comp matrix"); + // Type *tl = base_type(a); + // lbValue lhs = lb_address_from_load_or_generate_local(p, left); + // lbValue rhs = lb_address_from_load_or_generate_local(p, right); + + + // // TODO(bill): Test to see if this is actually faster!!!! + // auto args = array_make(permanent_allocator(), 3); + // args[0] = lb_emit_conv(p, lhs, t_rawptr); + // args[1] = lb_emit_conv(p, rhs, t_rawptr); + // args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); + // lbValue val = lb_emit_runtime_call(p, "memory_compare", args); + // lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); + // return lb_emit_conv(p, res, t_bool); + } + if (is_type_array_like(a)) { + GB_PANIC("TODO(bill): cg_emit_comp is_type_array_like"); + // Type *tl = base_type(a); + // lbValue lhs = lb_address_from_load_or_generate_local(p, left); + // lbValue rhs = lb_address_from_load_or_generate_local(p, right); + + + // TokenKind cmp_op = Token_And; + // lbValue res = lb_const_bool(p->module, t_llvm_bool, true); + // if (op_kind == Token_NotEq) { + // res = lb_const_bool(p->module, t_llvm_bool, false); + // cmp_op = Token_Or; + // } else if (op_kind == Token_CmpEq) { + // res = lb_const_bool(p->module, t_llvm_bool, true); + // cmp_op = Token_And; + // } + + // bool inline_array_arith = lb_can_try_to_inline_array_arith(tl); + // i32 count = 0; + // switch (tl->kind) { + // case Type_Array: count = cast(i32)tl->Array.count; break; + // case Type_EnumeratedArray: count = cast(i32)tl->EnumeratedArray.count; break; + // } + + // if (inline_array_arith) { + // // inline + // lbAddr val = lb_add_local_generated(p, t_bool, false); + // lb_addr_store(p, val, res); + // for (i32 i = 0; i < count; i++) { + // lbValue x = lb_emit_load(p, lb_emit_array_epi(p, lhs, i)); + // lbValue y = lb_emit_load(p, lb_emit_array_epi(p, rhs, i)); + // lbValue cmp = lb_emit_comp(p, op_kind, x, y); + // lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); + // lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); + // } + + // return lb_addr_load(p, val); + // } else { + // if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + // // TODO(bill): Test to see if this is actually faster!!!! + // auto args = array_make(permanent_allocator(), 3); + // args[0] = lb_emit_conv(p, lhs, t_rawptr); + // args[1] = lb_emit_conv(p, rhs, t_rawptr); + // args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); + // lbValue val = lb_emit_runtime_call(p, "memory_compare", args); + // lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); + // return lb_emit_conv(p, res, t_bool); + // } else { + // lbAddr val = lb_add_local_generated(p, t_bool, false); + // lb_addr_store(p, val, res); + // auto loop_data = lb_loop_start(p, count, t_i32); + // { + // lbValue i = loop_data.idx; + // lbValue x = lb_emit_load(p, lb_emit_array_ep(p, lhs, i)); + // lbValue y = lb_emit_load(p, lb_emit_array_ep(p, rhs, i)); + // lbValue cmp = lb_emit_comp(p, op_kind, x, y); + // lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); + // lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); + // } + // lb_loop_end(p, loop_data); + + // return lb_addr_load(p, val); + // } + // } + } + + if ((is_type_struct(a) || is_type_union(a)) && is_type_comparable(a)) { + GB_PANIC("TODO(bill): cg_compare_records"); + // return cg_compare_records(p, op_kind, left, right, a); + } + + if ((is_type_struct(b) || is_type_union(b)) && is_type_comparable(b)) { + GB_PANIC("TODO(bill): cg_compare_records"); + // return cg_compare_records(p, op_kind, left, right, b); + } + + if (is_type_string(a)) { + if (is_type_cstring(a)) { + left = cg_emit_conv(p, left, t_string); + right = cg_emit_conv(p, right, t_string); + } + + char const *runtime_procedure = nullptr; + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "string_eq"; break; + case Token_NotEq: runtime_procedure = "string_ne"; break; + case Token_Lt: runtime_procedure = "string_lt"; break; + case Token_Gt: runtime_procedure = "string_gt"; break; + case Token_LtEq: runtime_procedure = "string_le"; break; + case Token_GtEq: runtime_procedure = "string_gt"; break; + } + 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 cg_emit_runtime_call(p, runtime_procedure, args); + } + + if (is_type_complex(a)) { + char const *runtime_procedure = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 32: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "complex32_eq"; break; + case Token_NotEq: runtime_procedure = "complex32_ne"; break; + } + break; + case 64: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "complex64_eq"; break; + case Token_NotEq: runtime_procedure = "complex64_ne"; break; + } + break; + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "complex128_eq"; break; + case Token_NotEq: runtime_procedure = "complex128_ne"; break; + } + break; + } + 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); + } + + if (is_type_quaternion(a)) { + char const *runtime_procedure = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 64: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "quaternion64_eq"; break; + case Token_NotEq: runtime_procedure = "quaternion64_ne"; break; + } + break; + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "quaternion128_eq"; break; + case Token_NotEq: runtime_procedure = "quaternion128_ne"; break; + } + break; + case 256: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "quaternion256_eq"; break; + case Token_NotEq: runtime_procedure = "quaternion256_ne"; break; + } + break; + } + 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); + } + + if (is_type_bit_set(a)) { + switch (op_kind) { + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: + { + Type *it = bit_set_to_int(a); + cgValue lhs = cg_emit_transmute(p, left, it); + cgValue rhs = cg_emit_transmute(p, right, it); + cgValue res = cg_emit_arith(p, Token_And, lhs, rhs, it); + GB_ASSERT(lhs.kind == cgValue_Value); + GB_ASSERT(rhs.kind == cgValue_Value); + GB_ASSERT(res.kind == cgValue_Value); + + if (op_kind == Token_Lt || op_kind == Token_LtEq) { + // (lhs & rhs) == lhs + res = cg_value(tb_inst_cmp_eq(p->func, res.node, lhs.node), t_bool); + } else if (op_kind == Token_Gt || op_kind == Token_GtEq) { + // (lhs & rhs) == rhs + res = cg_value(tb_inst_cmp_eq(p->func, res.node, rhs.node), t_bool); + } + + // NOTE(bill): Strict subsets + if (op_kind == Token_Lt || op_kind == Token_Gt) { + // res &~ (lhs == rhs) + cgValue eq = cg_value(tb_inst_cmp_eq(p->func, lhs.node, rhs.node), t_bool); + res = cg_emit_arith(p, Token_AndNot, res, eq, t_bool); + } + return res; + } + + case Token_CmpEq: + GB_ASSERT(left.kind == cgValue_Value); + GB_ASSERT(right.kind == cgValue_Value); + return cg_value(tb_inst_cmp_eq(p->func, left.node, right.node), t_bool); + case Token_NotEq: + GB_ASSERT(left.kind == cgValue_Value); + GB_ASSERT(right.kind == cgValue_Value); + return cg_value(tb_inst_cmp_ne(p->func, left.node, right.node), t_bool); + } + } + + if (op_kind != Token_CmpEq && op_kind != Token_NotEq) { + Type *t = left.type; + if (is_type_integer(t) && is_type_different_to_arch_endianness(t)) { + Type *platform_type = integer_endian_type_to_platform_type(t); + cgValue x = cg_emit_byte_swap(p, left, platform_type); + cgValue y = cg_emit_byte_swap(p, right, platform_type); + left = x; + right = y; + } else if (is_type_float(t) && is_type_different_to_arch_endianness(t)) { + Type *platform_type = integer_endian_type_to_platform_type(t); + cgValue x = cg_emit_conv(p, left, platform_type); + cgValue y = cg_emit_conv(p, right, platform_type); + left = x; + right = y; + } + } + + a = core_type(left.type); + b = core_type(right.type); + + + if (is_type_integer(a) || + is_type_boolean(a) || + is_type_pointer(a) || + is_type_multi_pointer(a) || + is_type_proc(a) || + is_type_enum(a) || + is_type_typeid(a)) { + TB_Node *lhs = left.node; + TB_Node *rhs = right.node; + TB_Node *res = nullptr; + + bool is_signed = is_type_integer(left.type) && !is_type_unsigned(left.type); + switch (op_kind) { + case Token_CmpEq: res = tb_inst_cmp_eq(p->func, lhs, rhs); break; + case Token_NotEq: res = tb_inst_cmp_ne(p->func, lhs, rhs); break; + case Token_Gt: res = tb_inst_cmp_igt(p->func, lhs, rhs, is_signed); break; + case Token_GtEq: res = tb_inst_cmp_ige(p->func, lhs, rhs, is_signed); break; + case Token_Lt: res = tb_inst_cmp_ilt(p->func, lhs, rhs, is_signed); break; + case Token_LtEq: res = tb_inst_cmp_ige(p->func, lhs, rhs, is_signed); break; + } + + GB_ASSERT(res != nullptr); + return cg_value(res, t_bool); + } else if (is_type_float(a)) { + TB_Node *lhs = left.node; + TB_Node *rhs = right.node; + TB_Node *res = nullptr; + switch (op_kind) { + case Token_CmpEq: res = tb_inst_cmp_eq(p->func, lhs, rhs); break; + case Token_NotEq: res = tb_inst_cmp_ne(p->func, lhs, rhs); break; + case Token_Gt: res = tb_inst_cmp_fgt(p->func, lhs, rhs); break; + case Token_GtEq: res = tb_inst_cmp_fge(p->func, lhs, rhs); break; + case Token_Lt: res = tb_inst_cmp_flt(p->func, lhs, rhs); break; + case Token_LtEq: res = tb_inst_cmp_fge(p->func, lhs, rhs); break; + } + GB_ASSERT(res != nullptr); + return cg_value(res, t_bool); + } else if (is_type_simd_vector(a)) { + GB_PANIC("TODO(bill): #simd vector"); + // LLVMValueRef mask = nullptr; + // Type *elem = base_array_type(a); + // if (is_type_float(elem)) { + // LLVMRealPredicate pred = {}; + // switch (op_kind) { + // case Token_CmpEq: pred = LLVMRealOEQ; break; + // case Token_NotEq: pred = LLVMRealONE; break; + // } + // mask = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); + // } else { + // LLVMIntPredicate pred = {}; + // switch (op_kind) { + // case Token_CmpEq: pred = LLVMIntEQ; break; + // case Token_NotEq: pred = LLVMIntNE; break; + // } + // mask = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); + // } + // GB_ASSERT_MSG(mask != nullptr, "Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); + + // /* NOTE(bill, 2022-05-28): + // Thanks to Per Vognsen, sign extending to + // a vector of the same width as the input vector, bit casting to an integer, + // and then comparing against zero is the better option + // See: https://lists.llvm.org/pipermail/llvm-dev/2012-September/053046.html + + // // Example assuming 128-bit vector + + // %1 = <4 x float> ... + // %2 = <4 x float> ... + // %3 = fcmp oeq <4 x float> %1, %2 + // %4 = sext <4 x i1> %3 to <4 x i32> + // %5 = bitcast <4 x i32> %4 to i128 + // %6 = icmp ne i128 %5, 0 + // br i1 %6, label %true1, label %false2 + + // This will result in 1 cmpps + 1 ptest + 1 br + // (even without SSE4.1, contrary to what the mail list states, because of pmovmskb) + + // */ + + // unsigned count = cast(unsigned)get_array_type_count(a); + // unsigned elem_sz = cast(unsigned)(type_size_of(elem)*8); + // LLVMTypeRef mask_type = LLVMVectorType(LLVMIntTypeInContext(p->module->ctx, elem_sz), count); + // mask = LLVMBuildSExtOrBitCast(p->builder, mask, mask_type, ""); + + // LLVMTypeRef mask_int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(8*type_size_of(a))); + // LLVMValueRef mask_int = LLVMBuildBitCast(p->builder, mask, mask_int_type, ""); + // res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(LLVMTypeOf(mask_int)), ""); + // return res; + } + + GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); + return {}; +} + +gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x) { + GB_ASSERT(op_kind == Token_CmpEq || op_kind == Token_NotEq); + x = cg_flatten_value(p, x); + cgValue res = {}; + Type *t = x.type; + + TB_DataType dt = cg_data_type(t); + + Type *bt = base_type(t); + TypeKind type_kind = bt->kind; + + switch (type_kind) { + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_rawptr: + case Basic_cstring: + GB_ASSERT(x.kind == cgValue_Value); + if (op_kind == Token_CmpEq) { + return cg_value(tb_inst_cmp_eq(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); + } else if (op_kind == Token_NotEq) { + return cg_value(tb_inst_cmp_ne(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); + } + break; + case Basic_any: + { + GB_PANIC("TODO(bill): cg_emit_struct_ev"); + // // TODO(bill): is this correct behaviour for nil comparison for any? + // cgValue data = cg_emit_struct_ev(p, x, 0); + // cgValue ti = cg_emit_struct_ev(p, x, 1); + // if (op_kind == Token_CmpEq) { + // LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); + // LLVMValueRef b = LLVMBuildIsNull(p->builder, ti.value, ""); + // res.value = LLVMBuildOr(p->builder, a, b, ""); + // return res; + // } else if (op_kind == Token_NotEq) { + // LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); + // LLVMValueRef b = LLVMBuildIsNotNull(p->builder, ti.value, ""); + // res.value = LLVMBuildAnd(p->builder, a, b, ""); + // return res; + // } + } + break; + case Basic_typeid: + cgValue invalid_typeid = cg_const_value(p, t_typeid, exact_value_i64(0)); + return cg_emit_comp(p, op_kind, x, invalid_typeid); + } + break; + + case Type_Enum: + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + case Type_BitSet: + GB_ASSERT(x.kind == cgValue_Value); + if (op_kind == Token_CmpEq) { + return cg_value(tb_inst_cmp_eq(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); + } else if (op_kind == Token_NotEq) { + return cg_value(tb_inst_cmp_ne(p->func, x.node, tb_inst_uint(p->func, dt, 0)), t_bool); + } + break; + + case Type_Slice: + { + GB_PANIC("TODO(bill): cg_emit_struct_ev"); + // cgValue data = cg_emit_struct_ev(p, x, 0); + // if (op_kind == Token_CmpEq) { + // res.value = LLVMBuildIsNull(p->builder, data.value, ""); + // return res; + // } else if (op_kind == Token_NotEq) { + // res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); + // return res; + // } + } + break; + + case Type_DynamicArray: + { + GB_PANIC("TODO(bill): cg_emit_struct_ev"); + // cgValue data = cg_emit_struct_ev(p, x, 0); + // if (op_kind == Token_CmpEq) { + // res.value = LLVMBuildIsNull(p->builder, data.value, ""); + // return res; + // } else if (op_kind == Token_NotEq) { + // res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); + // return res; + // } + } + break; + + case Type_Map: + { + GB_PANIC("TODO(bill): cg_emit_struct_ev"); + // cgValue data_ptr = cg_emit_struct_ev(p, x, 0); + + // if (op_kind == Token_CmpEq) { + // res.value = LLVMBuildIsNull(p->builder, data_ptr.value, ""); + // return res; + // } else { + // res.value = LLVMBuildIsNotNull(p->builder, data_ptr.value, ""); + // return res; + // } + } + break; + + case Type_Union: + { + GB_PANIC("TODO(bill): cg_emit_struct_ev"); + // if (type_size_of(t) == 0) { + // if (op_kind == Token_CmpEq) { + // return cg_const_bool(p->module, t_llvm_bool, true); + // } else if (op_kind == Token_NotEq) { + // return cg_const_bool(p->module, t_llvm_bool, false); + // } + // } else if (is_type_union_maybe_pointer(t)) { + // cgValue tag = cg_emit_transmute(p, x, t_rawptr); + // return cg_emit_comp_against_nil(p, op_kind, tag); + // } else { + // cgValue tag = cg_emit_union_tag_value(p, x); + // return cg_emit_comp(p, op_kind, tag, cg_zero(p->module, tag.type)); + // } + } + 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; + // } + break; + } + GB_PANIC("Unknown handled type: %s -> %s", type_to_string(t), type_to_string(bt)); + return {}; +} + gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { t = reduce_tuple_to_single_type(t); -- cgit v1.2.3