mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +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,
|
generated_struct: ^TypeInfo,
|
||||||
count: int, // == 0 if dynamic
|
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;
|
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));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
+10
-2
@@ -197,11 +197,13 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
|
|||||||
}
|
}
|
||||||
case Float:
|
case Float:
|
||||||
match info.size {
|
match info.size {
|
||||||
|
case 2: write_string(buf, "f16");
|
||||||
case 4: write_string(buf, "f32");
|
case 4: write_string(buf, "f32");
|
||||||
case 8: write_string(buf, "f64");
|
case 8: write_string(buf, "f64");
|
||||||
}
|
}
|
||||||
case Complex:
|
case Complex:
|
||||||
match info.size {
|
match info.size {
|
||||||
|
case 4: write_string(buf, "complex32");
|
||||||
case 8: write_string(buf, "complex64");
|
case 8: write_string(buf, "complex64");
|
||||||
case 16: write_string(buf, "complex128");
|
case 16: write_string(buf, "complex128");
|
||||||
}
|
}
|
||||||
@@ -625,7 +627,6 @@ fmt_float :: proc(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) {
|
|||||||
|
|
||||||
case:
|
case:
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) {
|
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); }
|
_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); }
|
_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) {
|
fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) {
|
||||||
if arg == nil {
|
if arg == nil {
|
||||||
write_string(fi.buf, "<nil>");
|
write_string(fi.buf, "<nil>");
|
||||||
@@ -950,8 +956,10 @@ fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) {
|
|||||||
match a in base_arg {
|
match a in base_arg {
|
||||||
case any: fmt_arg(fi, a, verb);
|
case any: fmt_arg(fi, a, verb);
|
||||||
case bool: fmt_bool(fi, a, verb);
|
case bool: fmt_bool(fi, a, verb);
|
||||||
|
|
||||||
case f32: fmt_float(fi, f64(a), 32, 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 complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||||
case complex128: fmt_complex(fi, a, 128, verb);
|
case complex128: fmt_complex(fi, a, 128, verb);
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -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";
|
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: f32) -> (x: 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: 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: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||||
sign :: proc(x: f64) -> f64 { 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: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
|
||||||
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
|
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
|
||||||
|
|
||||||
|
|||||||
+155
-25
@@ -28,35 +28,164 @@ _digit_value :: proc(r: rune) -> (int) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_i64 :: proc(s: string, base: int) -> i64 {
|
parse_i128 :: proc(s: string) -> i128 {
|
||||||
result: i64;
|
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 {
|
for r in s {
|
||||||
v := _digit_value(r);
|
if r == '_' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v := i128(_digit_value(r));
|
||||||
if v >= base {
|
if v >= base {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result *= i64(base);
|
value *= base;
|
||||||
result += i64(v);
|
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 {
|
for r in s {
|
||||||
v := _digit_value(r);
|
if r == '_' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v := u128(_digit_value(r));
|
||||||
if v >= base {
|
if v >= base {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result *= u64(base);
|
value *= base;
|
||||||
result += u64(v);
|
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 {
|
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,
|
digits: []byte,
|
||||||
count: int,
|
count: int,
|
||||||
decimal_point: int,
|
decimal_point: int,
|
||||||
@@ -94,8 +223,9 @@ Float_Info :: struct {
|
|||||||
bias: int,
|
bias: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
f32_info := Float_Info{23, 8, -127};
|
_f16_info := Float_Info{10, 5, -15};
|
||||||
f64_info := Float_Info{52, 11, -1023};
|
_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 {
|
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 {
|
match bit_size {
|
||||||
case 32:
|
case 32:
|
||||||
bits = u64(transmute(u32, f32(val)));
|
bits = u64(transmute(u32, f32(val)));
|
||||||
flt = &f32_info;
|
flt = &_f32_info;
|
||||||
case 64:
|
case 64:
|
||||||
bits = transmute(u64, val);
|
bits = transmute(u64, val);
|
||||||
flt = &f64_info;
|
flt = &_f64_info;
|
||||||
case:
|
case:
|
||||||
panic("strconv: invalid bit_size");
|
panic("strconv: invalid bit_size");
|
||||||
}
|
}
|
||||||
@@ -142,11 +272,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
|||||||
d := &d_;
|
d := &d_;
|
||||||
assign(d, mant);
|
assign(d, mant);
|
||||||
shift(d, exp - int(flt.mantbits));
|
shift(d, exp - int(flt.mantbits));
|
||||||
digs: Decimal_Slice;
|
digs: DecimalSlice;
|
||||||
shortest := prec < 0;
|
shortest := prec < 0;
|
||||||
if shortest {
|
if shortest {
|
||||||
round_shortest(d, mant, exp, flt);
|
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 {
|
match fmt {
|
||||||
case 'e', 'E': prec = digs.count-1;
|
case 'e', 'E': prec = digs.count-1;
|
||||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
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);
|
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);
|
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 {
|
match fmt {
|
||||||
case 'f', 'F':
|
case 'f', 'F':
|
||||||
append(buf, neg ? '-' : '+');
|
append(buf, neg ? '-' : '+');
|
||||||
@@ -190,7 +320,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
|
|||||||
// fractional part
|
// fractional part
|
||||||
if prec > 0 {
|
if prec > 0 {
|
||||||
append(buf, '.');
|
append(buf, '.');
|
||||||
for i in 0..prec {
|
for i in 0..<prec {
|
||||||
c: byte = '0';
|
c: byte = '0';
|
||||||
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||||
c = digs.digits[j];
|
c = digs.digits[j];
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
}
|
}
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
}
|
}
|
||||||
|
if (is_type_bit_field_value(t)) {
|
||||||
|
t = default_bit_field_value_type(t);
|
||||||
|
}
|
||||||
|
|
||||||
GB_ASSERT(is_type_typed(t));
|
GB_ASSERT(is_type_typed(t));
|
||||||
e->type = t;
|
e->type = t;
|
||||||
}
|
}
|
||||||
|
|||||||
+138
-2
@@ -192,6 +192,18 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
|
|||||||
return 1;
|
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)) {
|
if (check_is_assignable_to_using_subtype(operand->type, type)) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@@ -301,10 +313,10 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type == NULL) {
|
if (type == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_is_assignable_to(c, operand, type)) {
|
if (!check_is_assignable_to(c, operand, type)) {
|
||||||
gbString type_str = type_to_string(type);
|
gbString type_str = type_to_string(type);
|
||||||
gbString op_type_str = type_to_string(operand->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_) {
|
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) {
|
||||||
if (_params == NULL) {
|
if (_params == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1766,6 +1891,15 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_
|
|||||||
return true;
|
return true;
|
||||||
case_end;
|
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);
|
case_ast_node(pt, ProcType, e);
|
||||||
*type = alloc_type(c->allocator, Type_Proc);
|
*type = alloc_type(c->allocator, Type_Proc);
|
||||||
set_base_type(named_type, *type);
|
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) {
|
if (s < 128) {
|
||||||
umax = u128_sub(u128_shl(U128_ONE, s), U128_ONE);
|
umax = u128_sub(u128_shl(U128_ONE, s), U128_ONE);
|
||||||
} else {
|
} 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;
|
s = 128;
|
||||||
}
|
}
|
||||||
i128 imax = i128_shl(I128_ONE, s-1ll);
|
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) {
|
switch (type->Basic.kind) {
|
||||||
|
// case Basic_f16:
|
||||||
case Basic_f32:
|
case Basic_f32:
|
||||||
case Basic_f64:
|
case Basic_f64:
|
||||||
return true;
|
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;
|
BasicKind kind = core_type(x.type)->Basic.kind;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
// case Basic_f16: operand->type = t_complex32; break;
|
||||||
case Basic_f32: operand->type = t_complex64; break;
|
case Basic_f32: operand->type = t_complex64; break;
|
||||||
case Basic_f64: operand->type = t_complex128; break;
|
case Basic_f64: operand->type = t_complex128; break;
|
||||||
case Basic_UntypedFloat: operand->type = t_untyped_complex; break;
|
case Basic_UntypedFloat: operand->type = t_untyped_complex; break;
|
||||||
|
|||||||
+35
-2
@@ -207,7 +207,6 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rhs->mode == Addressing_Overload) {
|
if (rhs->mode == Addressing_Overload) {
|
||||||
isize overload_count = rhs->overload_count;
|
isize overload_count = rhs->overload_count;
|
||||||
Entity **procs = rhs->overload_entities;
|
Entity **procs = rhs->overload_entities;
|
||||||
@@ -256,8 +255,42 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
|||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return NULL;
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Addressing_MapIndex: {
|
case Addressing_MapIndex: {
|
||||||
AstNode *ln = unparen_expr(lhs_node);
|
AstNode *ln = unparen_expr(lhs_node);
|
||||||
if (ln->kind == AstNode_IndexExpr) {
|
if (ln->kind == AstNode_IndexExpr) {
|
||||||
|
|||||||
+19
-14
@@ -126,19 +126,19 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
|||||||
#include "types.c"
|
#include "types.c"
|
||||||
|
|
||||||
typedef enum AddressingMode {
|
typedef enum AddressingMode {
|
||||||
Addressing_Invalid, // invalid addressing mode
|
Addressing_Invalid, // invalid addressing mode
|
||||||
Addressing_NoValue, // no value (void in C)
|
Addressing_NoValue, // no value (void in C)
|
||||||
Addressing_Value, // computed value (rvalue)
|
Addressing_Value, // computed value (rvalue)
|
||||||
Addressing_Immutable, // immutable computed value (const rvalue)
|
Addressing_Immutable, // immutable computed value (const rvalue)
|
||||||
Addressing_Variable, // addressable variable (lvalue)
|
Addressing_Variable, // addressable variable (lvalue)
|
||||||
Addressing_Constant, // constant
|
Addressing_Constant, // constant
|
||||||
Addressing_Type, // type
|
Addressing_Type, // type
|
||||||
Addressing_Builtin, // built-in procedure
|
Addressing_Builtin, // built-in procedure
|
||||||
Addressing_Overload, // overloaded procedure
|
Addressing_Overload, // overloaded procedure
|
||||||
Addressing_MapIndex, // map index expression -
|
Addressing_MapIndex, // map index expression -
|
||||||
// lhs: acts like a Variable
|
// lhs: acts like a Variable
|
||||||
// rhs: acts like OptionalOk
|
// rhs: acts like OptionalOk
|
||||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||||
} AddressingMode;
|
} AddressingMode;
|
||||||
|
|
||||||
// Operand is used as an intermediate value whilst checking
|
// Operand is used as an intermediate value whilst checking
|
||||||
@@ -947,6 +947,9 @@ void add_type_info_type(Checker *c, Type *t) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
|
if (is_type_bit_field_value(t)) {
|
||||||
|
t = default_bit_field_value_type(t);
|
||||||
|
}
|
||||||
if (is_type_untyped(t)) {
|
if (is_type_untyped(t)) {
|
||||||
return; // Could be nil
|
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");
|
compiler_error("Invalid `TypeInfo` layout");
|
||||||
}
|
}
|
||||||
t_type_info_named = record->variants[ 1]->type;
|
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_union = record->variants[18]->type;
|
||||||
t_type_info_enum = record->variants[19]->type;
|
t_type_info_enum = record->variants[19]->type;
|
||||||
t_type_info_map = record->variants[20]->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_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);
|
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_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_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_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) {
|
if (t_allocator == NULL) {
|
||||||
|
|||||||
+12
-11
@@ -33,17 +33,18 @@ String const entity_strings[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef enum EntityFlag {
|
typedef enum EntityFlag {
|
||||||
EntityFlag_Visited = 1<<0,
|
EntityFlag_Visited = 1<<0,
|
||||||
EntityFlag_Used = 1<<1,
|
EntityFlag_Used = 1<<1,
|
||||||
EntityFlag_Using = 1<<2,
|
EntityFlag_Using = 1<<2,
|
||||||
EntityFlag_Field = 1<<3,
|
EntityFlag_Field = 1<<3,
|
||||||
EntityFlag_Param = 1<<4,
|
EntityFlag_Param = 1<<4,
|
||||||
EntityFlag_VectorElem = 1<<5,
|
EntityFlag_VectorElem = 1<<5,
|
||||||
EntityFlag_Ellipsis = 1<<6,
|
EntityFlag_Ellipsis = 1<<6,
|
||||||
EntityFlag_NoAlias = 1<<7,
|
EntityFlag_NoAlias = 1<<7,
|
||||||
EntityFlag_TypeField = 1<<8,
|
EntityFlag_TypeField = 1<<8,
|
||||||
EntityFlag_Value = 1<<9,
|
EntityFlag_Value = 1<<9,
|
||||||
EntityFlag_Sret = 1<<10,
|
EntityFlag_Sret = 1<<10,
|
||||||
|
EntityFlag_BitFieldValue = 1<<11,
|
||||||
} EntityFlag;
|
} EntityFlag;
|
||||||
|
|
||||||
// Zero value means the overloading process is not yet done
|
// Zero value means the overloading process is not yet done
|
||||||
|
|||||||
@@ -404,6 +404,7 @@ typedef enum irAddrKind {
|
|||||||
irAddr_Default,
|
irAddr_Default,
|
||||||
// irAddr_Vector,
|
// irAddr_Vector,
|
||||||
irAddr_Map,
|
irAddr_Map,
|
||||||
|
irAddr_BitField,
|
||||||
} irAddrKind;
|
} irAddrKind;
|
||||||
|
|
||||||
typedef struct irAddr {
|
typedef struct irAddr {
|
||||||
@@ -415,6 +416,9 @@ typedef struct irAddr {
|
|||||||
Type * map_type;
|
Type * map_type;
|
||||||
Type * map_result;
|
Type * map_result;
|
||||||
};
|
};
|
||||||
|
struct {
|
||||||
|
i32 bit_field_value_index;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
// union {
|
// union {
|
||||||
// struct { irValue *index; } Vector;
|
// 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;
|
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 {
|
typedef enum irDebugEncoding {
|
||||||
irDebugBasicEncoding_Invalid = 0,
|
irDebugBasicEncoding_Invalid = 0,
|
||||||
|
|
||||||
@@ -1078,9 +1088,12 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) {
|
|||||||
irValue *ir_const_int(gbAllocator a, i64 i) {
|
irValue *ir_const_int(gbAllocator a, i64 i) {
|
||||||
return ir_value_constant(a, t_int, exact_value_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));
|
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) {
|
irValue *ir_const_i64(gbAllocator a, i64 i) {
|
||||||
return ir_value_constant(a, t_i64, exact_value_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) {
|
irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
|
||||||
if (addr.addr == NULL) {
|
if (addr.addr == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (addr.kind == irAddr_Map) {
|
if (addr.kind == irAddr_Map) {
|
||||||
return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value);
|
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));
|
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);
|
irValue *single = ir_emit_struct_ep(proc, v, 0);
|
||||||
return ir_emit_load(proc, single);
|
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));
|
Type *t = base_type(ir_type(addr.addr));
|
||||||
if (t->kind == Type_Proc) {
|
if (t->kind == Type_Proc) {
|
||||||
// NOTE(bill): Imported procedures don't require a load as they are pointers
|
// 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
|
// float -> float
|
||||||
if (is_type_float(src) && is_type_float(dst)) {
|
if (is_type_float(src) && is_type_float(dst)) {
|
||||||
|
gbAllocator a = proc->module->allocator;
|
||||||
i64 sz = type_size_of(proc->module->allocator, src);
|
i64 sz = type_size_of(proc->module->allocator, src);
|
||||||
i64 dz = type_size_of(proc->module->allocator, dst);
|
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;
|
irConvKind kind = irConv_fptrunc;
|
||||||
if (dz >= sz) {
|
if (dz >= sz) {
|
||||||
kind = irConv_fpext;
|
kind = irConv_fpext;
|
||||||
@@ -2878,6 +3042,7 @@ bool ir_is_type_aggregate(Type *t) {
|
|||||||
case Basic_any:
|
case Basic_any:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// case Basic_complex32:
|
||||||
case Basic_complex64:
|
case Basic_complex64:
|
||||||
case Basic_complex128:
|
case Basic_complex128:
|
||||||
return true;
|
return true;
|
||||||
@@ -3139,7 +3304,7 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (entry_index < 0) {
|
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;
|
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);
|
Selection sel = lookup_field(proc->module->allocator, type, selector, false);
|
||||||
GB_ASSERT(sel.entity != NULL);
|
GB_ASSERT(sel.entity != NULL);
|
||||||
|
|
||||||
irValue *a = ir_build_addr(proc, se->expr).addr;
|
if (sel.entity->type->kind == Type_BitFieldValue) {
|
||||||
a = ir_emit_deep_field_gep(proc, a, sel);
|
irAddr addr = ir_build_addr(proc, se->expr);
|
||||||
return ir_addr(a);
|
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 {
|
} else {
|
||||||
Type *type = type_deref(type_of_expr(proc->module->info, se->expr));
|
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));
|
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) {
|
switch (t->kind) {
|
||||||
case Type_Named: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_named_ptr);
|
||||||
|
|
||||||
// TODO(bill): Which is better? The mangled name or actual name?
|
// TODO(bill): Which is better? The mangled name or actual name?
|
||||||
@@ -7323,11 +7497,12 @@ void ir_gen_tree(irGen *s) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
ir_emit_comment(proc, str_lit("Type_Info_Basic"));
|
ir_emit_comment(proc, str_lit("TypeInfoBasic"));
|
||||||
switch (t->Basic.kind) {
|
switch (t->Basic.kind) {
|
||||||
case Basic_bool:
|
case Basic_bool:
|
||||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_boolean_ptr);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_boolean_ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Basic_i8:
|
case Basic_i8:
|
||||||
case Basic_u8:
|
case Basic_u8:
|
||||||
case Basic_i16:
|
case Basic_i16:
|
||||||
@@ -7341,20 +7516,21 @@ void ir_gen_tree(irGen *s) {
|
|||||||
case Basic_int:
|
case Basic_int:
|
||||||
case Basic_uint: {
|
case Basic_uint: {
|
||||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr);
|
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, (t->Basic.flags & BasicFlag_Unsigned) == 0);
|
||||||
irValue *is_signed = ir_const_bool(a, !is_unsigned);
|
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), is_signed);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), is_signed);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
// case Basic_f16:
|
||||||
case Basic_f32:
|
case Basic_f32:
|
||||||
case Basic_f64: {
|
case Basic_f64:
|
||||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr);
|
||||||
} break;
|
break;
|
||||||
|
|
||||||
|
// case Basic_complex32:
|
||||||
case Basic_complex64:
|
case Basic_complex64:
|
||||||
case Basic_complex128: {
|
case Basic_complex128:
|
||||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr);
|
||||||
} break;
|
break;
|
||||||
|
|
||||||
case Basic_rawptr:
|
case Basic_rawptr:
|
||||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr);
|
||||||
@@ -7371,19 +7547,19 @@ void ir_gen_tree(irGen *s) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Pointer: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
||||||
} break;
|
} break;
|
||||||
case Type_Atomic: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_atomic_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
||||||
} break;
|
} break;
|
||||||
case Type_Array: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
||||||
@@ -7397,7 +7573,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Type_DynamicArray: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
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));
|
ir_emit_store(proc, elem_size, ir_const_int(a, ez));
|
||||||
} break;
|
} break;
|
||||||
case Type_Slice: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
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));
|
ir_emit_store(proc, elem_size, ir_const_int(a, ez));
|
||||||
} break;
|
} break;
|
||||||
case Type_Vector: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr);
|
||||||
irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem);
|
irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep);
|
||||||
@@ -7428,7 +7604,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Type_Proc: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_procedure_ptr);
|
||||||
|
|
||||||
irValue *params = ir_emit_struct_ep(proc, tag, 2);
|
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, variadic, ir_const_bool(a, t->Proc.variadic));
|
||||||
ir_emit_store(proc, convention, ir_const_int(a, t->Proc.calling_convention));
|
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;
|
} break;
|
||||||
case Type_Tuple: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr);
|
||||||
irValue *record = ir_emit_struct_ep(proc, tag, 2);
|
irValue *record = ir_emit_struct_ep(proc, tag, 2);
|
||||||
|
|
||||||
@@ -7476,7 +7652,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
switch (t->Record.kind) {
|
switch (t->Record.kind) {
|
||||||
case TypeRecord_Struct: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
|
||||||
irValue *record = ir_emit_struct_ep(proc, tag, 2);
|
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);
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 3), memory_usings, count, count);
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_Union: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -7591,7 +7767,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_RawUnion: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr);
|
||||||
irValue *record = ir_emit_struct_ep(proc, tag, 2);
|
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);
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count);
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_Enum:
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
|
||||||
{
|
{
|
||||||
GB_ASSERT(t->Record.enum_base_type != NULL);
|
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 *names = ir_emit_struct_ep(proc, tag, 3);
|
||||||
irValue *name_array_elem = ir_array_elem(proc, name_array);
|
irValue *name_array_elem = ir_array_elem(proc, name_array);
|
||||||
|
ir_fill_slice(proc, names, name_array_elem, v_count, v_count);
|
||||||
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);
|
|
||||||
|
|
||||||
irValue *values = ir_emit_struct_ep(proc, tag, 4);
|
irValue *values = ir_emit_struct_ep(proc, tag, 4);
|
||||||
irValue *value_array_elem = ir_array_elem(proc, value_array);
|
irValue *value_array_elem = ir_array_elem(proc, value_array);
|
||||||
|
ir_fill_slice(proc, values, value_array_elem, v_count, v_count);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Type_Map: {
|
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);
|
tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr);
|
||||||
|
|
||||||
irValue *key = ir_emit_struct_ep(proc, tag, 2);
|
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, 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));
|
ir_emit_store(proc, count, ir_const_int(a, t->Map.count));
|
||||||
} break;
|
} 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));
|
GB_ASSERT_MSG(found, "%s", type_to_string(tag_type));
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("Unhandled Type_Info type: %s", type_to_string(t));
|
GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-2
@@ -193,9 +193,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
case Basic_i128: ir_fprintf(f, "i128"); return;
|
case Basic_i128: ir_fprintf(f, "i128"); return;
|
||||||
case Basic_u128: 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_f32: ir_fprintf(f, "float"); return;
|
||||||
case Basic_f64: ir_fprintf(f, "double"); 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_complex64: ir_fprintf(f, "%%..complex64"); return;
|
||||||
case Basic_complex128: ir_fprintf(f, "%%..complex128"); 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);
|
GB_ASSERT(t->Map.generated_struct_type != NULL);
|
||||||
ir_print_type(f, m, t->Map.generated_struct_type);
|
ir_print_type(f, m, t->Map.generated_struct_type);
|
||||||
} break;
|
} 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
|
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
|
||||||
// a 64 bit number if bits_of(float type) <= 64.
|
// a 64 bit number if bits_of(float type) <= 64.
|
||||||
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
|
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
|
||||||
// 64 bit mantiir: 52 bits
|
// 64 bit mantissa: 52 bits
|
||||||
// 32 bit mantiir: 23 bits
|
// 32 bit mantissa: 23 bits
|
||||||
|
// 16 bit mantissa: 10 bits
|
||||||
// 29 == 52-23
|
// 29 == 52-23
|
||||||
u >>= 29;
|
u >>= 29;
|
||||||
u <<= 29;
|
u <<= 29;
|
||||||
break;
|
break;
|
||||||
|
// case Basic_f16:
|
||||||
|
// u >>= 42;
|
||||||
|
// u <<= 42;
|
||||||
|
// break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type->Basic.kind) {
|
switch (type->Basic.kind) {
|
||||||
@@ -1568,6 +1581,8 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
ir_print_encoded_local(f, str_lit("..rawptr"));
|
ir_print_encoded_local(f, str_lit("..rawptr"));
|
||||||
ir_fprintf(f, " = type i8* ; Basic_rawptr\n");
|
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_print_encoded_local(f, str_lit("..complex64"));
|
||||||
ir_fprintf(f, " = type {float, float} ; Basic_complex64\n");
|
ir_fprintf(f, " = type {float, float} ; Basic_complex64\n");
|
||||||
ir_print_encoded_local(f, str_lit("..complex128"));
|
ir_print_encoded_local(f, str_lit("..complex128"));
|
||||||
|
|||||||
@@ -397,6 +397,11 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
|
|||||||
AstNode *base_type; \
|
AstNode *base_type; \
|
||||||
AstNodeArray fields; /* FieldValue */ \
|
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 { \
|
AST_NODE_KIND(MapType, "map type", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
AstNode *count; \
|
AstNode *count; \
|
||||||
@@ -547,6 +552,7 @@ Token ast_node_token(AstNode *node) {
|
|||||||
case AstNode_UnionType: return node->UnionType.token;
|
case AstNode_UnionType: return node->UnionType.token;
|
||||||
case AstNode_RawUnionType: return node->RawUnionType.token;
|
case AstNode_RawUnionType: return node->RawUnionType.token;
|
||||||
case AstNode_EnumType: return node->EnumType.token;
|
case AstNode_EnumType: return node->EnumType.token;
|
||||||
|
case AstNode_BitFieldType: return node->BitFieldType.token;
|
||||||
case AstNode_MapType: return node->MapType.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.base_type = clone_ast_node(a, n->EnumType.base_type);
|
||||||
n->EnumType.fields = clone_ast_node_array(a, n->EnumType.fields);
|
n->EnumType.fields = clone_ast_node_array(a, n->EnumType.fields);
|
||||||
break;
|
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:
|
case AstNode_MapType:
|
||||||
n->MapType.count = clone_ast_node(a, n->MapType.count);
|
n->MapType.count = clone_ast_node(a, n->MapType.count);
|
||||||
n->MapType.key = clone_ast_node(a, n->MapType.key);
|
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;
|
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 *ast_map_type(AstFile *f, Token token, AstNode *count, AstNode *key, AstNode *value) {
|
||||||
AstNode *result = make_ast_node(f, AstNode_MapType);
|
AstNode *result = make_ast_node(f, AstNode_MapType);
|
||||||
result->MapType.token = token;
|
result->MapType.token = token;
|
||||||
@@ -1622,6 +1639,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
|
|||||||
case AstNode_UnionType:
|
case AstNode_UnionType:
|
||||||
case AstNode_RawUnionType:
|
case AstNode_RawUnionType:
|
||||||
case AstNode_EnumType:
|
case AstNode_EnumType:
|
||||||
|
case AstNode_BitFieldType:
|
||||||
return true;
|
return true;
|
||||||
case AstNode_ProcLit:
|
case AstNode_ProcLit:
|
||||||
return s->ProcLit.body != NULL;
|
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);
|
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: {
|
case Token_proc: {
|
||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
AstNode *pt = parse_proc_type(f, NULL, NULL, NULL);
|
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;
|
u64 x = *cast(u64 *)&fp;
|
||||||
gb_fprintf(f, " [0x%llx]", cast(unsigned long long)x);
|
gb_fprintf(f, " [0x%llx]", cast(unsigned long long)x);
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("unhandled integer");
|
GB_PANIC("unhandled float");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ExactValue_String:
|
case ExactValue_String:
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
|
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||||
TOKEN_KIND(Token_vector, "vector"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
TOKEN_KIND(Token_static, "static"), \
|
TOKEN_KIND(Token_static, "static"), \
|
||||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
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_CloseBrace; break;
|
||||||
case '\\': token.kind = Token_BackSlash; 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_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
|
||||||
|
|
||||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||||
|
|||||||
+134
-7
@@ -14,9 +14,11 @@ typedef enum BasicKind {
|
|||||||
Basic_i128,
|
Basic_i128,
|
||||||
Basic_u128,
|
Basic_u128,
|
||||||
|
|
||||||
|
// Basic_f16,
|
||||||
Basic_f32,
|
Basic_f32,
|
||||||
Basic_f64,
|
Basic_f64,
|
||||||
|
|
||||||
|
// Basic_complex32,
|
||||||
Basic_complex64,
|
Basic_complex64,
|
||||||
Basic_complex128,
|
Basic_complex128,
|
||||||
|
|
||||||
@@ -149,6 +151,15 @@ typedef struct TypeRecord {
|
|||||||
Type *generated_struct_type; \
|
Type *generated_struct_type; \
|
||||||
Type *lookup_result_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_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_f32, BasicFlag_Float, 4, STR_LIT("f32")}},
|
||||||
{Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}},
|
{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_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
|
||||||
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
|
{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_i128 = &basic_types[Basic_i128];
|
||||||
gb_global Type *t_u128 = &basic_types[Basic_u128];
|
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_f32 = &basic_types[Basic_f32];
|
||||||
gb_global Type *t_f64 = &basic_types[Basic_f64];
|
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_complex64 = &basic_types[Basic_complex64];
|
||||||
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
|
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_union = NULL;
|
||||||
gb_global Type *t_type_info_enum = NULL;
|
gb_global Type *t_type_info_enum = NULL;
|
||||||
gb_global Type *t_type_info_map = 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_named_ptr = NULL;
|
||||||
gb_global Type *t_type_info_integer_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_union_ptr = NULL;
|
||||||
gb_global Type *t_type_info_enum_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_map_ptr = NULL;
|
||||||
|
gb_global Type *t_type_info_bit_field_ptr = NULL;
|
||||||
|
|
||||||
gb_global Type *t_allocator = NULL;
|
gb_global Type *t_allocator = NULL;
|
||||||
gb_global Type *t_allocator_ptr = 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;
|
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) {
|
Type *type_deref(Type *t) {
|
||||||
@@ -777,6 +807,7 @@ Type *base_complex_elem_type(Type *t) {
|
|||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
if (is_type_complex(t)) {
|
if (is_type_complex(t)) {
|
||||||
switch (t->Basic.kind) {
|
switch (t->Basic.kind) {
|
||||||
|
// case Basic_complex32: return t_f16;
|
||||||
case Basic_complex64: return t_f32;
|
case Basic_complex64: return t_f32;
|
||||||
case Basic_complex128: return t_f64;
|
case Basic_complex128: return t_f64;
|
||||||
case Basic_UntypedComplex: return t_untyped_float;
|
case Basic_UntypedComplex: return t_untyped_float;
|
||||||
@@ -802,7 +833,14 @@ bool is_type_enum(Type *t) {
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum);
|
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) {
|
bool is_type_map(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->kind == Type_Map;
|
return t->kind == Type_Map;
|
||||||
@@ -1067,6 +1105,26 @@ Type *default_type(Type *type) {
|
|||||||
return 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
|
// NOTE(bill): Valid Compile time execution #run type
|
||||||
bool is_type_cte_safe(Type *type) {
|
bool is_type_cte_safe(Type *type) {
|
||||||
type = default_type(base_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;
|
i64 max_count = 0;
|
||||||
switch (type->kind) {
|
switch (type->kind) {
|
||||||
case Type_Record: max_count = type->Record.field_count; break;
|
case Type_Record: max_count = type->Record.field_count; break;
|
||||||
case Type_Tuple: max_count = type->Tuple.variable_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) {
|
if (index >= max_count) {
|
||||||
@@ -1244,6 +1303,14 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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");
|
GB_PANIC("Illegal index");
|
||||||
@@ -1407,6 +1474,21 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
return sel;
|
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;
|
return sel;
|
||||||
@@ -1641,7 +1723,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
return max;
|
return max;
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_RawUnion: {
|
case TypeRecord_RawUnion: {
|
||||||
i64 max = build_context.word_size;
|
i64 max = 1;
|
||||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||||
Type *field_type = t->Record.fields[i]->type;
|
Type *field_type = t->Record.fields[i]->type;
|
||||||
type_path_push(path, field_type);
|
type_path_push(path, field_type);
|
||||||
@@ -1658,6 +1740,14 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
} 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);
|
// 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;
|
||||||
}
|
}
|
||||||
} 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
|
// Catch all
|
||||||
@@ -2009,8 +2111,6 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gbString write_type_to_string(gbString str, Type *type) {
|
gbString write_type_to_string(gbString str, Type *type) {
|
||||||
if (type == NULL) {
|
if (type == NULL) {
|
||||||
return gb_string_appendc(str, "<no type>");
|
return gb_string_appendc(str, "<no type>");
|
||||||
@@ -2191,8 +2291,9 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
|
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
str = gb_string_appendc(str, "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 = write_type_to_string(str, type->Proc.params);
|
||||||
|
}
|
||||||
str = gb_string_appendc(str, ")");
|
str = gb_string_appendc(str, ")");
|
||||||
if (type->Proc.results) {
|
if (type->Proc.results) {
|
||||||
str = gb_string_appendc(str, " -> ");
|
str = gb_string_appendc(str, " -> ");
|
||||||
@@ -2213,6 +2314,32 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
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;
|
return str;
|
||||||
|
|||||||
Reference in New Issue
Block a user