bit_field; Lexical sugar operators ≠ ≤ ≥

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,
}
This commit is contained in:
Ginger Bill
2017-06-03 22:27:23 +01:00
parent 9d1a4c304a
commit 2c0e59ae06
16 changed files with 979 additions and 110 deletions

View File

@@ -98,6 +98,11 @@ TypeInfo :: union {
generated_struct: ^TypeInfo,
count: int, // == 0 if dynamic
},
BitField{
names: []string,
bits: []i32,
offsets: []i32,
},
}

View File

@@ -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));
}
*/

View File

@@ -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, "<nil>");
@@ -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);

View File

@@ -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";

View File

@@ -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..<prec {
c: byte = '0';
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];

View File

@@ -40,6 +40,10 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
}
t = default_type(t);
}
if (is_type_bit_field_value(t)) {
t = default_bit_field_value_type(t);
}
GB_ASSERT(is_type_typed(t));
e->type = t;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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

291
src/ir.c
View File

@@ -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));
}
}
}

View File

@@ -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"));

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;

View File

@@ -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, "<no type>");
@@ -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;