Fill out more of the tilde expression code

This commit is contained in:
gingerBill
2024-04-30 15:13:03 +01:00
parent 1fb5bf6bdb
commit 915db6d228
4 changed files with 296 additions and 104 deletions

View File

@@ -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);

View File

@@ -375,6 +375,9 @@ gb_internal isize cg_append_tuple_values(cgProcedure *p, Array<cgValue> *dst_val
gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const &param_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);

View File

@@ -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<cgValue>(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<lbValue>(permanent_allocator(), 2);
// args[0] = left;
// args[1] = right;
// return lb_emit_runtime_call(p, runtime_procedure, args);
auto args = slice_make<cgValue>(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<lbValue>(permanent_allocator(), 2);
// args[0] = left;
// args[1] = right;
// return lb_emit_runtime_call(p, runtime_procedure, args);
auto args = slice_make<cgValue>(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<cgValue>(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<cgValue>(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<lbValue>(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<cgValue>(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<lbValue>(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<cgValue>(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;

View File

@@ -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");