aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_general.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-03-24 11:55:03 +0000
committergingerBill <bill@gingerbill.org>2022-03-24 11:55:03 +0000
commit3f935bea2505b3ee7e169a29b7aed50c0e5614b7 (patch)
tree3d3886ccfe8146a2226703c1d10b7908f3b54e3b /src/llvm_backend_general.cpp
parent3e66eec7354a8248fe8e0edfccbdc9e8b203e88a (diff)
`union #shared_nil`
This adds a feature to `union` which requires all the variants to have a `nil` value and on assign to the union, checks whether that value is `nil` or not. If the value is `nil`, the union will be `nil` (thus sharing the `nil` value)
Diffstat (limited to 'src/llvm_backend_general.cpp')
-rw-r--r--src/llvm_backend_general.cpp31
1 files changed, 28 insertions, 3 deletions
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index dd1555193..f6dd97966 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -1176,10 +1176,35 @@ void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *varia
}
void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) {
- lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
+ Type *pt = base_type(type_deref(parent.type));
+ GB_ASSERT(pt->kind == Type_Union);
+ if (pt->Union.kind == UnionType_shared_nil) {
+ lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil");
+ lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil");
+ lbBlock *done = lb_create_block(p, "shared_nil.done");
+
+ lbValue cond_is_nil = lb_emit_comp_against_nil(p, Token_CmpEq, variant);
+ lb_emit_if(p, cond_is_nil, if_nil, if_not_nil);
+
+ lb_start_block(p, if_nil);
+ lb_emit_store(p, parent, lb_const_nil(p->module, type_deref(parent.type)));
+ lb_emit_jump(p, done);
+
+ lb_start_block(p, if_not_nil);
+ lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
+ lb_emit_store(p, underlying, variant);
+ lb_emit_store_union_variant_tag(p, parent, variant_type);
+ lb_emit_jump(p, done);
+
+ lb_start_block(p, done);
- lb_emit_store(p, underlying, variant);
- lb_emit_store_union_variant_tag(p, parent, variant_type);
+
+ } else {
+ lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
+
+ lb_emit_store(p, underlying, variant);
+ lb_emit_store_union_variant_tag(p, parent, variant_type);
+ }
}