Add bit_set type

This commit is contained in:
gingerBill
2018-08-14 17:07:56 +01:00
parent 89f4e7a8db
commit acc010cba5
14 changed files with 509 additions and 45 deletions
+87 -1
View File
@@ -70,7 +70,7 @@ write_rune :: proc(buf: ^String_Buffer, r: rune) {
write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) {
b: [129]byte;
s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, 0);
s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, nil);
write_string(buf, s);
}
@@ -312,6 +312,11 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
write_i64(buf, i64(info.bits[i]), 10);
}
write_string(buf, "}");
case runtime.Type_Info_Bit_Set:
write_string(buf, "bit_set[");
write_type(buf, info.base);
write_string(buf, "]");
}
}
@@ -714,6 +719,82 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
}
enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
switch i in ev {
case rune: return u64(i);
case i8: return u64(i);
case i16: return u64(i);
case i32: return u64(i);
case i64: return u64(i);
case int: return u64(i);
case u8: return u64(i);
case u16: return u64(i);
case u32: return u64(i);
case u64: return u64(i);
case uint: return u64(i);
case uintptr: return u64(i);
case f32: return u64(i);
case f64: return u64(i);
}
return 0;
}
fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
type_info := type_info_of(v.typeid);
switch info in type_info.variant {
case runtime.Type_Info_Named:
val := v;
val.typeid = info.base.id;
fmt_bit_set(fi, val, info.name);
case runtime.Type_Info_Bit_Set:
bits: u64;
bit_size := u64(8*type_info.size);
verb := 'b';
switch bit_size {
case 0: bits = 0;
case 8: bits = u64( (^u8)(v.data)^);
case 16: bits = u64((^u16)(v.data)^);
case 32: bits = u64((^u32)(v.data)^);
case 64: bits = u64((^u64)(v.data)^);
case: panic("unknown bit_size size");
}
et := runtime.type_info_base(info.base);
e := et.variant.(runtime.Type_Info_Enum);
if name != "" {
write_string(fi.buf, name);
} else {
write_type(fi.buf, type_info);
}
write_byte(fi.buf, '{');
defer write_byte(fi.buf, '}');
commas := 0;
loop: for i in 0 .. bit_size-1 {
if bits & (1<<i) == 0 {
continue loop;
}
if commas > 0 do write_string(fi.buf, ", ");
defer commas += 1;
for ev, evi in e.values {
v := enum_value_to_u64(ev);
if v == i {
write_string(fi.buf, e.names[evi]);
continue loop;
}
}
write_i64(fi.buf, i64(i), 10);
}
}
}
fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
if v.data == nil || v.typeid == nil {
write_string(fi.buf, "<nil>");
@@ -765,6 +846,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
if hash do for in 0..indent-1 do write_byte(fi.buf, '\t');
write_byte(fi.buf, '}');
case runtime.Type_Info_Bit_Set:
fmt_bit_set(fi, v);
case:
fmt_value(fi, any{v.data, typeid_of(info.base)}, verb);
}
@@ -929,6 +1012,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
case runtime.Type_Info_Type_Id:
id := (^typeid)(v.data)^;
write_typeid(fi.buf, id);
case runtime.Type_Info_Bit_Set:
fmt_bit_set(fi, v);
}
}
+4 -1
View File
@@ -99,7 +99,9 @@ Type_Info_Bit_Field :: struct {
bits: []i32,
offsets: []i32,
};
Type_Info_Bit_Set :: struct {
base: ^Type_Info,
};
Type_Info :: struct {
size: int,
@@ -127,6 +129,7 @@ Type_Info :: struct {
Type_Info_Enum,
Type_Info_Map,
Type_Info_Bit_Field,
Type_Info_Bit_Set,
},
}
+50
View File
@@ -0,0 +1,50 @@
package runtime
foreign import kernel32 "system:Kernel32.lib"
@(link_name="memcpy")
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
foreign kernel32 {
RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) ---
}
RtlCopyMemory(dst, src, len);
return dst;
}
@(link_name="memmove")
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
foreign kernel32 {
RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) ---
}
RtlMoveMemory(dst, src, len);
return dst;
}
@(link_name="memset")
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
foreign kernel32 {
RtlFillMemory :: proc "c" (dst: rawptr, len: int, fill: byte) ---
}
RtlFillMemory(ptr, len, byte(val));
return ptr;
}
// @(link_name="memcmp")
// memcmp :: proc "c" (dst, src: rawptr, len: int) -> i32 {
// if dst == nil || src == nil {
// return 0;
// }
// if dst == src {
// return 0;
// }
// d, s := uintptr(dst), uintptr(src);
// n := uintptr(len);
// for i := uintptr(0); i < n; i += 1 {
// x, y := (^byte)(d+i)^, (^byte)(s+i)^;
// if x != y {
// return x < y ? -1 : +1;
// }
// }
// return 0;
// }
+5 -5
View File
@@ -198,10 +198,10 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
}
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, 0);
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, nil);
}
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil);
}
itoa :: proc(buf: []byte, i: int) -> string do return append_int(buf, i64(i), 10);
@@ -474,7 +474,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
}
i-=1; a[i] = digits[u % b];
if flags&Int_Flag.Prefix != 0 {
if flags&Int_Flag.Prefix != nil {
ok := true;
switch base {
case 2: i-=1; a[i] = 'b';
@@ -492,9 +492,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
switch {
case neg:
i-=1; a[i] = '-';
case flags&Int_Flag.Plus != 0:
case flags&Int_Flag.Plus != nil:
i-=1; a[i] = '+';
case flags&Int_Flag.Space != 0:
case flags&Int_Flag.Space != nil:
i-=1; a[i] = ' ';
}
+20
View File
@@ -712,6 +712,25 @@ deprecated_attribute :: proc() {
// foo_v1(1);
}
bit_set_type :: proc() {
using Day :: enum {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
}
Days :: distinct bit_set[Day];
d: Days;
d = Days{Sunday};
x := Tuesday;
d |= Days{Saturday, x};
fmt.println(d);
}
main :: proc() {
when true {
general_stuff();
@@ -725,5 +744,6 @@ main :: proc() {
complete_switch();
cstring_example();
deprecated_attribute();
bit_set_type();
}
}
+83 -31
View File
@@ -841,6 +841,9 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
case Type_Enum:
return false;
case Type_BitSet:
return false;
case Type_Union:
if (source->kind == Type_Union) {
TypeUnion *x = &poly->Union;
@@ -1115,8 +1118,8 @@ bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
break;
case Token_Xor:
if (!is_type_integer(type) && !is_type_boolean(type)) {
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
}
break;
@@ -1142,33 +1145,17 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
switch (op.kind) {
case Token_Sub:
case Token_SubEq:
if (!is_type_numeric(type) && !is_type_pointer(type)) {
error(op, "Operator '%.*s' is only allowed with numeric or pointer expressions", LIT(op.string));
return false;
}
#if defined(NO_POINTER_ARITHMETIC)
if (is_type_pointer(type)) {
error(o->expr, "Pointer arithmetic is not supported");
return false;
}
#else
if (is_type_pointer(type)) {
o->type = t_int;
}
if (base_type(type) == t_rawptr) {
gbString str = type_to_string(type);
error(o->expr, "Invalid pointer type for pointer arithmetic: '%s'", str);
gb_string_free(str);
if (!is_type_numeric(type)) {
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
return false;
}
break;
#endif
case Token_Mul:
case Token_Quo:
case Token_AddEq:
case Token_MulEq:
case Token_QuoEq:
case Token_AddEq:
if (!is_type_numeric(type)) {
error(op, "Operator '%.*s' is only allowed with numeric expressions", LIT(op.string));
return false;
@@ -1194,24 +1181,30 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
case Token_OrEq:
case Token_Xor:
case Token_XorEq:
if (!is_type_integer(type) && !is_type_boolean(type)) {
error(op, "Operator '%.*s' is only allowed with integers or booleans", LIT(op.string));
if (!is_type_integer(type) && !is_type_boolean(type) && !is_type_bit_set(type)) {
error(op, "Operator '%.*s' is only allowed with integers, booleans, or bit sets", LIT(op.string));
return false;
}
break;
case Token_Mod:
case Token_ModMod:
case Token_AndNot:
case Token_ModEq:
case Token_ModModEq:
case Token_AndNotEq:
if (!is_type_integer(type)) {
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
return false;
}
break;
case Token_AndNot:
case Token_AndNotEq:
if (!is_type_integer(type) && !is_type_bit_set(type)) {
error(op, "Operator '%.*s' is only allowed with integers and bit sets", LIT(op.string));
return false;
}
break;
case Token_CmpAnd:
case Token_CmpOr:
case Token_CmpAndEq:
@@ -2329,7 +2322,11 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
return;
}
Type *t = core_type(target_type);
Type *t = base_type(target_type);
if (c->in_enum_type) {
t = core_type(target_type);
}
switch (t->kind) {
case Type_Basic:
if (operand->mode == Addressing_Constant) {
@@ -4264,6 +4261,12 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
} else {
pt = type_to_string(t);
}
String prefix = {};
String prefix_sep = {};
if (proc->pkg) {
prefix = proc->pkg->name;
prefix_sep = str_lit(".");
}
String name = proc->token.string;
char const *sep = "::";
@@ -4271,7 +4274,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
sep = ":=";
}
// gb_printf_err("\t%.*s %s %s at %.*s(%td:%td) with score %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
gb_printf_err("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column);
gb_printf_err("\t%.*s%.*s%.*s %s %s at %.*s(%td:%td)\n", LIT(prefix), LIT(prefix_sep), LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column);
}
if (procs.count > 0) {
gb_printf_err("\n");
@@ -5096,9 +5099,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
switch (t->kind) {
case Type_Struct: {
if (is_type_union(t)) {
is_constant = false;
}
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
}
@@ -5111,7 +5111,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
break;
}
{ // Checker values
if (is_type_struct(t)) { // Checker values
isize field_count = t->Struct.fields.count;
isize min_field_count = t->Struct.fields.count;
for (isize i = min_field_count-1; i >= 0; i--) {
@@ -5220,6 +5220,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
}
}
}
break;
}
@@ -5409,6 +5410,39 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
break;
}
case Type_BitSet: {
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
}
Type *et = base_type(t->BitSet.base_type);
isize field_count = 0;
if (et->kind == Type_Enum) {
field_count = et->Enum.fields.count;
}
if (cl->elems[0]->kind == Ast_FieldValue) {
error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed");
} else {
for_array(index, cl->elems) {
Entity *field = nullptr;
Ast *elem = cl->elems[index];
if (elem->kind == Ast_FieldValue) {
error(elem, "'field = value' in a bit_set a literal is not allowed");
continue;
}
check_expr(c, o, elem);
if (is_constant) {
is_constant = o->mode == Addressing_Constant;
}
check_assignment(c, o, t->BitSet.base_type, str_lit("bit_set literal"));
}
}
break;
}
default: {
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
@@ -6108,6 +6142,24 @@ gbString write_expr_to_string(gbString str, Ast *node) {
str = write_expr_to_string(str, at->elem);
case_end;
case_ast_node(bf, BitFieldType, node);
str = gb_string_appendc(str, "bit_field ");
if (bf->align) {
str = gb_string_appendc(str, "#align ");
str = write_expr_to_string(str, bf->align);
}
str = gb_string_appendc(str, "{");
str = write_struct_fields_to_string(str, bf->fields);
str = gb_string_appendc(str, "}");
case_end;
case_ast_node(bs, BitSetType, node);
str = gb_string_appendc(str, "bit_set[");
str = write_expr_to_string(str, bs->base_type);
str = gb_string_appendc(str, "]");
case_end;
case_ast_node(mt, MapType, node);
str = gb_string_appendc(str, "map[");
str = write_expr_to_string(str, mt->key);
+70 -1
View File
@@ -681,6 +681,59 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node)
}
void check_bit_set_type(CheckerContext *ctx, Type *type, Ast *node) {
ast_node(bs, BitSetType, node);
GB_ASSERT(type->kind == Type_BitSet);
Type *bt = check_type_expr(ctx, bs->base_type, nullptr);
type->BitSet.base_type = bt;
if (!is_type_enum(bt)) {
error(bs->base_type, "Expected an enum type for a bit_set");
} else {
Type *et = base_type(bt);
GB_ASSERT(et->kind == Type_Enum);
if (!is_type_integer(et->Enum.base_type)) {
error(bs->base_type, "Enum type for bit_set must be an integer");
return;
}
i64 min_value = 0;
i64 max_value = 0;
BigInt v64 = {}; big_int_from_i64(&v64, 64);
for_array(i, et->Enum.fields) {
Entity *e = et->Enum.fields[i];
if (e->kind != Entity_Constant) {
continue;
}
ExactValue value = exact_value_to_integer(e->Constant.value);
GB_ASSERT(value.kind == ExactValue_Integer);
BigInt v = value.value_integer;
if (big_int_cmp(&v, &BIG_INT_ZERO) < 0) {
error(bs->base_type, "Negative enum values are not allowed in a bit_set");
return;
}
if (big_int_cmp(&v, &v64) >= 0) {
error(bs->base_type, "Enum values overe 64 are not allowed in a bit_set");
return;
}
i64 x = big_int_to_i64(&v);
min_value = gb_min(min_value, x);
max_value = gb_max(max_value, x);
}
type->BitSet.min = min_value;
type->BitSet.max = max_value;
}
}
bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
if (type == nullptr ||
type == t_invalid) {
@@ -1014,6 +1067,12 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
type = t_invalid;
}
}
if (p->flags&FieldFlag_auto_cast) {
error(name, "'auto_cast' can only be applied variable fields");
p->flags &= ~FieldFlag_auto_cast;
}
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
param->TypeName.is_type_alias = true;
} else {
@@ -1885,18 +1944,28 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
check_enum_type(ctx, *type, named_type, e);
check_close_scope(ctx);
(*type)->Enum.node = e;
ctx->in_enum_type = false;
return true;
case_end;
case_ast_node(et, BitFieldType, e);
*type = alloc_type_bit_field();
set_base_type(named_type, *type);
check_open_scope(ctx, e);
check_bit_field_type(ctx, *type, e);
return true;
case_end;
case_ast_node(bs, BitSetType, e);
*type = alloc_type_bit_set();
set_base_type(named_type, *type);
check_open_scope(ctx, e);
check_bit_set_type(ctx, *type, e);
check_close_scope(ctx);
return true;
case_end;
case_ast_node(pt, ProcType, e);
bool ips = ctx->in_polymorphic_specialization;
defer (ctx->in_polymorphic_specialization = ips);
+6
View File
@@ -1043,6 +1043,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
add_type_info_type(c, bt->Enum.base_type);
break;
case Type_BitSet:
add_type_info_type(c, bt->BitSet.base_type);
break;
case Type_Union:
add_type_info_type(c, t_int);
add_type_info_type(c, t_type_info_ptr);
@@ -1600,6 +1604,7 @@ void init_core_type_info(Checker *c) {
t_type_info_enum = find_core_type(c, str_lit("Type_Info_Enum"));
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
@@ -1621,6 +1626,7 @@ void init_core_type_info(Checker *c) {
t_type_info_enum_ptr = alloc_type_pointer(t_type_info_enum);
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
}
void init_mem_allocator(Checker *c) {
+46 -6
View File
@@ -3275,8 +3275,6 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
// boolean -> boolean/integer
if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
GB_ASSERT(src != t_llvm_bool);
irValue *b = ir_emit(proc, ir_instr_binary_op(proc, Token_NotEq, value, v_zero, t_llvm_bool));
return ir_emit(proc, ir_instr_conv(proc, irConv_zext, b, t_llvm_bool, t));
}
@@ -4247,7 +4245,7 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
}
void ir_build_stmt_list(irProcedure *proc, Array<Ast *> stmts);
void ir_build_assign_op(irProcedure *proc, irAddr const &lhs, irValue *value, TokenKind op);
bool is_double_pointer(Type *t) {
if (!is_type_pointer(t)) {
@@ -5610,8 +5608,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
Type *et = nullptr;
switch (bt->kind) {
case Type_Array: et = bt->Array.elem; break;
case Type_Slice: et = bt->Slice.elem; break;
case Type_Array: et = bt->Array.elem; break;
case Type_Slice: et = bt->Slice.elem; break;
case Type_BitSet: et = bt->BitSet.base_type; break;
}
String proc_name = {};
@@ -5821,7 +5820,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
ir_emit_store(proc, gep, fv);
}
}
break;
}
case Type_BitSet: {
i64 sz = type_size_of(type);
if (cl->elems.count > 0 && sz > 0) {
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
irValue *lower = ir_value_constant(t_int, exact_value_i64(bt->BitSet.min));
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
GB_ASSERT(elem->kind != Ast_FieldValue);
if (ir_is_elem_const(proc->module, elem, et)) {
continue;
}
irValue *expr = ir_build_expr(proc, elem);
GB_ASSERT(ir_type(expr)->kind != Type_Tuple);
Type *it = bit_set_to_int(bt);
irValue *e = ir_emit_conv(proc, expr, it);
e = ir_emit_arith(proc, Token_Sub, e, lower, it);
e = ir_emit_arith(proc, Token_Shl, v_one, e, it);
irValue *old_value = ir_emit_bitcast(proc, ir_emit_load(proc, v), it);
irValue *new_value = ir_emit_arith(proc, Token_Or, old_value, e, it);
new_value = ir_emit_bitcast(proc, new_value, type);
ir_emit_store(proc, v, new_value);
}
}
break;
}
}
return ir_addr(v);
@@ -8025,8 +8059,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
}
break;
}
}
case Type_BitSet:
ir_emit_comment(proc, str_lit("Type_Info_Bit_Set"));
tag = ir_emit_conv(proc, variant_ptr, t_type_info_bit_set_ptr);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->BitSet.base_type));
break;
}
if (tag != nullptr) {
Type *tag_type = type_deref(ir_type(tag));
+45
View File
@@ -65,6 +65,10 @@ void ir_write_i64(irFileBuffer *f, i64 i) {
String str = i64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
ir_write_string(f, str);
}
void ir_write_u64(irFileBuffer *f, u64 i) {
String str = u64_to_string(i, f->buf, IR_FILE_BUFFER_BUF_LEN-1);
ir_write_string(f, str);
}
void ir_write_big_int(irFileBuffer *f, BigInt const &x) {
i64 i = 0;
if (x.neg) {
@@ -502,6 +506,19 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
break;
}
case Type_BitSet: {
i64 align = type_align_of(t);
i64 size = type_size_of(t);
switch (size) {
case 0: ir_write_str_lit(f, "{}"); return;
case 1: ir_write_str_lit(f, "i8"); return;
case 2: ir_write_str_lit(f, "i16"); return;
case 4: ir_write_str_lit(f, "i32"); return;
case 8: ir_write_str_lit(f, "i64"); return;
default: GB_PANIC("Unknown bit_set size"); break;
}
}
}
}
@@ -766,6 +783,34 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_byte(f, '}');
if (type->Struct.is_packed) ir_write_byte(f, '>');
} else if (is_type_bit_set(type)) {
ast_node(cl, CompoundLit, value.value_compound);
if (cl->elems.count == 0) {
ir_write_str_lit(f, "zeroinitializer");
break;
}
i64 sz = type_size_of(type);
if (sz == 0) {
ir_write_str_lit(f, "zeroinitializer");
break;
}
u64 bits = 0;
for_array(i, cl->elems) {
Ast *e = cl->elems[i];
GB_ASSERT(e->kind != Ast_FieldValue);
TypeAndValue tav = e->tav;
if (tav.mode != Addressing_Constant) {
continue;
}
GB_ASSERT(tav.value.kind == ExactValue_Integer);
i64 v = big_int_to_i64(&tav.value.value_integer);
i64 lower = type->BitSet.min;
bits |= 1ull<<cast(u64)(v-lower);
}
ir_write_u64(f, bits);
} else {
ir_write_str_lit(f, "zeroinitializer");
}
+21
View File
@@ -89,6 +89,7 @@ Token ast_token(Ast *node) {
case Ast_UnionType: return node->UnionType.token;
case Ast_EnumType: return node->EnumType.token;
case Ast_BitFieldType: return node->BitFieldType.token;
case Ast_BitSetType: return node->BitSetType.token;
case Ast_MapType: return node->MapType.token;
}
@@ -344,6 +345,10 @@ Ast *clone_ast(Ast *node) {
case Ast_BitFieldType:
n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields);
n->BitFieldType.align = clone_ast(n->BitFieldType.align);
break;
case Ast_BitSetType:
n->BitSetType.base_type = clone_ast(n->BitSetType.base_type);
break;
case Ast_MapType:
n->MapType.count = clone_ast(n->MapType.count);
n->MapType.key = clone_ast(n->MapType.key);
@@ -922,6 +927,13 @@ Ast *ast_bit_field_type(AstFile *f, Token token, Array<Ast *> fields, Ast *align
return result;
}
Ast *ast_bit_set_type(AstFile *f, Token token, Ast *base_type) {
Ast *result = alloc_ast_node(f, Ast_BitSetType);
result->BitSetType.token = token;
result->BitSetType.base_type = base_type;
return result;
}
Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
Ast *result = alloc_ast_node(f, Ast_MapType);
result->MapType.token = token;
@@ -1962,6 +1974,15 @@ Ast *parse_operand(AstFile *f, bool lhs) {
return ast_bit_field_type(f, token, fields, align);
} break;
case Token_bit_set: {
Token token = expect_token(f, Token_bit_set);
Token open = expect_token(f, Token_OpenBracket);
Ast *base_type = parse_type(f);
Token close = expect_token(f, Token_CloseBracket);
return ast_bit_set_type(f, token, base_type);
}
default: {
#if 0
Ast *type = parse_type_or_ident(f);
+4
View File
@@ -480,6 +480,10 @@ AST_KIND(_TypeBegin, "", bool) \
Array<Ast *> fields; /* FieldValue with : */ \
Ast * align; \
}) \
AST_KIND(BitSetType, "bit set type", struct { \
Token token; \
Ast * base_type; \
}) \
AST_KIND(MapType, "map type", struct { \
Token token; \
Ast *count; \
+1
View File
@@ -105,6 +105,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_bit_field, "bit_field"), \
TOKEN_KIND(Token_bit_set, "bit_set"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
+67
View File
@@ -178,6 +178,11 @@ struct TypeStruct {
Scope * scope; \
i64 custom_align; \
}) \
TYPE_KIND(BitSet, struct { \
Type *base_type; \
i64 min; \
i64 max; \
}) \
@@ -376,6 +381,7 @@ gb_global Type *t_type_info_union = nullptr;
gb_global Type *t_type_info_enum = nullptr;
gb_global Type *t_type_info_map = nullptr;
gb_global Type *t_type_info_bit_field = nullptr;
gb_global Type *t_type_info_bit_set = nullptr;
gb_global Type *t_type_info_named_ptr = nullptr;
gb_global Type *t_type_info_integer_ptr = nullptr;
@@ -398,6 +404,7 @@ gb_global Type *t_type_info_union_ptr = nullptr;
gb_global Type *t_type_info_enum_ptr = nullptr;
gb_global Type *t_type_info_map_ptr = nullptr;
gb_global Type *t_type_info_bit_field_ptr = nullptr;
gb_global Type *t_type_info_bit_set_ptr = nullptr;
gb_global Type *t_allocator = nullptr;
gb_global Type *t_allocator_ptr = nullptr;
@@ -607,6 +614,10 @@ Type *alloc_type_bit_field() {
Type *t = alloc_type(Type_BitField);
return t;
}
Type *alloc_type_bit_set() {
Type *t = alloc_type(Type_BitSet);
return t;
}
@@ -903,6 +914,10 @@ bool is_type_bit_field_value(Type *t) {
t = base_type(t);
return (t->kind == Type_BitFieldValue);
}
bool is_type_bit_set(Type *t) {
t = base_type(t);
return (t->kind == Type_BitSet);
}
bool is_type_map(Type *t) {
t = base_type(t);
return t->kind == Type_Map;
@@ -963,6 +978,19 @@ bool is_type_valid_for_keys(Type *t) {
return false;
}
Type *bit_set_to_int(Type *t) {
GB_ASSERT(is_type_bit_set(t));
i64 sz = type_size_of(t);
switch (sz) {
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
}
GB_PANIC("Unknown bit_set size");
return nullptr;
}
bool is_type_indexable(Type *t) {
Type *bt = base_type(t);
@@ -1108,6 +1136,10 @@ bool type_has_nil(Type *t) {
}
return false;
} break;
case Type_Enum:
case Type_BitSet:
case Type_BitField:
return true;
case Type_Slice:
case Type_Proc:
case Type_Pointer:
@@ -1158,6 +1190,9 @@ bool is_type_comparable(Type *t) {
return is_type_comparable(t->Array.elem);
case Type_Proc:
return true;
case Type_BitSet:
return true;
}
return false;
}
@@ -1237,6 +1272,12 @@ bool are_types_identical(Type *x, Type *y) {
}
break;
case Type_BitSet:
if (y->kind == Type_BitSet) {
return are_types_identical(x->BitSet.base_type, y->BitSet.base_type);
}
break;
case Type_Enum:
return x == y; // NOTE(bill): All enums are unique
@@ -2023,6 +2064,16 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
}
return gb_clamp(next_pow2(align), 1, build_context.max_align);
} break;
case Type_BitSet: {
i64 bits = t->BitSet.max - t->BitSet.min + 1;
if (bits == 0) return 0;
if (bits <= 8) return 1;
if (bits <= 16) return 2;
if (bits <= 32) return 4;
if (bits <= 64) return 8;
GB_PANIC("unknown bit_set size");
}
}
// return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align);
@@ -2239,6 +2290,16 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
GB_ASSERT((bits%8) == 0);
return bits/8;
} break;
case Type_BitSet: {
i64 bits = t->BitSet.max - t->BitSet.min + 1;
if (bits == 0) return 0;
if (bits <= 8) return 1;
if (bits <= 16) return 2;
if (bits <= 32) return 4;
if (bits <= 64) return 8;
GB_PANIC("unknown bit_set size");
}
}
// Catch all
@@ -2549,6 +2610,12 @@ gbString write_type_to_string(gbString str, Type *type) {
case Type_BitFieldValue:
str = gb_string_append_fmt(str, "(bit field value with %d bits)", cast(int)type->BitFieldValue.bits);
break;
case Type_BitSet:
str = gb_string_appendc(str, "bit_field[");
str = write_type_to_string(str, type->BitSet.base_type);
str = gb_string_appendc(str, "]");
break;
}
return str;