ソースを参照

`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,
}
Ginger Bill 8 年 前
コミット
2c0e59ae06
16 ファイル変更979 行追加110 行削除
  1. 5 0
      core/_preload.odin
  2. 123 0
      core/_soft_numbers.odin
  3. 10 2
      core/fmt.odin
  4. 5 6
      core/math.odin
  5. 155 25
      core/strconv.odin
  6. 4 0
      src/check_decl.c
  7. 138 2
      src/check_expr.c
  8. 35 2
      src/check_stmt.c
  9. 19 14
      src/checker.c
  10. 12 11
      src/entity.c
  11. 253 38
      src/ir.c
  12. 17 2
      src/ir_print.c
  13. 63 0
      src/parser.c
  14. 1 1
      src/ssa.c
  15. 5 0
      src/tokenizer.c
  16. 134 7
      src/types.c

+ 5 - 0
core/_preload.odin

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

+ 123 - 0
core/_soft_numbers.odin

@@ -67,3 +67,126 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_odin #link_nam
 	return q;
 }
 
+/*
+__f16_to_f32 :: proc(f: f16) -> f32 #cc_odin #no_inline #link_name "__gnu_h2f_ieee" {
+	when true {
+		// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
+		FP32 :: raw_union {u: u32, f: f32};
+
+		magic, was_infnan: FP32;
+		magic.u = (254-15) << 23;
+		was_infnan.u = (127+16) << 23;
+
+		hu := transmute(u16, f);
+
+		o := FP32{};
+
+		o.u = u32((hu & 0x7fff) << 13);
+		o.f *= magic.f;
+		if o.f >= was_infnan.f {
+			o.u |= 255 << 23;
+		}
+		o.u |= u32(hu & 0x8000) << 16;
+		return o.f;
+	} else {
+		return 0;
+	}
+}
+__f32_to_f16 :: proc(f_: f32) -> f16 #cc_odin #no_inline #link_name "__gnu_f2h_ieee" {
+	when false {
+		// Source: https://gist.github.com/rygorous/2156668
+		FP16 :: raw_union {u: u16, f: f16};
+		FP32 :: raw_union {u: u32, f: f32};
+
+		f32infty, f16infty, magic: FP32;
+		f32infty.u = 255<<23;
+		f16infty.u =  31<<23;
+		magic.u    =  15<<23;
+
+		sign_mask :: u32(0x80000000);
+		round_mask :: ~u32(0x0fff);
+
+		f := transmute(FP32, f_);
+
+		o: FP16;
+		sign := f.u & sign_mask;
+		f.u ~= sign;
+
+		// NOTE all the integer compares in this function can be safely
+		// compiled into signed compares since all operands are below
+		// 0x80000000. Important if you want fast straight SSE2 code
+		// (since there's no unsigned PCMPGTD).
+
+		if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
+			o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
+		} else { // (De)normalized number or zero
+			f.u &= round_mask;
+			f.f *= magic.f;
+			f.u -= round_mask;
+			if f.u > f16infty.u {
+				f.u = f16infty.u; // Clamp to signed infinity if overflowed
+			}
+
+			o.u = u16(f.u >> 13); // Take the bits!
+		}
+
+		o.u |= u16(sign >> 16);
+		return o.f;
+	} else {
+		f := transmute(u32, f_);
+		h: u16;
+		hs, he, hf: u16;
+
+		fs := (f >> 31) & 1;
+		fe := (f >> 23) & 0b1111_1111;
+		ff := (f >> 0)  & 0b0111_1111_1111_1111_1111_1111;
+
+		add_one := false;
+
+		if (fe == 0) {
+			he = 0;
+		} else if (fe == 255) {
+			he = 31;
+			hf = ff != 0 ? 0x200 : 0;
+		} else {
+			ne := fe - 127 + 15;
+			if ne >= 31 {
+				he = 31;
+			} else if ne <= 0 {
+				if (14-ne) <= 24 {
+					mant := ff | 0x800000;
+					hf = u16(mant >> (14-ne));
+
+					if (mant >> (13-ne)) & 1 != 0 {
+						add_one = true;
+					}
+				}
+			} else {
+				he = u16(ne);
+				hf = u16(ff >> 13);
+				if ff&0x1000 != 0 {
+					add_one = true;
+				}
+			}
+		}
+
+
+		hs = u16(hs);
+		h |= (he&0b0001_1111)<<10;
+		h |= (hf&0b0011_1111_1111);
+		if add_one {
+			h++;
+		}
+		h |= (hs&1) << 15;
+		return transmute(f16, h);
+	}
+}
+
+__f64_to_f16 :: proc(f: f64) -> f16 #cc_odin #no_inline #link_name "__truncdfhf2" {
+	return __f32_to_f16(f32(f));
+}
+
+__f16_to_f64 :: proc(f: f16) -> f64 #cc_odin #no_inline {
+	return f64(__f16_to_f32(f));
+}
+*/

+ 10 - 2
core/fmt.odin

@@ -197,11 +197,13 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		}
 	case Float:
 		match info.size {
+		case 2: write_string(buf, "f16");
 		case 4: write_string(buf, "f32");
 		case 8: write_string(buf, "f64");
 		}
 	case Complex:
 		match info.size {
+		case 4:  write_string(buf, "complex32");
 		case 8:  write_string(buf, "complex64");
 		case 16: write_string(buf, "complex128");
 		}
@@ -625,7 +627,6 @@ fmt_float :: proc(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) {
 
 	case:
 		fmt_bad_verb(fi, verb);
-		return;
 	}
 }
 fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) {
@@ -928,6 +929,11 @@ fmt_complex :: proc(fi: ^FmtInfo, c: complex128, bits: int, verb: rune) {
 _u128_to_lo_hi :: proc(a: u128) -> (lo, hi: u64) { return u64(a), u64(a>>64); }
 _i128_to_lo_hi :: proc(a: u128) -> (lo: u64 hi: i64) { return u64(a), i64(a>>64); }
 
+
+do_foo :: proc(fi: ^FmtInfo, f: f64) {
+	fmt_string(fi, "Hellope$%!", 'v');
+}
+
 fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) {
 	if arg == nil {
 		write_string(fi.buf, "<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);
 

+ 5 - 6
core/math.odin

@@ -43,16 +43,15 @@ pow  :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32";
 pow  :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
 
 
-lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
-lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
+lerp   :: proc(a, b, t: f32) -> (x: f32) { return a*(1-t) + b*t; }
+lerp   :: proc(a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; }
+unlerp :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
+unlerp :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
+
 
 sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
 sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
 
-bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
-bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
-bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
-
 fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
 fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
 

+ 155 - 25
core/strconv.odin

@@ -28,35 +28,164 @@ _digit_value :: proc(r: rune) -> (int) {
 	return v;
 }
 
-parse_i64 :: proc(s: string, base: int) -> i64 {
-	result: i64;
+parse_i128 :: proc(s: string) -> i128 {
+	neg := false;
+	if len(s) > 1 {
+		match s[0] {
+		case '-':
+			neg = true;
+			s = s[1..];
+		case '+':
+			s = s[1..];
+		}
+	}
+
+
+	base: i128 = 10;
+	if len(s) > 2 && s[0] == '0' {
+		match s[1] {
+		case 'b': base =  2;  s = s[2..];
+		case 'o': base =  8;  s = s[2..];
+		case 'd': base = 10;  s = s[2..];
+		case 'z': base = 12;  s = s[2..];
+		case 'x': base = 16;  s = s[2..];
+		}
+	}
+
+
+	value: i128;
 	for r in s {
-		v := _digit_value(r);
+		if r == '_' {
+			continue;
+		}
+
+		v := i128(_digit_value(r));
 		if v >= base {
 			break;
 		}
-		result *= i64(base);
-		result += i64(v);
+		value *= base;
+		value += v;
 	}
-	return result;
+
+	return neg ? -value : value;
 }
-parse_u64 :: proc(s: string, base: int) -> u64 {
-	result: u64;
+
+parse_u128 :: proc(s: string) -> u128 {
+	neg := false;
+	if len(s) > 1 && s[0] == '+' {
+		s = s[1..];
+	}
+
+
+	base: = u128(10);
+	if len(s) > 2 && s[0] == '0' {
+		match s[1] {
+		case 'b': base =  2;  s = s[2..];
+		case 'o': base =  8;  s = s[2..];
+		case 'd': base = 10;  s = s[2..];
+		case 'z': base = 12;  s = s[2..];
+		case 'x': base = 16;  s = s[2..];
+		}
+	}
+
+
+	value: u128;
 	for r in s {
-		v := _digit_value(r);
+		if r == '_' {
+			continue;
+		}
+
+		v := u128(_digit_value(r));
 		if v >= base {
 			break;
 		}
-		result *= u64(base);
-		result += u64(v);
+		value *= base;
+		value += u128(v);
 	}
-	return result;
+
+	return neg ? -value : value;
 }
-parse_int :: proc(s: string, base: int) -> int {
-	return int(parse_i64(s, base));
+
+
+parse_int :: proc(s: string) -> int {
+	return int(parse_i128(s));
 }
 parse_uint :: proc(s: string, base: int) -> uint {
-	return uint(parse_u64(s, base));
+	return uint(parse_u128(s));
+}
+
+parse_f64 :: proc(s: string) -> f64 {
+	i := 0;
+
+	sign: f64 = 1;
+	match s[i] {
+	case '-': i++; sign = -1;
+	case '+': i++;
+	}
+
+	value: f64 = 0;
+	for ; i < len(s); i++ {
+		r := rune(s[i]);
+		if r == '_' {
+			continue;
+		}
+		v := _digit_value(r);
+		if v >= 10 {
+			break;
+		}
+		value *= 10;
+		value += f64(v);
+	}
+
+	if s[i] == '.' {
+		pow10: f64 = 10;
+		i++;
+
+		for ; i < len(s); i++ {
+			r := rune(s[i]);
+			if r == '_' {
+				continue;
+			}
+			v := _digit_value(r);
+			if v >= 10 {
+				break;
+			}
+			value += f64(v)/pow10;
+			pow10 *= 10;
+		}
+	}
+
+	frac := false;
+	scale: f64 = 1;
+
+	if s[i] == 'e' || s[i] == 'E' {
+		i++;
+
+		match s[i] {
+		case '-': i++; frac = true;
+		case '+': i++;
+		}
+
+		exp: u32 = 0;
+		for ; i < len(s); i++ {
+			r := rune(s[i]);
+			if r == '_' {
+				continue;
+			}
+			d := u32(_digit_value(r));
+			if d >= 10 {
+				break;
+			}
+			exp = exp * 10 + d;
+		}
+		if exp > 308 { exp = 308; }
+
+		for exp >= 50 { scale *= 1e50; exp -= 50; }
+		for exp >=  8 { scale *=  1e8; exp -=  8; }
+		for exp >   0 { scale *=   10; exp -=  1; }
+	}
+
+	return sign * (frac ? (value/scale) : (value*scale));
 }
 
 
@@ -81,7 +210,7 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str
 
 
 
-Decimal_Slice :: struct {
+DecimalSlice :: struct {
 	digits:        []byte,
 	count:         int,
 	decimal_point: int,
@@ -94,8 +223,9 @@ Float_Info :: struct {
 	bias:     int,
 }
 
-f32_info := Float_Info{23, 8, -127};
-f64_info := Float_Info{52, 11, -1023};
+_f16_info := Float_Info{10, 5,   -15};
+_f32_info := Float_Info{23, 8,  -127};
+_f64_info := Float_Info{52, 11, -1023};
 
 
 generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
@@ -104,10 +234,10 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
 	match bit_size {
 	case 32:
 		bits = u64(transmute(u32, f32(val)));
-		flt = &f32_info;
+		flt = &_f32_info;
 	case 64:
 		bits = transmute(u64, val);
-		flt = &f64_info;
+		flt = &_f64_info;
 	case:
 		panic("strconv: invalid bit_size");
 	}
@@ -142,11 +272,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
 	d := &d_;
 	assign(d, mant);
 	shift(d, exp - int(flt.mantbits));
-	digs: Decimal_Slice;
+	digs: DecimalSlice;
 	shortest := prec < 0;
 	if shortest {
 		round_shortest(d, mant, exp, flt);
-		digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
+		digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
 		match fmt {
 		case 'e', 'E': prec = digs.count-1;
 		case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
@@ -163,14 +293,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
 			round(d, prec);
 		}
 
-		digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
+		digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
 	}
 	return format_digits(buf, shortest, neg, digs, prec, fmt);
 }
 
 
 
-format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
+format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte {
 	match fmt {
 	case 'f', 'F':
 		append(buf, neg ? '-' : '+');
@@ -190,7 +320,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
 		// fractional part
 		if prec > 0 {
 			append(buf, '.');
-			for i in 0..prec {
+			for i in 0..<prec {
 				c: byte = '0';
 				if j := digs.decimal_point + i; 0 <= j && j < digs.count {
 					c = digs.digits[j];

+ 4 - 0
src/check_decl.c

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

+ 138 - 2
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;

+ 35 - 2
src/check_stmt.c

@@ -207,7 +207,6 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
 		return NULL;
 	}
 
-
 	if (rhs->mode == Addressing_Overload) {
 		isize overload_count = rhs->overload_count;
 		Entity **procs = rhs->overload_entities;
@@ -256,8 +255,42 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
 	case Addressing_Invalid:
 		return NULL;
 
-	case Addressing_Variable:
+	case Addressing_Variable: {
+		if (is_type_bit_field_value(lhs.type)) {
+			Type *lt = base_type(lhs.type);
+			i64 lhs_bits = lt->BitFieldValue.bits;
+			if (rhs->mode == Addressing_Constant) {
+				ExactValue v = exact_value_to_integer(rhs->value);
+				if (v.kind == ExactValue_Integer) {
+					i128 i = v.value_integer;
+					u128 u = *cast(u128 *)&i;
+					u128 umax = U128_NEG_ONE;
+					if (lhs_bits < 128) {
+						umax = u128_sub(u128_shl(U128_ONE, lhs_bits), U128_ONE);
+					}
+					i128 imax = i128_shl(I128_ONE, lhs_bits-1ll);
+
+					bool ok = false;
+					ok = !(u128_lt(u, U128_ZERO) || u128_gt(u, umax));
+
+					if (ok) {
+						return rhs->type;
+					}
+				}
+			} else if (is_type_integer(rhs->type)) {
+				// TODO(bill): Any other checks?
+				return rhs->type;
+			}
+			gbString lhs_expr = expr_to_string(lhs.expr);
+			gbString rhs_expr = expr_to_string(rhs->expr);
+			error_node(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr);
+			gb_string_free(rhs_expr);
+			gb_string_free(lhs_expr);
+			return NULL;
+		}
 		break;
+	}
+
 	case Addressing_MapIndex: {
 		AstNode *ln = unparen_expr(lhs_node);
 		if (ln->kind == AstNode_IndexExpr) {

+ 19 - 14
src/checker.c

@@ -126,19 +126,19 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 #include "types.c"
 
 typedef enum AddressingMode {
-	Addressing_Invalid,    // invalid addressing mode
-	Addressing_NoValue,    // no value (void in C)
-	Addressing_Value,      // computed value (rvalue)
-	Addressing_Immutable,  // immutable computed value (const rvalue)
-	Addressing_Variable,   // addressable variable (lvalue)
-	Addressing_Constant,   // constant
-	Addressing_Type,       // type
-	Addressing_Builtin,    // built-in procedure
-	Addressing_Overload,   // overloaded procedure
-	Addressing_MapIndex,   // map index expression -
-	                       // 	lhs: acts like a Variable
-	                       // 	rhs: acts like OptionalOk
-	Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
+	Addressing_Invalid,       // invalid addressing mode
+	Addressing_NoValue,       // no value (void in C)
+	Addressing_Value,         // computed value (rvalue)
+	Addressing_Immutable,     // immutable computed value (const rvalue)
+	Addressing_Variable,      // addressable variable (lvalue)
+	Addressing_Constant,      // constant
+	Addressing_Type,          // type
+	Addressing_Builtin,       // built-in procedure
+	Addressing_Overload,      // overloaded procedure
+	Addressing_MapIndex,      // map index expression -
+	                          // 	lhs: acts like a Variable
+	                          // 	rhs: acts like OptionalOk
+	Addressing_OptionalOk,    // rhs: acts like a value with an optional boolean part (for existence check)
 } AddressingMode;
 
 // Operand is used as an intermediate value whilst checking
@@ -947,6 +947,9 @@ void add_type_info_type(Checker *c, Type *t) {
 		return;
 	}
 	t = default_type(t);
+	if (is_type_bit_field_value(t)) {
+		t = default_bit_field_value_type(t);
+	}
 	if (is_type_untyped(t)) {
 		return; // Could be nil
 	}
@@ -1200,7 +1203,7 @@ void init_preload(Checker *c) {
 
 
 
-		if (record->variant_count != 21) {
+		if (record->variant_count != 22) {
 			compiler_error("Invalid `TypeInfo` layout");
 		}
 		t_type_info_named         = record->variants[ 1]->type;
@@ -1223,6 +1226,7 @@ void init_preload(Checker *c) {
 		t_type_info_union         = record->variants[18]->type;
 		t_type_info_enum          = record->variants[19]->type;
 		t_type_info_map           = record->variants[20]->type;
+		t_type_info_bit_field     = record->variants[21]->type;
 
 		t_type_info_named_ptr         = make_type_pointer(c->allocator, t_type_info_named);
 		t_type_info_integer_ptr       = make_type_pointer(c->allocator, t_type_info_integer);
@@ -1244,6 +1248,7 @@ void init_preload(Checker *c) {
 		t_type_info_union_ptr         = make_type_pointer(c->allocator, t_type_info_union);
 		t_type_info_enum_ptr          = make_type_pointer(c->allocator, t_type_info_enum);
 		t_type_info_map_ptr           = make_type_pointer(c->allocator, t_type_info_map);
+		t_type_info_bit_field_ptr     = make_type_pointer(c->allocator, t_type_info_bit_field);
 	}
 
 	if (t_allocator == NULL) {

+ 12 - 11
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

+ 253 - 38
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));
 				}
 			}
 		}

+ 17 - 2
src/ir_print.c

@@ -193,9 +193,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		case Basic_i128:   ir_fprintf(f, "i128");                     return;
 		case Basic_u128:   ir_fprintf(f, "i128");                     return;
 
+		// case Basic_f16:    ir_fprintf(f, "half");                     return;
 		case Basic_f32:    ir_fprintf(f, "float");                    return;
 		case Basic_f64:    ir_fprintf(f, "double");                   return;
 
+		// case Basic_complex32:  ir_fprintf(f, "%%..complex32");        return;
 		case Basic_complex64:  ir_fprintf(f, "%%..complex64");        return;
 		case Basic_complex128: ir_fprintf(f, "%%..complex128");       return;
 
@@ -348,6 +350,12 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		GB_ASSERT(t->Map.generated_struct_type != NULL);
 		ir_print_type(f, m, t->Map.generated_struct_type);
 	} break;
+
+	case Type_BitField: {
+		i64 align = type_align_of(heap_allocator(), t);
+		i64 size  = type_size_of(heap_allocator(),  t);
+		ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
+	} break;
 	}
 }
 
@@ -426,12 +434,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 			// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
 			// a 64 bit number if bits_of(float type) <= 64.
 			// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
-			// 64 bit mantiir: 52 bits
-			// 32 bit mantiir: 23 bits
+			// 64 bit mantissa: 52 bits
+			// 32 bit mantissa: 23 bits
+			// 16 bit mantissa: 10 bits
 			// 29 == 52-23
 			u >>= 29;
 			u <<= 29;
 			break;
+		// case Basic_f16:
+			// u >>= 42;
+			// u <<= 42;
+			// break;
 		}
 
 		switch (type->Basic.kind) {
@@ -1568,6 +1581,8 @@ void print_llvm_ir(irGen *ir) {
 	ir_print_encoded_local(f, str_lit("..rawptr"));
 	ir_fprintf(f, " = type i8* ; Basic_rawptr\n");
 
+	ir_print_encoded_local(f, str_lit("..complex32"));
+	ir_fprintf(f, " = type {half, half} ; Basic_complex32\n");
 	ir_print_encoded_local(f, str_lit("..complex64"));
 	ir_fprintf(f, " = type {float, float} ; Basic_complex64\n");
 	ir_print_encoded_local(f, str_lit("..complex128"));

+ 63 - 0
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);

+ 1 - 1
src/ssa.c

@@ -2289,7 +2289,7 @@ void ssa_print_exact_value(gbFile *f, ssaValue *v) {
 			u64 x = *cast(u64 *)&fp;
 			gb_fprintf(f, " [0x%llx]", cast(unsigned long long)x);
 		} else {
-			GB_PANIC("unhandled integer");
+			GB_PANIC("unhandled float");
 		}
 		break;
 	case ExactValue_String:

+ 5 - 0
src/tokenizer.c

@@ -100,6 +100,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_union,          "union"),               \
 	TOKEN_KIND(Token_raw_union,      "raw_union"),           \
 	TOKEN_KIND(Token_enum,           "enum"),                \
+	TOKEN_KIND(Token_bit_field,      "bit_field"),           \
 	TOKEN_KIND(Token_vector,         "vector"),              \
 	TOKEN_KIND(Token_static,         "static"),              \
 	TOKEN_KIND(Token_dynamic,        "dynamic"),             \
@@ -889,6 +890,10 @@ Token tokenizer_get_token(Tokenizer *t) {
 		case '}':  token.kind = Token_CloseBrace;   break;
 		case '\\': token.kind = Token_BackSlash;    break;
 
+		case '≠':  token.kind = Token_NotEq; break;
+		case '≤':  token.kind = Token_LtEq;  break;
+		case '≥':  token.kind = Token_GtEq;  break;
+
 		case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq);      break;
 
 		case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq);                                        break;

+ 134 - 7
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,8 +577,21 @@ 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) {
 	if (t != NULL) {
@@ -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;