From 2c0e59ae064b273899a56cb8d3c53b6967466fa2 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 3 Jun 2017 22:27:23 +0100 Subject: [PATCH] =?UTF-8?q?`bit=5Ffield`;=20Lexical=20sugar=20operators=20?= =?UTF-8?q?=E2=89=A0=20=E2=89=A4=20=E2=89=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example below: // See: https://en.wikipedia.org/wiki/Bit_field BoxProps :: bit_field { opaque : 1, fill_colour : 3, _ : 4, show_border : 1, border_colour : 3, border_style : 2, _ : 2, width : 4, height : 4, _ : 8, } --- core/_preload.odin | 5 + core/_soft_numbers.odin | 123 +++++++++++++++++ core/fmt.odin | 12 +- core/math.odin | 11 +- core/strconv.odin | 180 +++++++++++++++++++++---- src/check_decl.c | 4 + src/check_expr.c | 140 ++++++++++++++++++- src/check_stmt.c | 37 ++++- src/checker.c | 33 +++-- src/entity.c | 23 ++-- src/ir.c | 291 ++++++++++++++++++++++++++++++++++------ src/ir_print.c | 19 ++- src/parser.c | 63 +++++++++ src/ssa.c | 2 +- src/tokenizer.c | 5 + src/types.c | 141 ++++++++++++++++++- 16 files changed, 979 insertions(+), 110 deletions(-) diff --git a/core/_preload.odin b/core/_preload.odin index 5c678d31a..4803c8535 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -98,6 +98,11 @@ TypeInfo :: union { generated_struct: ^TypeInfo, count: int, // == 0 if dynamic }, + BitField{ + names: []string, + bits: []i32, + offsets: []i32, + }, } diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin index f6a14db0b..fd7dc2905 100644 --- a/core/_soft_numbers.odin +++ b/core/_soft_numbers.odin @@ -67,3 +67,126 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_odin #link_nam return q; } +/* +__f16_to_f32 :: proc(f: f16) -> f32 #cc_odin #no_inline #link_name "__gnu_h2f_ieee" { + when true { + // Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ + FP32 :: raw_union {u: u32, f: f32}; + + magic, was_infnan: FP32; + magic.u = (254-15) << 23; + was_infnan.u = (127+16) << 23; + + hu := transmute(u16, f); + + o := FP32{}; + + o.u = u32((hu & 0x7fff) << 13); + o.f *= magic.f; + if o.f >= was_infnan.f { + o.u |= 255 << 23; + } + o.u |= u32(hu & 0x8000) << 16; + return o.f; + } else { + return 0; + } +} +__f32_to_f16 :: proc(f_: f32) -> f16 #cc_odin #no_inline #link_name "__gnu_f2h_ieee" { + when false { + // Source: https://gist.github.com/rygorous/2156668 + FP16 :: raw_union {u: u16, f: f16}; + FP32 :: raw_union {u: u32, f: f32}; + + f32infty, f16infty, magic: FP32; + f32infty.u = 255<<23; + f16infty.u = 31<<23; + magic.u = 15<<23; + + sign_mask :: u32(0x80000000); + round_mask :: ~u32(0x0fff); + + f := transmute(FP32, f_); + + o: FP16; + sign := f.u & sign_mask; + f.u ~= sign; + + // NOTE all the integer compares in this function can be safely + // compiled into signed compares since all operands are below + // 0x80000000. Important if you want fast straight SSE2 code + // (since there's no unsigned PCMPGTD). + + if f.u >= f32infty.u { // Inf or NaN (all exponent bits set) + o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf + } else { // (De)normalized number or zero + f.u &= round_mask; + f.f *= magic.f; + f.u -= round_mask; + if f.u > f16infty.u { + f.u = f16infty.u; // Clamp to signed infinity if overflowed + } + + o.u = u16(f.u >> 13); // Take the bits! + } + + o.u |= u16(sign >> 16); + return o.f; + } else { + f := transmute(u32, f_); + h: u16; + hs, he, hf: u16; + + fs := (f >> 31) & 1; + fe := (f >> 23) & 0b1111_1111; + ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111; + + add_one := false; + + if (fe == 0) { + he = 0; + } else if (fe == 255) { + he = 31; + hf = ff != 0 ? 0x200 : 0; + } else { + ne := fe - 127 + 15; + if ne >= 31 { + he = 31; + } else if ne <= 0 { + if (14-ne) <= 24 { + mant := ff | 0x800000; + hf = u16(mant >> (14-ne)); + + if (mant >> (13-ne)) & 1 != 0 { + add_one = true; + } + } + } else { + he = u16(ne); + hf = u16(ff >> 13); + if ff&0x1000 != 0 { + add_one = true; + } + } + } + + + hs = u16(hs); + h |= (he&0b0001_1111)<<10; + h |= (hf&0b0011_1111_1111); + if add_one { + h++; + } + h |= (hs&1) << 15; + return transmute(f16, h); + } +} + +__f64_to_f16 :: proc(f: f64) -> f16 #cc_odin #no_inline #link_name "__truncdfhf2" { + return __f32_to_f16(f32(f)); +} + +__f16_to_f64 :: proc(f: f16) -> f64 #cc_odin #no_inline { + return f64(__f16_to_f32(f)); +} +*/ diff --git a/core/fmt.odin b/core/fmt.odin index 4b056634e..c2f6f1e07 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -197,11 +197,13 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { } case Float: match info.size { + case 2: write_string(buf, "f16"); case 4: write_string(buf, "f32"); case 8: write_string(buf, "f64"); } case Complex: match info.size { + case 4: write_string(buf, "complex32"); case 8: write_string(buf, "complex64"); case 16: write_string(buf, "complex128"); } @@ -625,7 +627,6 @@ fmt_float :: proc(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) { case: fmt_bad_verb(fi, verb); - return; } } fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) { @@ -928,6 +929,11 @@ fmt_complex :: proc(fi: ^FmtInfo, c: complex128, bits: int, verb: rune) { _u128_to_lo_hi :: proc(a: u128) -> (lo, hi: u64) { return u64(a), u64(a>>64); } _i128_to_lo_hi :: proc(a: u128) -> (lo: u64 hi: i64) { return u64(a), i64(a>>64); } + +do_foo :: proc(fi: ^FmtInfo, f: f64) { + fmt_string(fi, "Hellope$%!", 'v'); +} + fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) { if arg == nil { write_string(fi.buf, ""); @@ -950,8 +956,10 @@ fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) { match a in base_arg { case any: fmt_arg(fi, a, verb); case bool: fmt_bool(fi, a, verb); + case f32: fmt_float(fi, f64(a), 32, verb); - case f64: fmt_float(fi, a, 64, verb); + case f64: fmt_float(fi, a, 64, verb); + case complex64: fmt_complex(fi, complex128(a), 64, verb); case complex128: fmt_complex(fi, a, 128, verb); diff --git a/core/math.odin b/core/math.odin index f5edd76ee..9e49e6eb6 100644 --- a/core/math.odin +++ b/core/math.odin @@ -43,16 +43,15 @@ pow :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32"; pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64"; -lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; } -lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; } +lerp :: proc(a, b, t: f32) -> (x: f32) { return a*(1-t) + b*t; } +lerp :: proc(a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; } +unlerp :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); } +unlerp :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); } + sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; } sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; } -bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16"; -bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; -bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64"; - fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32"; fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64"; diff --git a/core/strconv.odin b/core/strconv.odin index b04fdb387..b249029d6 100644 --- a/core/strconv.odin +++ b/core/strconv.odin @@ -28,35 +28,164 @@ _digit_value :: proc(r: rune) -> (int) { return v; } -parse_i64 :: proc(s: string, base: int) -> i64 { - result: i64; +parse_i128 :: proc(s: string) -> i128 { + neg := false; + if len(s) > 1 { + match s[0] { + case '-': + neg = true; + s = s[1..]; + case '+': + s = s[1..]; + } + } + + + base: i128 = 10; + if len(s) > 2 && s[0] == '0' { + match s[1] { + case 'b': base = 2; s = s[2..]; + case 'o': base = 8; s = s[2..]; + case 'd': base = 10; s = s[2..]; + case 'z': base = 12; s = s[2..]; + case 'x': base = 16; s = s[2..]; + } + } + + + value: i128; for r in s { - v := _digit_value(r); + if r == '_' { + continue; + } + + v := i128(_digit_value(r)); if v >= base { break; } - result *= i64(base); - result += i64(v); + value *= base; + value += v; } - return result; + + return neg ? -value : value; } -parse_u64 :: proc(s: string, base: int) -> u64 { - result: u64; + +parse_u128 :: proc(s: string) -> u128 { + neg := false; + if len(s) > 1 && s[0] == '+' { + s = s[1..]; + } + + + base: = u128(10); + if len(s) > 2 && s[0] == '0' { + match s[1] { + case 'b': base = 2; s = s[2..]; + case 'o': base = 8; s = s[2..]; + case 'd': base = 10; s = s[2..]; + case 'z': base = 12; s = s[2..]; + case 'x': base = 16; s = s[2..]; + } + } + + + value: u128; for r in s { - v := _digit_value(r); + if r == '_' { + continue; + } + + v := u128(_digit_value(r)); if v >= base { break; } - result *= u64(base); - result += u64(v); + value *= base; + value += u128(v); } - return result; + + return neg ? -value : value; } -parse_int :: proc(s: string, base: int) -> int { - return int(parse_i64(s, base)); + + +parse_int :: proc(s: string) -> int { + return int(parse_i128(s)); } parse_uint :: proc(s: string, base: int) -> uint { - return uint(parse_u64(s, base)); + return uint(parse_u128(s)); +} + +parse_f64 :: proc(s: string) -> f64 { + i := 0; + + sign: f64 = 1; + match s[i] { + case '-': i++; sign = -1; + case '+': i++; + } + + value: f64 = 0; + for ; i < len(s); i++ { + r := rune(s[i]); + if r == '_' { + continue; + } + v := _digit_value(r); + if v >= 10 { + break; + } + value *= 10; + value += f64(v); + } + + if s[i] == '.' { + pow10: f64 = 10; + i++; + + for ; i < len(s); i++ { + r := rune(s[i]); + if r == '_' { + continue; + } + v := _digit_value(r); + if v >= 10 { + break; + } + value += f64(v)/pow10; + pow10 *= 10; + } + } + + frac := false; + scale: f64 = 1; + + if s[i] == 'e' || s[i] == 'E' { + i++; + + match s[i] { + case '-': i++; frac = true; + case '+': i++; + } + + exp: u32 = 0; + for ; i < len(s); i++ { + r := rune(s[i]); + if r == '_' { + continue; + } + d := u32(_digit_value(r)); + if d >= 10 { + break; + } + exp = exp * 10 + d; + } + if exp > 308 { exp = 308; } + + for exp >= 50 { scale *= 1e50; exp -= 50; } + for exp >= 8 { scale *= 1e8; exp -= 8; } + for exp > 0 { scale *= 10; exp -= 1; } + } + + return sign * (frac ? (value/scale) : (value*scale)); } @@ -81,7 +210,7 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str -Decimal_Slice :: struct { +DecimalSlice :: struct { digits: []byte, count: int, decimal_point: int, @@ -94,8 +223,9 @@ Float_Info :: struct { bias: int, } -f32_info := Float_Info{23, 8, -127}; -f64_info := Float_Info{52, 11, -1023}; +_f16_info := Float_Info{10, 5, -15}; +_f32_info := Float_Info{23, 8, -127}; +_f64_info := Float_Info{52, 11, -1023}; generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte { @@ -104,10 +234,10 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ match bit_size { case 32: bits = u64(transmute(u32, f32(val))); - flt = &f32_info; + flt = &_f32_info; case 64: bits = transmute(u64, val); - flt = &f64_info; + flt = &_f64_info; case: panic("strconv: invalid bit_size"); } @@ -142,11 +272,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ d := &d_; assign(d, mant); shift(d, exp - int(flt.mantbits)); - digs: Decimal_Slice; + digs: DecimalSlice; shortest := prec < 0; if shortest { round_shortest(d, mant, exp, flt); - digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; + digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; match fmt { case 'e', 'E': prec = digs.count-1; case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0); @@ -163,14 +293,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ round(d, prec); } - digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; + digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; } return format_digits(buf, shortest, neg, digs, prec, fmt); } -format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte { +format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte { match fmt { case 'f', 'F': append(buf, neg ? '-' : '+'); @@ -190,7 +320,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic // fractional part if prec > 0 { append(buf, '.'); - for i in 0..prec { + for i in 0..type = t; } diff --git a/src/check_expr.c b/src/check_expr.c index 468598caf..9b23e57e4 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -192,6 +192,18 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { return 1; } + + if (is_type_bit_field_value(operand->type) && is_type_integer(type)) { + Type *bfv = base_type(operand->type); + i32 bits = bfv->BitFieldValue.bits; + i32 size = next_pow2((bits+7)/8); + i32 dst_size = type_size_of(c->allocator, type); + i32 diff = gb_abs(dst_size - size); + // TODO(bill): figure out a decent rule here + return 1; + } + + if (check_is_assignable_to_using_subtype(operand->type, type)) { return 4; } @@ -301,10 +313,10 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } } - if (type == NULL) { return; } + if (!check_is_assignable_to(c, operand, type)) { gbString type_str = type_to_string(type); gbString op_type_str = type_to_string(operand->type); @@ -901,6 +913,119 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } +void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, AstNode *node) { + ast_node(bft, BitFieldType, node); + GB_ASSERT(is_type_bit_field(bit_field_type)); + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + + + MapEntity entity_map = {0}; // Key: String + map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(bft->fields.count)); + + isize field_count = 0; + Entity **fields = gb_alloc_array(c->allocator, Entity *, bft->fields.count); + u32 * sizes = gb_alloc_array(c->allocator, u32, bft->fields.count); + u32 * offsets = gb_alloc_array(c->allocator, u32, bft->fields.count); + + u32 curr_offset = 0; + for_array(i, bft->fields) { + AstNode *field = bft->fields.e[i]; + GB_ASSERT(field->kind == AstNode_FieldValue); + AstNode *ident = field->FieldValue.field; + AstNode *value = field->FieldValue.value; + + if (ident->kind != AstNode_Ident) { + error_node(field, "A bit field value's name must be an identifier"); + continue; + } + String name = ident->Ident.string; + + Operand o = {0}; + check_expr(c, &o, value); + if (o.mode != Addressing_Constant) { + error_node(value, "Bit field bit size must be a constant"); + continue; + } + ExactValue v = exact_value_to_integer(o.value); + if (v.kind != ExactValue_Integer) { + error_node(value, "Bit field bit size must be a constant integer"); + continue; + } + i64 bits = i128_to_i64(v.value_integer); + if (bits < 0 || bits > 128) { + error_node(value, "Bit field's bit size must be within the range 1..<128, got %lld", cast(long long)bits); + continue; + } + + Type *value_type = make_type_bit_field_value(c->allocator, bits); + Entity *e = make_entity_variable(c->allocator, bit_field_type->BitField.scope, ident->Ident, value_type, false); + e->identifier = ident; + e->flags |= EntityFlag_BitFieldValue; + + HashKey key = hash_string(name); + if (str_ne(name, str_lit("_")) && + map_entity_get(&entity_map, key) != NULL) { + error_node(ident, "`%.*s` is already declared in this bit field", LIT(name)); + } else { + map_entity_set(&entity_map, key, e); + add_entity(c, c->context.scope, NULL, e); + add_entity_use(c, field, e); + + fields [field_count] = e; + offsets[field_count] = curr_offset; + sizes [field_count] = bits; + field_count++; + + curr_offset += bits; + } + } + GB_ASSERT(field_count <= bft->fields.count); + gb_temp_arena_memory_end(tmp); + + bit_field_type->BitField.fields = fields; + bit_field_type->BitField.field_count = field_count; + bit_field_type->BitField.sizes = sizes; + bit_field_type->BitField.offsets = offsets; + + + if (bft->align != NULL) { + Operand o = {0}; + check_expr(c, &o, bft->align); + if (o.mode != Addressing_Constant) { + if (o.mode != Addressing_Invalid) { + error_node(bft->align, "#align must be a constant"); + } + return; + } + + Type *type = base_type(o.type); + if (is_type_untyped(type) || is_type_integer(type)) { + if (o.value.kind == ExactValue_Integer) { + i64 align = i128_to_i64(o.value.value_integer); + if (align < 1 || !gb_is_power_of_two(align)) { + error_node(bft->align, "#align must be a power of 2, got %lld", align); + return; + } + + // NOTE(bill): Success!!! + i64 custom_align = gb_clamp(align, 1, build_context.max_align); + if (custom_align < align) { + warning_node(bft->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align); + } + bit_field_type->BitField.custom_align = custom_align; + return; + } + } + + error_node(bft->align, "#align must be an integer"); + return; + } +} + + + + Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) { if (_params == NULL) { return NULL; @@ -1766,6 +1891,15 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ return true; case_end; + case_ast_node(et, BitFieldType, e); + *type = make_type_bit_field(c->allocator); + set_base_type(named_type, *type); + check_open_scope(c, e); + check_bit_field_type(c, *type, named_type, e); + check_close_scope(c); + return true; + case_end; + case_ast_node(pt, ProcType, e); *type = alloc_type(c->allocator, Type_Proc); set_base_type(named_type, *type); @@ -1985,7 +2119,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type if (s < 128) { umax = u128_sub(u128_shl(U128_ONE, s), U128_ONE); } else { - // IMPORTANT TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats + // IMPORTANT TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit floats s = 128; } i128 imax = i128_shl(I128_ONE, s-1ll); @@ -2021,6 +2155,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type switch (type->Basic.kind) { + // case Basic_f16: case Basic_f32: case Basic_f64: return true; @@ -4080,6 +4215,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id BasicKind kind = core_type(x.type)->Basic.kind; switch (kind) { + // case Basic_f16: operand->type = t_complex32; break; case Basic_f32: operand->type = t_complex64; break; case Basic_f64: operand->type = t_complex128; break; case Basic_UntypedFloat: operand->type = t_untyped_complex; break; diff --git a/src/check_stmt.c b/src/check_stmt.c index e00ba4bc1..d9639a11e 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -207,7 +207,6 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { return NULL; } - if (rhs->mode == Addressing_Overload) { isize overload_count = rhs->overload_count; Entity **procs = rhs->overload_entities; @@ -256,8 +255,42 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { case Addressing_Invalid: return NULL; - case Addressing_Variable: + case Addressing_Variable: { + if (is_type_bit_field_value(lhs.type)) { + Type *lt = base_type(lhs.type); + i64 lhs_bits = lt->BitFieldValue.bits; + if (rhs->mode == Addressing_Constant) { + ExactValue v = exact_value_to_integer(rhs->value); + if (v.kind == ExactValue_Integer) { + i128 i = v.value_integer; + u128 u = *cast(u128 *)&i; + u128 umax = U128_NEG_ONE; + if (lhs_bits < 128) { + umax = u128_sub(u128_shl(U128_ONE, lhs_bits), U128_ONE); + } + i128 imax = i128_shl(I128_ONE, lhs_bits-1ll); + + bool ok = false; + ok = !(u128_lt(u, U128_ZERO) || u128_gt(u, umax)); + + if (ok) { + return rhs->type; + } + } + } else if (is_type_integer(rhs->type)) { + // TODO(bill): Any other checks? + return rhs->type; + } + gbString lhs_expr = expr_to_string(lhs.expr); + gbString rhs_expr = expr_to_string(rhs->expr); + error_node(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr); + gb_string_free(rhs_expr); + gb_string_free(lhs_expr); + return NULL; + } break; + } + case Addressing_MapIndex: { AstNode *ln = unparen_expr(lhs_node); if (ln->kind == AstNode_IndexExpr) { diff --git a/src/checker.c b/src/checker.c index 47842d913..a7f8ec950 100644 --- a/src/checker.c +++ b/src/checker.c @@ -126,19 +126,19 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { #include "types.c" typedef enum AddressingMode { - Addressing_Invalid, // invalid addressing mode - Addressing_NoValue, // no value (void in C) - Addressing_Value, // computed value (rvalue) - Addressing_Immutable, // immutable computed value (const rvalue) - Addressing_Variable, // addressable variable (lvalue) - Addressing_Constant, // constant - Addressing_Type, // type - Addressing_Builtin, // built-in procedure - Addressing_Overload, // overloaded procedure - Addressing_MapIndex, // map index expression - - // lhs: acts like a Variable - // rhs: acts like OptionalOk - Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check) + Addressing_Invalid, // invalid addressing mode + Addressing_NoValue, // no value (void in C) + Addressing_Value, // computed value (rvalue) + Addressing_Immutable, // immutable computed value (const rvalue) + Addressing_Variable, // addressable variable (lvalue) + Addressing_Constant, // constant + Addressing_Type, // type + Addressing_Builtin, // built-in procedure + Addressing_Overload, // overloaded procedure + Addressing_MapIndex, // map index expression - + // lhs: acts like a Variable + // rhs: acts like OptionalOk + Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check) } AddressingMode; // Operand is used as an intermediate value whilst checking @@ -947,6 +947,9 @@ void add_type_info_type(Checker *c, Type *t) { return; } t = default_type(t); + if (is_type_bit_field_value(t)) { + t = default_bit_field_value_type(t); + } if (is_type_untyped(t)) { return; // Could be nil } @@ -1200,7 +1203,7 @@ void init_preload(Checker *c) { - if (record->variant_count != 21) { + if (record->variant_count != 22) { compiler_error("Invalid `TypeInfo` layout"); } t_type_info_named = record->variants[ 1]->type; @@ -1223,6 +1226,7 @@ void init_preload(Checker *c) { t_type_info_union = record->variants[18]->type; t_type_info_enum = record->variants[19]->type; t_type_info_map = record->variants[20]->type; + t_type_info_bit_field = record->variants[21]->type; t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); @@ -1244,6 +1248,7 @@ void init_preload(Checker *c) { t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union); t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum); t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map); + t_type_info_bit_field_ptr = make_type_pointer(c->allocator, t_type_info_bit_field); } if (t_allocator == NULL) { diff --git a/src/entity.c b/src/entity.c index ddc170597..f029685c3 100644 --- a/src/entity.c +++ b/src/entity.c @@ -33,17 +33,18 @@ String const entity_strings[] = { }; typedef enum EntityFlag { - EntityFlag_Visited = 1<<0, - EntityFlag_Used = 1<<1, - EntityFlag_Using = 1<<2, - EntityFlag_Field = 1<<3, - EntityFlag_Param = 1<<4, - EntityFlag_VectorElem = 1<<5, - EntityFlag_Ellipsis = 1<<6, - EntityFlag_NoAlias = 1<<7, - EntityFlag_TypeField = 1<<8, - EntityFlag_Value = 1<<9, - EntityFlag_Sret = 1<<10, + EntityFlag_Visited = 1<<0, + EntityFlag_Used = 1<<1, + EntityFlag_Using = 1<<2, + EntityFlag_Field = 1<<3, + EntityFlag_Param = 1<<4, + EntityFlag_VectorElem = 1<<5, + EntityFlag_Ellipsis = 1<<6, + EntityFlag_NoAlias = 1<<7, + EntityFlag_TypeField = 1<<8, + EntityFlag_Value = 1<<9, + EntityFlag_Sret = 1<<10, + EntityFlag_BitFieldValue = 1<<11, } EntityFlag; // Zero value means the overloading process is not yet done diff --git a/src/ir.c b/src/ir.c index 8864e1c45..10d744f20 100644 --- a/src/ir.c +++ b/src/ir.c @@ -404,6 +404,7 @@ typedef enum irAddrKind { irAddr_Default, // irAddr_Vector, irAddr_Map, + irAddr_BitField, } irAddrKind; typedef struct irAddr { @@ -415,6 +416,9 @@ typedef struct irAddr { Type * map_type; Type * map_result; }; + struct { + i32 bit_field_value_index; + }; }; // union { // struct { irValue *index; } Vector; @@ -434,6 +438,12 @@ irAddr ir_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_re return v; } +irAddr ir_addr_bit_field(irValue *addr, isize bit_field_value_index) { + irAddr v = {irAddr_BitField, addr}; + v.bit_field_value_index = bit_field_value_index; + return v; +} + typedef enum irDebugEncoding { irDebugBasicEncoding_Invalid = 0, @@ -1078,9 +1088,12 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) { irValue *ir_const_int(gbAllocator a, i64 i) { return ir_value_constant(a, t_int, exact_value_i64(i)); } -irValue *ir_const_i32(gbAllocator a, i64 i) { +irValue *ir_const_i32(gbAllocator a, i32 i) { return ir_value_constant(a, t_i32, exact_value_i64(i)); } +irValue *ir_const_u32(gbAllocator a, u32 i) { + return ir_value_constant(a, t_u32, exact_value_i64(i)); +} irValue *ir_const_i64(gbAllocator a, i64 i) { return ir_value_constant(a, t_i64, exact_value_i64(i)); } @@ -1734,12 +1747,82 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T } +irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset); +irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type); + irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == NULL) { return NULL; } if (addr.kind == irAddr_Map) { return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); + } else if (addr.kind == irAddr_BitField) { + gbAllocator a = proc->module->allocator; + + Type *bft = base_type(type_deref(ir_type(addr.addr))); + GB_ASSERT(is_type_bit_field(bft)); + i32 value_index = addr.bit_field_value_index; + i32 offset = bft->BitField.offsets[value_index]; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + + i32 byte_index = offset / 8; + i32 bit_inset = offset % 8; + + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + if (size_in_bytes == 0) { + GB_ASSERT(size_in_bits == 0); + return NULL; + } + + Type *int_type = NULL; + switch (size_in_bytes) { + case 1: int_type = t_u8; break; + case 2: int_type = t_u16; break; + case 4: int_type = t_u32; break; + case 8: int_type = t_u64; break; + case 16: int_type = t_u128; break; + } + GB_ASSERT(int_type != NULL); + + value = ir_emit_conv(proc, value, int_type); + + irValue *bytes = ir_emit_conv(proc, addr.addr, t_u8_ptr); + bytes = ir_emit_ptr_offset(proc, bytes, ir_const_int(a, byte_index)); + + + if (bit_inset == 0) { + irValue *v = value; + i32 sa = 8*size_in_bytes - size_in_bits; + if (sa > 0) { + irValue *shift_amount = ir_const_int(a, sa); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Shr, v, shift_amount, int_type); + } + irValue *ptr = ir_emit_conv(proc, bytes, make_type_pointer(a, int_type)); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, ptr), v, int_type); + return ir_emit_store(proc, ptr, v); + } + + + // First byte + { + i32 sa = 8 - bit_inset; + irValue *shift_amount = ir_const_int(a, sa); + irValue *v = ir_emit_conv(proc, value, t_u8); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, bytes), v, int_type); + ir_emit_store(proc, bytes, v); + + } + + // Remaining bytes + { + irValue *shift_amount = ir_const_int(a, bit_inset); + irValue *ptr = ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), make_type_pointer(a, int_type)); + irValue *v = ir_emit_arith(proc, Token_Shr, value, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, ptr), v, int_type); + return ir_emit_store(proc, ptr, v); + } } irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); @@ -1787,12 +1870,62 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { irValue *single = ir_emit_struct_ep(proc, v, 0); return ir_emit_load(proc, single); } + } else if (addr.kind == irAddr_BitField) { + gbAllocator a = proc->module->allocator; + + + Type *bft = base_type(type_deref(ir_type(addr.addr))); + GB_ASSERT(is_type_bit_field(bft)); + i32 value_index = addr.bit_field_value_index; + i32 offset = bft->BitField.offsets[value_index]; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + + i32 byte_index = offset / 8; + i32 bit_inset = offset % 8; + + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + if (size_in_bytes == 0) { + GB_ASSERT(size_in_bits == 0); + return ir_const_i32(a, 0); + } + + Type *int_type = NULL; + switch (size_in_bytes) { + case 1: int_type = t_u8; break; + case 2: int_type = t_u16; break; + case 4: int_type = t_u32; break; + case 8: int_type = t_u64; break; + case 16: int_type = t_u128; break; + } + GB_ASSERT(int_type != NULL); + + + irValue *bytes = ir_emit_conv(proc, addr.addr, t_u8_ptr); + bytes = ir_emit_ptr_offset(proc, bytes, ir_const_int(a, byte_index)); + + Type *int_ptr = make_type_pointer(a, int_type); + + if (bit_inset == 0) { + irValue *v = ir_emit_load(proc, ir_emit_conv(proc, bytes, int_ptr)); + i32 sa = 8*size_in_bytes - size_in_bits; + if (sa > 0) { + irValue *shift_amount = ir_const_int(a, sa); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Shr, v, shift_amount, int_type); + } + return v; + } + + + irValue *first_byte = ir_emit_load(proc, bytes); + irValue *res = ir_emit_arith(proc, Token_Shr, first_byte, ir_const_int(a, 8 - bit_inset), int_type); + + irValue *remaining_bytes = ir_emit_load(proc, ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), int_ptr)); + remaining_bytes = ir_emit_arith(proc, Token_Shl, remaining_bytes, ir_const_int(a, bit_inset), int_type); + return ir_emit_arith(proc, Token_Or, res, remaining_bytes, int_type); + } - // if (addr.kind == irAddr_Vector) { - // irValue *v = ir_emit_load(proc, addr.addr); - // return ir_emit(proc, ir_instr_extract_element(proc, v, addr.Vector.index)); - // } Type *t = base_type(ir_type(addr.addr)); if (t->kind == Type_Proc) { // NOTE(bill): Imported procedures don't require a load as they are pointers @@ -2664,8 +2797,39 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { // float -> float if (is_type_float(src) && is_type_float(dst)) { + gbAllocator a = proc->module->allocator; i64 sz = type_size_of(proc->module->allocator, src); i64 dz = type_size_of(proc->module->allocator, dst); + if (sz == 2) { + switch (dz) { + case 2: return value; + case 4: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__gnu_h2f_ieee", args, 1); + } break; + case 8: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__f16_to_f64", args, 1); + } break; + } + } else if (dz == 2) { + switch (sz) { + case 2: return value; + case 4: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__gnu_f2h_ieee", args, 1); + } break; + case 8: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__truncdfhf2", args, 1); + } break; + } + } + irConvKind kind = irConv_fptrunc; if (dz >= sz) { kind = irConv_fpext; @@ -2878,6 +3042,7 @@ bool ir_is_type_aggregate(Type *t) { case Basic_any: return true; + // case Basic_complex32: case Basic_complex64: case Basic_complex128: return true; @@ -3139,7 +3304,7 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) { } if (entry_index < 0) { - compiler_error("Type_Info for `%s` could not be found", type_to_string(type)); + compiler_error("TypeInfo for `%s` could not be found", type_to_string(type)); } return entry_index; } @@ -4668,9 +4833,18 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Selection sel = lookup_field(proc->module->allocator, type, selector, false); GB_ASSERT(sel.entity != NULL); - irValue *a = ir_build_addr(proc, se->expr).addr; - a = ir_emit_deep_field_gep(proc, a, sel); - return ir_addr(a); + if (sel.entity->type->kind == Type_BitFieldValue) { + irAddr addr = ir_build_addr(proc, se->expr); + Type *bft = type_deref(ir_addr_type(addr)); + GB_ASSERT(is_type_bit_field(bft)); + GB_ASSERT(sel.index.count == 1); + i32 index = sel.index.e[0]; + return ir_addr_bit_field(addr.addr, index); + } else { + irValue *a = ir_build_addr(proc, se->expr).addr; + a = ir_emit_deep_field_gep(proc, a, sel); + return ir_addr(a); + } } else { Type *type = type_deref(type_of_expr(proc->module->info, se->expr)); Type *selector_type = base_type(type_of_expr(proc->module->info, se->selector)); @@ -7311,7 +7485,7 @@ void ir_gen_tree(irGen *s) { switch (t->kind) { case Type_Named: { - ir_emit_comment(proc, str_lit("Type_Info_Named")); + ir_emit_comment(proc, str_lit("TypeInfoNamed")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_named_ptr); // TODO(bill): Which is better? The mangled name or actual name? @@ -7323,11 +7497,12 @@ void ir_gen_tree(irGen *s) { } break; case Type_Basic: - ir_emit_comment(proc, str_lit("Type_Info_Basic")); + ir_emit_comment(proc, str_lit("TypeInfoBasic")); switch (t->Basic.kind) { case Basic_bool: tag = ir_emit_conv(proc, ti_ptr, t_type_info_boolean_ptr); break; + case Basic_i8: case Basic_u8: case Basic_i16: @@ -7341,20 +7516,21 @@ void ir_gen_tree(irGen *s) { case Basic_int: case Basic_uint: { tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr); - bool is_unsigned = (t->Basic.flags & BasicFlag_Unsigned) != 0; - irValue *is_signed = ir_const_bool(a, !is_unsigned); + irValue *is_signed = ir_const_bool(a, (t->Basic.flags & BasicFlag_Unsigned) == 0); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), is_signed); } break; + // case Basic_f16: case Basic_f32: - case Basic_f64: { + case Basic_f64: tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr); - } break; + break; + // case Basic_complex32: case Basic_complex64: - case Basic_complex128: { + case Basic_complex128: tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr); - } break; + break; case Basic_rawptr: tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); @@ -7371,19 +7547,19 @@ void ir_gen_tree(irGen *s) { break; case Type_Pointer: { - ir_emit_comment(proc, str_lit("Type_Info_Pointer")); + ir_emit_comment(proc, str_lit("TypeInfoPointer")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); } break; case Type_Atomic: { - ir_emit_comment(proc, str_lit("Type_Info_Atomic")); + ir_emit_comment(proc, str_lit("TypeInfoAtomic")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_atomic_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); } break; case Type_Array: { - ir_emit_comment(proc, str_lit("Type_Info_Array")); + ir_emit_comment(proc, str_lit("TypeInfoArray")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); @@ -7397,7 +7573,7 @@ void ir_gen_tree(irGen *s) { } break; case Type_DynamicArray: { - ir_emit_comment(proc, str_lit("Type_Info_DynamicArray")); + ir_emit_comment(proc, str_lit("TypeInfoDynamicArray")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); @@ -7407,7 +7583,7 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, elem_size, ir_const_int(a, ez)); } break; case Type_Slice: { - ir_emit_comment(proc, str_lit("Type_Info_Slice")); + ir_emit_comment(proc, str_lit("TypeInfoSlice")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); @@ -7417,7 +7593,7 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, elem_size, ir_const_int(a, ez)); } break; case Type_Vector: { - ir_emit_comment(proc, str_lit("Type_Info_Vector")); + ir_emit_comment(proc, str_lit("TypeInfoVector")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); @@ -7428,7 +7604,7 @@ void ir_gen_tree(irGen *s) { } break; case Type_Proc: { - ir_emit_comment(proc, str_lit("Type_Info_Proc")); + ir_emit_comment(proc, str_lit("TypeInfoProc")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_procedure_ptr); irValue *params = ir_emit_struct_ep(proc, tag, 2); @@ -7445,10 +7621,10 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, variadic, ir_const_bool(a, t->Proc.variadic)); ir_emit_store(proc, convention, ir_const_int(a, t->Proc.calling_convention)); - // TODO(bill): Type_Info for procedures + // TODO(bill): TypeInfo for procedures } break; case Type_Tuple: { - ir_emit_comment(proc, str_lit("Type_Info_Tuple")); + ir_emit_comment(proc, str_lit("TypeInfoTuple")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr); irValue *record = ir_emit_struct_ep(proc, tag, 2); @@ -7476,7 +7652,7 @@ void ir_gen_tree(irGen *s) { case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: { - ir_emit_comment(proc, str_lit("Type_Info_Struct")); + ir_emit_comment(proc, str_lit("TypeInfoStruct")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); irValue *record = ir_emit_struct_ep(proc, tag, 2); @@ -7523,7 +7699,7 @@ void ir_gen_tree(irGen *s) { ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 3), memory_usings, count, count); } break; case TypeRecord_Union: { - ir_emit_comment(proc, str_lit("Type_Info_Union")); + ir_emit_comment(proc, str_lit("TypeInfoUnion")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr); { @@ -7591,7 +7767,7 @@ void ir_gen_tree(irGen *s) { } break; case TypeRecord_RawUnion: { - ir_emit_comment(proc, str_lit("Type_Info_RawUnion")); + ir_emit_comment(proc, str_lit("TypeInfoRawUnion")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr); irValue *record = ir_emit_struct_ep(proc, tag, 2); @@ -7618,7 +7794,7 @@ void ir_gen_tree(irGen *s) { ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count); } break; case TypeRecord_Enum: - ir_emit_comment(proc, str_lit("Type_Info_Enum")); + ir_emit_comment(proc, str_lit("TypeInfoEnum")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); { GB_ASSERT(t->Record.enum_base_type != NULL); @@ -7659,22 +7835,18 @@ void ir_gen_tree(irGen *s) { irValue *names = ir_emit_struct_ep(proc, tag, 3); irValue *name_array_elem = ir_array_elem(proc, name_array); - - ir_emit_store(proc, ir_emit_struct_ep(proc, names, 0), name_array_elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, names, 1), v_count); + ir_fill_slice(proc, names, name_array_elem, v_count, v_count); irValue *values = ir_emit_struct_ep(proc, tag, 4); irValue *value_array_elem = ir_array_elem(proc, value_array); - - ir_emit_store(proc, ir_emit_struct_ep(proc, values, 0), value_array_elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, values, 1), v_count); + ir_fill_slice(proc, values, value_array_elem, v_count, v_count); } } break; } } break; case Type_Map: { - ir_emit_comment(proc, str_lit("Type_Info_Map")); + ir_emit_comment(proc, str_lit("TypeInfoMap")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); irValue *key = ir_emit_struct_ep(proc, tag, 2); @@ -7687,6 +7859,49 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type)); ir_emit_store(proc, count, ir_const_int(a, t->Map.count)); } break; + + case Type_BitField: { + ir_emit_comment(proc, str_lit("TypeInfoBitField")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + // names: []string, + // bits: []u32, + // offsets: []u32, + isize count = t->BitField.field_count; + if (count > 0) { + Entity **fields = t->BitField.fields; + irValue *name_array = ir_generate_array(m, t_string, count, str_lit("__$bit_field_names"), cast(i64)entry_index); + irValue *bit_array = ir_generate_array(m, t_u32, count, str_lit("__$bit_field_bits"), cast(i64)entry_index); + irValue *offset_array = ir_generate_array(m, t_u32, count, str_lit("__$bit_field_offsets"), cast(i64)entry_index); + + for (isize i = 0; i < count; i++) { + Entity *f = fields[i]; + GB_ASSERT(f->type != NULL); + GB_ASSERT(f->type->kind == Type_BitFieldValue); + irValue *name_ep = ir_emit_array_epi(proc, name_array, i); + irValue *bit_ep = ir_emit_array_epi(proc, bit_array, i); + irValue *offset_ep = ir_emit_array_epi(proc, offset_array, i); + + ir_emit_store(proc, name_ep, ir_const_string(a, f->token.string)); + ir_emit_store(proc, bit_ep, ir_const_u32(a, f->type->BitFieldValue.bits)); + ir_emit_store(proc, offset_ep, ir_const_u32(a, t->BitField.offsets[i])); + + } + + irValue *v_count = ir_const_int(a, count); + + irValue *names = ir_emit_struct_ep(proc, tag, 3); + irValue *name_array_elem = ir_array_elem(proc, name_array); + ir_fill_slice(proc, names, name_array_elem, v_count, v_count); + + irValue *bits = ir_emit_struct_ep(proc, tag, 4); + irValue *bit_array_elem = ir_array_elem(proc, bit_array); + ir_fill_slice(proc, bits, bit_array_elem, v_count, v_count); + + irValue *offsets = ir_emit_struct_ep(proc, tag, 5); + irValue *offset_array_elem = ir_array_elem(proc, offset_array); + ir_fill_slice(proc, offsets, offset_array_elem, v_count, v_count); + } + } break; } @@ -7707,7 +7922,7 @@ void ir_gen_tree(irGen *s) { } GB_ASSERT_MSG(found, "%s", type_to_string(tag_type)); } else { - GB_PANIC("Unhandled Type_Info type: %s", type_to_string(t)); + GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t)); } } } diff --git a/src/ir_print.c b/src/ir_print.c index 520390d55..d66a99c23 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -193,9 +193,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { case Basic_i128: ir_fprintf(f, "i128"); return; case Basic_u128: ir_fprintf(f, "i128"); return; + // case Basic_f16: ir_fprintf(f, "half"); return; case Basic_f32: ir_fprintf(f, "float"); return; case Basic_f64: ir_fprintf(f, "double"); return; + // case Basic_complex32: ir_fprintf(f, "%%..complex32"); return; case Basic_complex64: ir_fprintf(f, "%%..complex64"); return; case Basic_complex128: ir_fprintf(f, "%%..complex128"); return; @@ -348,6 +350,12 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { GB_ASSERT(t->Map.generated_struct_type != NULL); ir_print_type(f, m, t->Map.generated_struct_type); } break; + + case Type_BitField: { + i64 align = type_align_of(heap_allocator(), t); + i64 size = type_size_of(heap_allocator(), t); + ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size); + } break; } } @@ -426,12 +434,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be // a 64 bit number if bits_of(float type) <= 64. // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M - // 64 bit mantiir: 52 bits - // 32 bit mantiir: 23 bits + // 64 bit mantissa: 52 bits + // 32 bit mantissa: 23 bits + // 16 bit mantissa: 10 bits // 29 == 52-23 u >>= 29; u <<= 29; break; + // case Basic_f16: + // u >>= 42; + // u <<= 42; + // break; } switch (type->Basic.kind) { @@ -1568,6 +1581,8 @@ void print_llvm_ir(irGen *ir) { ir_print_encoded_local(f, str_lit("..rawptr")); ir_fprintf(f, " = type i8* ; Basic_rawptr\n"); + ir_print_encoded_local(f, str_lit("..complex32")); + ir_fprintf(f, " = type {half, half} ; Basic_complex32\n"); ir_print_encoded_local(f, str_lit("..complex64")); ir_fprintf(f, " = type {float, float} ; Basic_complex64\n"); ir_print_encoded_local(f, str_lit("..complex128")); diff --git a/src/parser.c b/src/parser.c index 076f72a14..4c7cc50af 100644 --- a/src/parser.c +++ b/src/parser.c @@ -397,6 +397,11 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ AstNode *base_type; \ AstNodeArray fields; /* FieldValue */ \ }) \ + AST_NODE_KIND(BitFieldType, "bit field type", struct { \ + Token token; \ + AstNodeArray fields; /* FieldValue with : */ \ + AstNode *align; \ + }) \ AST_NODE_KIND(MapType, "map type", struct { \ Token token; \ AstNode *count; \ @@ -547,6 +552,7 @@ Token ast_node_token(AstNode *node) { case AstNode_UnionType: return node->UnionType.token; case AstNode_RawUnionType: return node->RawUnionType.token; case AstNode_EnumType: return node->EnumType.token; + case AstNode_BitFieldType: return node->BitFieldType.token; case AstNode_MapType: return node->MapType.token; } @@ -804,6 +810,9 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { n->EnumType.base_type = clone_ast_node(a, n->EnumType.base_type); n->EnumType.fields = clone_ast_node_array(a, n->EnumType.fields); break; + case AstNode_BitFieldType: + n->BitFieldType.fields = clone_ast_node_array(a, n->BitFieldType.fields); + n->BitFieldType.align = clone_ast_node(a, n->BitFieldType.align); case AstNode_MapType: n->MapType.count = clone_ast_node(a, n->MapType.count); n->MapType.key = clone_ast_node(a, n->MapType.key); @@ -1384,6 +1393,14 @@ AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArray return result; } +AstNode *ast_bit_field_type(AstFile *f, Token token, AstNodeArray fields, AstNode *align) { + AstNode *result = make_ast_node(f, AstNode_BitFieldType); + result->BitFieldType.token = token; + result->BitFieldType.fields = fields; + result->BitFieldType.align = align; + return result; +} + AstNode *ast_map_type(AstFile *f, Token token, AstNode *count, AstNode *key, AstNode *value) { AstNode *result = make_ast_node(f, AstNode_MapType); result->MapType.token = token; @@ -1622,6 +1639,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_UnionType: case AstNode_RawUnionType: case AstNode_EnumType: + case AstNode_BitFieldType: return true; case AstNode_ProcLit: return s->ProcLit.body != NULL; @@ -3128,6 +3146,51 @@ AstNode *parse_type_or_ident(AstFile *f) { return ast_enum_type(f, token, base_type, values); } + case Token_bit_field: { + Token token = expect_token(f, Token_bit_field); + AstNodeArray fields = make_ast_node_array(f); + AstNode *align = NULL; + Token open, close; + + isize prev_level = f->expr_level; + f->expr_level = -1; + + while (allow_token(f, Token_Hash)) { + Token tag = expect_token_after(f, Token_Ident, "#"); + if (str_eq(tag.string, str_lit("align"))) { + if (align) { + syntax_error(tag, "Duplicate bit_field tag `#%.*s`", LIT(tag.string)); + } + align = parse_expr(f, true); + } else { + syntax_error(tag, "Invalid bit_field tag `#%.*s`", LIT(tag.string)); + } + } + + f->expr_level = prev_level; + + open = expect_token_after(f, Token_OpenBrace, "bit_field"); + + while (f->curr_token.kind != Token_EOF && + f->curr_token.kind != Token_CloseBrace) { + AstNode *name = parse_ident(f); + Token colon = expect_token(f, Token_Colon); + AstNode *value = parse_expr(f, true); + + AstNode *field = ast_field_value(f, name, value, colon); + array_add(&fields, field); + + if (f->curr_token.kind != Token_Comma) { + break; + } + next_token(f); + } + + close = expect_token(f, Token_CloseBrace); + + return ast_bit_field_type(f, token, fields, align); + } + case Token_proc: { Token token = f->curr_token; AstNode *pt = parse_proc_type(f, NULL, NULL, NULL); diff --git a/src/ssa.c b/src/ssa.c index db3de5e72..b8e3f0b8d 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -2289,7 +2289,7 @@ void ssa_print_exact_value(gbFile *f, ssaValue *v) { u64 x = *cast(u64 *)&fp; gb_fprintf(f, " [0x%llx]", cast(unsigned long long)x); } else { - GB_PANIC("unhandled integer"); + GB_PANIC("unhandled float"); } break; case ExactValue_String: diff --git a/src/tokenizer.c b/src/tokenizer.c index 8d30a36a1..868ed93cc 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -100,6 +100,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_enum, "enum"), \ + TOKEN_KIND(Token_bit_field, "bit_field"), \ TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \ @@ -889,6 +890,10 @@ Token tokenizer_get_token(Tokenizer *t) { case '}': token.kind = Token_CloseBrace; break; case '\\': token.kind = Token_BackSlash; break; + case '≠': token.kind = Token_NotEq; break; + case '≤': token.kind = Token_LtEq; break; + case '≥': token.kind = Token_GtEq; break; + case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; diff --git a/src/types.c b/src/types.c index cbb0bd0d9..91d8dc4eb 100644 --- a/src/types.c +++ b/src/types.c @@ -14,9 +14,11 @@ typedef enum BasicKind { Basic_i128, Basic_u128, + // Basic_f16, Basic_f32, Basic_f64, + // Basic_complex32, Basic_complex64, Basic_complex128, @@ -149,6 +151,15 @@ typedef struct TypeRecord { Type *generated_struct_type; \ Type *lookup_result_type; \ }) \ + TYPE_KIND(BitFieldValue, struct { u32 bits; }) \ + TYPE_KIND(BitField, struct { \ + Scope * scope; \ + Entity **fields; \ + i32 field_count; \ + u32 * offsets; \ + u32 * sizes; \ + i64 custom_align; \ + }) \ @@ -225,9 +236,11 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}}, + // {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}}, {Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}}, {Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}}, + // {Type_Basic, {Basic_complex32, BasicFlag_Complex, 4, STR_LIT("complex32")}}, {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, @@ -265,9 +278,11 @@ gb_global Type *t_u64 = &basic_types[Basic_u64]; gb_global Type *t_i128 = &basic_types[Basic_i128]; gb_global Type *t_u128 = &basic_types[Basic_u128]; +// gb_global Type *t_f16 = &basic_types[Basic_f16]; gb_global Type *t_f32 = &basic_types[Basic_f32]; gb_global Type *t_f64 = &basic_types[Basic_f64]; +// gb_global Type *t_complex32 = &basic_types[Basic_complex32]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; @@ -325,6 +340,7 @@ gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_union = NULL; gb_global Type *t_type_info_enum = NULL; gb_global Type *t_type_info_map = NULL; +gb_global Type *t_type_info_bit_field = NULL; gb_global Type *t_type_info_named_ptr = NULL; gb_global Type *t_type_info_integer_ptr = NULL; @@ -347,6 +363,7 @@ gb_global Type *t_type_info_raw_union_ptr = NULL; gb_global Type *t_type_info_union_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL; gb_global Type *t_type_info_map_ptr = NULL; +gb_global Type *t_type_info_bit_field_ptr = NULL; gb_global Type *t_allocator = NULL; gb_global Type *t_allocator_ptr = NULL; @@ -560,7 +577,20 @@ Type *make_type_map(gbAllocator a, i64 count, Type *key, Type *value) { return t; } +Type *make_type_bit_field_value(gbAllocator a, u32 bits) { + Type *t = alloc_type(a, Type_BitFieldValue); + t->BitFieldValue.bits = bits; + return t; +} +Type *make_type_bit_field(gbAllocator a) { + Type *t = alloc_type(a, Type_BitField); + return t; +} + + + +//////////////////////////////////////////////////////////////// Type *type_deref(Type *t) { @@ -777,6 +807,7 @@ Type *base_complex_elem_type(Type *t) { t = core_type(t); if (is_type_complex(t)) { switch (t->Basic.kind) { + // case Basic_complex32: return t_f16; case Basic_complex64: return t_f32; case Basic_complex128: return t_f64; case Basic_UntypedComplex: return t_untyped_float; @@ -802,7 +833,14 @@ bool is_type_enum(Type *t) { t = base_type(t); return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum); } - +bool is_type_bit_field(Type *t) { + t = base_type(t); + return (t->kind == Type_BitField); +} +bool is_type_bit_field_value(Type *t) { + t = base_type(t); + return (t->kind == Type_BitFieldValue); +} bool is_type_map(Type *t) { t = base_type(t); return t->kind == Type_Map; @@ -1067,6 +1105,26 @@ Type *default_type(Type *type) { return type; } +Type *default_bit_field_value_type(Type *type) { + if (type == NULL) { + return t_invalid; + } + Type *t = base_type(type); + if (t->kind == Type_BitFieldValue) { + i32 bits = t->BitFieldValue.bits; + i32 size = 8*next_pow2((bits+7)/8); + switch (size) { + case 8: return t_u8; + case 16: return t_u16; + case 32: return t_u32; + case 64: return t_u64; + case 128: return t_u128; + default: GB_PANIC("Too big of a bit size!"); break; + } + } + return type; +} + // NOTE(bill): Valid Compile time execution #run type bool is_type_cte_safe(Type *type) { type = default_type(base_type(type)); @@ -1211,8 +1269,9 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { i64 max_count = 0; switch (type->kind) { - case Type_Record: max_count = type->Record.field_count; break; - case Type_Tuple: max_count = type->Tuple.variable_count; break; + case Type_Record: max_count = type->Record.field_count; break; + case Type_Tuple: max_count = type->Tuple.variable_count; break; + case Type_BitField: max_count = type->BitField.field_count; break; } if (index >= max_count) { @@ -1244,6 +1303,14 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { } } break; + + case Type_BitField: { + Array_i32 sel_array = {0}; + array_init_count(&sel_array, a, 1); + sel_array.e[0] = cast(i32)index; + return make_selection(type->BitField.fields[index], sel_array, false); + } break; + } GB_PANIC("Illegal index"); @@ -1407,6 +1474,21 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n return sel; } } + } else if (type->kind == Type_BitField) { + for (isize i = 0; i < type->BitField.field_count; i++) { + Entity *f = type->BitField.fields[i]; + if (f->kind != Entity_Variable || + (f->flags & EntityFlag_BitFieldValue) == 0) { + continue; + } + + String str = f->token.string; + if (str_eq(field_name, str)) { + selection_add_index(&sel, i); // HACK(bill): Leaky memory + sel.entity = f; + return sel; + } + } } return sel; @@ -1641,7 +1723,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { return max; } break; case TypeRecord_RawUnion: { - i64 max = build_context.word_size; + i64 max = 1; for (isize i = 0; i < t->Record.field_count; i++) { Type *field_type = t->Record.fields[i]->type; type_path_push(path, field_type); @@ -1658,6 +1740,14 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } break; } } break; + + case Type_BitField: { + i64 align = 1; + if (t->BitField.custom_align > 0) { + align = t->BitField.custom_align; + } + return gb_clamp(next_pow2(align), 1, build_context.max_align); + } break; } // return gb_clamp(next_pow2(type_size_of(allocator, t)), 1, build_context.max_align); @@ -1913,6 +2003,18 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } break; } } break; + + case Type_BitField: { + i64 align = 8*type_align_of_internal(allocator, t, path); + i64 end = 0; + if (t->BitField.field_count > 0) { + i64 last = t->BitField.field_count-1; + end = t->BitField.offsets[last] + t->BitField.sizes[last]; + } + i64 bits = align_formula(end, align); + GB_ASSERT((bits%8) == 0); + return bits/8; + } break; } // Catch all @@ -2009,8 +2111,6 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s return offset; } - - gbString write_type_to_string(gbString str, Type *type) { if (type == NULL) { return gb_string_appendc(str, ""); @@ -2191,8 +2291,9 @@ gbString write_type_to_string(gbString str, Type *type) { case Type_Proc: str = gb_string_appendc(str, "proc("); - if (type->Proc.params) + if (type->Proc.params) { str = write_type_to_string(str, type->Proc.params); + } str = gb_string_appendc(str, ")"); if (type->Proc.results) { str = gb_string_appendc(str, " -> "); @@ -2213,6 +2314,32 @@ gbString write_type_to_string(gbString str, Type *type) { break; } break; + + case Type_BitField: + str = gb_string_appendc(str, "bit_field "); + if (type->BitField.custom_align != 0) { + str = gb_string_appendc(str, gb_bprintf("#align %d ", cast(int)type->BitField.custom_align)); + } + str = gb_string_appendc(str, "{"); + + for (isize i = 0; i < type->BitField.field_count; i++) { + Entity *f = type->BitField.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + GB_ASSERT(f->type != NULL && f->type->kind == Type_BitFieldValue); + str = gb_string_appendc(str, "{"); + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, " : "); + str = gb_string_appendc(str, gb_bprintf("%lld", cast(long long)f->type->BitFieldValue.bits)); + } + str = gb_string_appendc(str, "}"); + break; + + case Type_BitFieldValue: + str = gb_string_appendc(str, gb_bprintf("(bit field value with %lld bits)", cast(int)type->BitFieldValue.bits)); + break; } return str;