mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-06 18:54:12 +00:00
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:
@@ -98,6 +98,11 @@ TypeInfo :: union {
|
||||
generated_struct: ^TypeInfo,
|
||||
count: int, // == 0 if dynamic
|
||||
},
|
||||
BitField{
|
||||
names: []string,
|
||||
bits: []i32,
|
||||
offsets: []i32,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
140
src/check_expr.c
140
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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
23
src/entity.c
23
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
|
||||
|
||||
291
src/ir.c
291
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
63
src/parser.c
63
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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
141
src/types.c
141
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, "<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;
|
||||
|
||||
Reference in New Issue
Block a user