diff options
| author | gingerBill <bill@gingerbill.org> | 2024-04-01 13:08:07 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2024-04-01 13:08:07 +0100 |
| commit | b862691d7524d5dc05d6c43872daa7a488c2411a (patch) | |
| tree | bb9804e3e00b702cc546e1204beab22b83f99a05 /src/llvm_backend_stmt.cpp | |
| parent | f482cc8374d041795dc106709093f194da5ce5bb (diff) | |
Support `for in` with `bit_set`
Diffstat (limited to 'src/llvm_backend_stmt.cpp')
| -rw-r--r-- | src/llvm_backend_stmt.cpp | 94 |
1 files changed, 87 insertions, 7 deletions
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 4ecf70ec4..24dd321f6 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -737,6 +737,22 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_start_block(p, done); } +gb_internal lbValue lb_enum_values_slice(lbProcedure *p, Type *enum_type, i64 *enum_count_) { + Type *t = enum_type; + GB_ASSERT(is_type_enum(t)); + t = base_type(t); + GB_ASSERT(t->kind == Type_Enum); + i64 enum_count = t->Enum.fields.count; + + if (enum_count_) *enum_count_ = enum_count; + + lbValue ti = lb_type_info(p, t); + lbValue variant = lb_emit_struct_ep(p, ti, 4); + lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); + lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); + return values; +} + gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { lbModule *m = p->module; @@ -744,15 +760,11 @@ gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_ GB_ASSERT(is_type_enum(t)); t = base_type(t); Type *core_elem = core_type(t); - GB_ASSERT(t->kind == Type_Enum); - i64 enum_count = t->Enum.fields.count; - lbValue max_count = lb_const_int(m, t_int, enum_count); + i64 enum_count = 0; - lbValue ti = lb_type_info(p, t); - lbValue variant = lb_emit_struct_ep(p, ti, 4); - lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); - lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); + lbValue values = lb_enum_values_slice(p, enum_type, &enum_count); lbValue values_data = lb_slice_elem(p, values); + lbValue max_count = lb_const_int(m, t_int, enum_count); lbAddr offset_ = lb_add_local_generated(p, t_int, false); lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); @@ -1052,6 +1064,74 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc case Type_Tuple: lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); break; + + case Type_BitSet: { + lbModule *m = p->module; + + lbValue the_set = lb_build_expr(p, expr); + if (is_type_pointer(type_deref(the_set.type))) { + the_set = lb_emit_load(p, the_set); + } + + Type *elem = et->BitSet.elem; + if (is_type_enum(elem)) { + i64 enum_count = 0; + lbValue values = lb_enum_values_slice(p, elem, &enum_count); + lbValue values_data = lb_slice_elem(p, values); + lbValue max_count = lb_const_int(m, t_int, enum_count); + + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + + loop = lb_create_block(p, "for.bit_set.enum.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body_check = lb_create_block(p, "for.bit_set.enum.body-check"); + lbBlock *body = lb_create_block(p, "for.bit_set.enum.body"); + done = lb_create_block(p, "for.bit_set.enum.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count); + lb_emit_if(p, cond, body_check, done); + lb_start_block(p, body_check); + + lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset); + lb_emit_increment(p, offset_.addr); + val = lb_emit_load(p, val_ptr); + val = lb_emit_conv(p, val, elem); + + lbValue check = lb_build_binary_in(p, val, the_set, Token_in); + lb_emit_if(p, check, body, loop); + lb_start_block(p, body); + } else { + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, et->BitSet.lower)); + + lbValue max_count = lb_const_int(m, t_int, et->BitSet.upper); + + loop = lb_create_block(p, "for.bit_set.range.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body_check = lb_create_block(p, "for.bit_set.range.body-check"); + lbBlock *body = lb_create_block(p, "for.bit_set.range.body"); + done = lb_create_block(p, "for.bit_set.range.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_LtEq, offset, max_count); + lb_emit_if(p, cond, body_check, done); + lb_start_block(p, body_check); + + val = lb_emit_conv(p, offset, elem); + lb_emit_increment(p, offset_.addr); + + lbValue check = lb_build_binary_in(p, val, the_set, Token_in); + lb_emit_if(p, check, body, loop); + lb_start_block(p, body); + } + break; + } default: GB_PANIC("Cannot range over %s", type_to_string(expr_type)); break; |