aboutsummaryrefslogtreecommitdiff
path: root/src/tilde_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-07-19 18:03:42 +0100
committergingerBill <bill@gingerbill.org>2023-07-19 18:03:42 +0100
commit5fb98609cd9d5d7efea6d54a722181ff46413333 (patch)
tree7a3a098b933251a87c0b1685e9e0350bbde98012 /src/tilde_expr.cpp
parent19633ece8059c32f1b2571097e5234c5903c7f2d (diff)
Implement type `switch` statement for `union`s
Diffstat (limited to 'src/tilde_expr.cpp')
-rw-r--r--src/tilde_expr.cpp38
1 files changed, 30 insertions, 8 deletions
diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp
index c2453b571..f3801682d 100644
--- a/src/tilde_expr.cpp
+++ b/src/tilde_expr.cpp
@@ -125,6 +125,26 @@ gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) {
return {};
}
+gb_internal cgValue cg_emit_union_tag_ptr(cgProcedure *p, cgValue const &parent_ptr) {
+ Type *t = parent_ptr.type;
+ Type *ut = base_type(type_deref(t));
+ GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
+ GB_ASSERT_MSG(ut->kind == Type_Union, "%s", type_to_string(t));
+
+ GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut));
+ GB_ASSERT(!is_type_union_maybe_pointer(ut));
+ GB_ASSERT(type_size_of(ut) > 0);
+
+ Type *tag_type = union_tag_type(ut);
+ i64 tag_offset = ut->Union.variant_block_size;
+
+ GB_ASSERT(parent_ptr.kind == cgValue_Value);
+ TB_Node *ptr = parent_ptr.node;
+ TB_Node *tag_ptr = tb_inst_member_access(p->func, ptr, tag_offset);
+ return cg_value(tag_ptr, alloc_type_pointer(tag_type));
+}
+
+
gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) {
Type *src = core_type(value.type);
@@ -166,7 +186,9 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type)
case cgValue_Value:
GB_ASSERT(!TB_IS_VOID_TYPE(dt));
value.type = type;
- value.node = tb_inst_bitcast(p->func, value.node, dt);
+ if (value.node->dt.raw != dt.raw) {
+ value.node = tb_inst_bitcast(p->func, value.node, dt);
+ }
return value;
case cgValue_Addr:
value.type = type;
@@ -1037,30 +1059,30 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) {
// Pointer <-> Pointer
if (is_type_pointer(src) && is_type_pointer(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
if (is_type_multi_pointer(src) && is_type_pointer(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
if (is_type_pointer(src) && is_type_multi_pointer(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
// proc <-> proc
if (is_type_proc(src) && is_type_proc(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
// pointer -> proc
if (is_type_pointer(src) && is_type_proc(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
// proc -> pointer
if (is_type_proc(src) && is_type_pointer(dst)) {
- return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+ return cg_value(value.node, t);
}
// []byte/[]u8 <-> string