Browse Source

expr as type; {N}bool is still causing problems

gingerBill 9 years ago
parent
commit
ee00236412
11 changed files with 831 additions and 544 deletions
  1. 67 15
      examples/basic.odin
  2. 261 166
      examples/main.ll
  3. 40 45
      examples/main.odin
  4. 137 107
      src/checker/expr.cpp
  5. 21 15
      src/checker/type.cpp
  6. 1 1
      src/codegen/codegen.cpp
  7. 29 5
      src/codegen/print_llvm.cpp
  8. 205 95
      src/codegen/ssa.cpp
  9. 54 79
      src/parser.cpp
  10. 0 6
      src/printer.cpp
  11. 16 10
      src/tokenizer.cpp

+ 67 - 15
examples/basic.odin

@@ -2,7 +2,7 @@ putchar :: proc(c: i32) -> i32 #foreign
 
 print_string :: proc(s: string) {
 	for i := 0; i < len(s); i++ {
-		putchar(cast(i32)s[i]);
+		putchar(s[i] as i32);
 	}
 }
 
@@ -15,15 +15,15 @@ byte_reverse :: proc(b: []byte) {
 
 encode_rune :: proc(r : rune) -> ([4]byte, int) {
 	buf : [4]byte;
-	i := cast(u32)r;
+	i := r as u32;
 	mask : byte : 0x3f;
 	if i <= 1<<7-1 {
-		buf[0] = cast(byte)r;
+		buf[0] = r as byte;
 		return buf, 1;
 	}
 	if i <= 1<<11-1 {
-		buf[0] = 0xc0 | cast(byte)(r>>6);
-		buf[1] = 0x80 | cast(byte)(r)&mask;
+		buf[0] = (0xc0 | r>>6) as byte;
+		buf[1] = (0x80 | r) as byte & mask;
 		return buf, 2;
 	}
 
@@ -34,22 +34,22 @@ encode_rune :: proc(r : rune) -> ([4]byte, int) {
 	}
 
 	if i <= 1<<16-1 {
-		buf[0] = 0xe0 | cast(byte)(r>>12);
-		buf[1] = 0x80 | cast(byte)(r>>6)&mask;
-		buf[2] = 0x80 | cast(byte)(r)&mask;
+		buf[0] = (0xe0 | r>>12) as byte ;
+		buf[1] = (0x80 | r>>6)  as byte & mask;
+		buf[2] = (0x80 | r)     as byte & mask;
 		return buf, 3;
 	}
 
-	buf[0] = 0xf0 | cast(byte)(r>>18);
-	buf[1] = 0x80 | cast(byte)(r>>12)&mask;
-	buf[2] = 0x80 | cast(byte)(r>>6)&mask;
-	buf[3] = 0x80 | cast(byte)(r)&mask;
+	buf[0] = (0xf0 | r>>18) as byte;
+	buf[1] = (0x80 | r>>12) as byte & mask;
+	buf[2] = (0x80 | r>>6)  as byte & mask;
+	buf[3] = (0x80 | r)     as byte & mask;
 	return buf, 4;
 }
 
 print_rune :: proc(r : rune) {
 	buf, n := encode_rune(r);
-	str := cast(string)buf[:n];
+	str := buf[:n] as string;
 	print_string(str);
 }
 
@@ -59,7 +59,7 @@ print_int :: proc(i : int) {
 print_int_base :: proc(i, base : int) {
 	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
 
-	buf: [21]byte;
+	buf: [65]byte;
 	len := 0;
 	negative := false;
 	if i < 0 {
@@ -82,5 +82,57 @@ print_int_base :: proc(i, base : int) {
 	}
 
 	byte_reverse(buf[:len]);
-	print_string(cast(string)buf[:len]);
+	print_string(buf[:len] as string);
 }
+
+print_uint :: proc(i : uint) {
+	print_uint_base(i, 10);
+}
+print_uint_base :: proc(i, base : uint) {
+	NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
+
+	buf: [65]byte;
+	len := 0;
+	negative := false;
+	if i < 0 {
+		negative = true;
+		i = -i;
+	}
+	if i == 0 {
+		buf[len] = '0';
+		len++;
+	}
+	for i > 0 {
+		buf[len] = NUM_TO_CHAR_TABLE[i % base];
+		len++;
+		i /= base;
+	}
+
+	if negative {
+		buf[len] = '-';
+		len++;
+	}
+
+	byte_reverse(buf[:len]);
+	print_string(buf[:len] as string);
+}
+
+
+// f64
+
+
+print_f64 :: proc(f : f64) {
+	buf: [128]byte;
+
+	if f == 0 {
+		value : u64;
+
+	} else {
+		if f < 0 {
+			print_rune('-');
+		}
+		print_rune('0');
+	}
+
+}
+

+ 261 - 166
examples/main.ll

@@ -4,142 +4,62 @@
 
 declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1)
 
-%main.Vec2 = type <2 x float>
-define void @exec(i64 ()* %p) {
-"entry - 0":
-	%0 = alloca i64 ()*, align 8 ; p
-	store i64 ()* zeroinitializer, i64 ()** %0
-	store i64 ()* %p, i64 ()** %0
-	%1 = load i64 ()*, i64 ()** %0
-	%2 = call i64 %1()
-	call void @print_int(i64 %2)
-	call void @print_rune(i32 10)
-	ret void
-}
-
 define void @main() {
 "entry - 0":
-	%0 = alloca i64, align 8 ; i
-	store i64 zeroinitializer, i64* %0
-	store i64 123, i64* %0
-	%1 = load i64, i64* %0
-	call void @print_int(i64 %1)
-	call void @print_rune(i32 128149)
-	call void @print_rune(i32 10)
-	%2 = alloca %main.Vec2, align 2 ; v
-	store %main.Vec2 zeroinitializer, %main.Vec2* %2
-	%3 = alloca %main.Vec2, align 2 
-	store %main.Vec2 zeroinitializer, %main.Vec2* %3
-	%4 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 0
-	store float 0x3ff0000000000000, float* %4
-	%5 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 1
-	store float 0x4000000000000000, float* %5
-	%6 = load %main.Vec2, %main.Vec2* %3
-	store %main.Vec2 %6, %main.Vec2* %2
-	%7 = alloca [4 x i64], align 8 ; a
-	store [4 x i64] zeroinitializer, [4 x i64]* %7
-	%8 = alloca [4 x i64], align 8 
-	store [4 x i64] zeroinitializer, [4 x i64]* %8
-	%9 = load i64, i64* %0
-	%10 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 0
-	store i64 %9, i64* %10
-	%11 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 1
-	store i64 2, i64* %11
-	%12 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 2
-	store i64 3, i64* %12
-	%13 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 3
-	store i64 7, i64* %13
-	%14 = load [4 x i64], [4 x i64]* %8
-	store [4 x i64] %14, [4 x i64]* %7
-	%15 = alloca [4 x i64], align 8 ; e
-	store [4 x i64] zeroinitializer, [4 x i64]* %15
-	%16 = alloca [4 x i64], align 8 
-	store [4 x i64] zeroinitializer, [4 x i64]* %16
-	%17 = load i64, i64* %0
-	%18 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 0
-	store i64 %17, i64* %18
-	%19 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 1
-	store i64 2, i64* %19
-	%20 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 2
-	store i64 3, i64* %20
-	%21 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 3
-	store i64 7, i64* %21
-	%22 = load [4 x i64], [4 x i64]* %16
-	store [4 x i64] %22, [4 x i64]* %15
-	%23 = alloca {i64*, i64, i64}, align 8 ; s
-	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %23
-	%24 = alloca {i64*, i64, i64}, align 8 
-	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %24
-	%25 = alloca [4 x i64], align 8 
-	store [4 x i64] zeroinitializer, [4 x i64]* %25
-	%26 = load i64, i64* %0
-	%27 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
-	store i64 %26, i64* %27
-	%28 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 1
-	store i64 2, i64* %28
-	%29 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 2
-	store i64 3, i64* %29
-	%30 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 3
-	store i64 7, i64* %30
-	%31 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
-	%32 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 0
-	store i64* %31, i64** %32
-	%33 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 1
-	store i64 4, i64* %33
-	%34 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 2
-	store i64 4, i64* %34
-	%35 = load {i64*, i64, i64}, {i64*, i64, i64}* %24
-	store {i64*, i64, i64} %35, {i64*, i64, i64}* %23
-	%36 = alloca i64, align 8 ; i
-	store i64 zeroinitializer, i64* %36
-	store i64 0, i64* %36
-	br label %"for.loop - 2"
-
-"for.body - 1":
-	%37 = getelementptr inbounds [4 x i64], [4 x i64]* %7, i64 0, i64 0
-	%38 = load i64, i64* %36
-	%39 = getelementptr i64, i64* %37, i64 %38
-	%40 = load i64, i64* %39
-	call void @print_int(i64 %40)
-	%41 = getelementptr inbounds [2 x i8], [2 x i8]* @.str0, i64 0, i64 0
-	%42 = alloca %.string, align 8 
-	store %.string zeroinitializer, %.string* %42
-	%43 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 0
-	%44 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 1
-	store i8* %41, i8** %43
-	store i64 2, i64* %44
-	%45 = load %.string, %.string* %42
-	call void @print_string(%.string %45)
-	br label %"for.post - 3"
-
-"for.loop - 2":
-	%46 = load i64, i64* %36
-	%47 = icmp slt i64 %46, 4
-	br i1 %47, label %"for.body - 1", label %"for.done - 4"
-
-"for.post - 3":
-	%48 = load i64, i64* %36
-	%49 = add i64 %48, 1
-	store i64 %49, i64* %36
-	br label %"for.loop - 2"
-
-"for.done - 4":
-	call void @print_rune(i32 10)
-	call void @exec(i64 ()* @main$0)
+	%0 = alloca <8 x float>, align 4 ; a
+	store <8 x float> zeroinitializer, <8 x float>* %0
+	%1 = alloca <8 x float>, align 4 ; b
+	store <8 x float> zeroinitializer, <8 x float>* %1
+	%2 = alloca <8 x float>, align 4 
+	store <8 x float> zeroinitializer, <8 x float>* %2
+	%3 = load <8 x float>, <8 x float>* %2
+	%4 = insertelement <8 x float> %3, float 0x3ff0000000000000, i64 0
+	%5 = insertelement <8 x float> %4, float 0x4000000000000000, i64 1
+	%6 = insertelement <8 x float> %5, float 0x4008000000000000, i64 2
+	%7 = insertelement <8 x float> %6, float 0x4010000000000000, i64 3
+	%8 = alloca <8 x float>, align 4 
+	store <8 x float> zeroinitializer, <8 x float>* %8
+	%9 = load <8 x float>, <8 x float>* %8
+	%10 = insertelement <8 x float> %9, float 0x3ff0000000000000, i64 0
+	%11 = insertelement <8 x float> %10, float 0x4000000000000000, i64 1
+	%12 = insertelement <8 x float> %11, float 0x4008000000000000, i64 2
+	%13 = insertelement <8 x float> %12, float 0x4010000000000000, i64 3
+	store <8 x float> %7, <8 x float>* %0
+	store <8 x float> %13, <8 x float>* %1
+	%14 = alloca <8 x i1>, align 1 ; c
+	store <8 x i1> zeroinitializer, <8 x i1>* %14
+	%15 = load <8 x float>, <8 x float>* %0
+	%16 = load <8 x float>, <8 x float>* %1
+	%17 = fcmp oeq <8 x float> %15, %16
+	store <8 x i1> %17, <8 x i1>* %14
+	%18 = alloca <32 x i1>, align 1 ; x
+	store <32 x i1> zeroinitializer, <32 x i1>* %18
+	%19 = alloca <32 x i1>, align 1 
+	store <32 x i1> zeroinitializer, <32 x i1>* %19
+	%20 = load <32 x i1>, <32 x i1>* %19
+	%21 = insertelement <32 x i1> %20, i1 true, i64 0
+	%22 = insertelement <32 x i1> %21, i1 false, i64 1
+	%23 = insertelement <32 x i1> %22, i1 true, i64 2
+	store <32 x i1> %23, <32 x i1>* %18
+	%24 = alloca i32, align 4 ; d
+	store i32 zeroinitializer, i32* %24
+	%25 = alloca i32*, align 8 
+	store i32* zeroinitializer, i32** %25
+	%26 = getelementptr inbounds <32 x i1>, <32 x i1>* %18, i64 0, i32 0
+	%27 = getelementptr i1, i1* %26, i64 0
+	%28 = getelementptr inbounds i1, i1* %27
+	%29 = bitcast i1* %28 to i32*
+	store i32* %29, i32** %25
+	%30 = load i32*, i32** %25
+	%31 = getelementptr i32, i32* %30
+	%32 = load i32, i32* %31
+	store i32 %32, i32* %24
+	%33 = load i32, i32* %24
+	%34 = zext i32 %33 to i64
+	call void @print_int_base(i64 %34, i64 2)
 	ret void
 }
 
-define i64 @main$0() {
-"entry - 0":
-	%0 = alloca i64, align 8 ; i
-	store i64 zeroinitializer, i64* %0
-	store i64 1337, i64* %0
-	call void @print_rune(i32 128149)
-	call void @print_rune(i32 10)
-	%1 = load i64, i64* %0
-	ret i64 %1
-}
-
 declare i32 @putchar(i32 %c) 	; foreign procedure
 
 define void @print_string(%.string %s) {
@@ -281,15 +201,15 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
 	%18 = getelementptr i8, i8* %17, i64 0
 	%19 = load i32, i32* %0
 	%20 = lshr i32 %19, 6
-	%21 = trunc i32 %20 to i8
-	%22 = or i8 192, %21
+	%21 = or i32 192, %20
+	%22 = trunc i32 %21 to i8
 	store i8 %22, i8* %18
 	%23 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%24 = getelementptr i8, i8* %23, i64 1
 	%25 = load i32, i32* %0
-	%26 = trunc i32 %25 to i8
-	%27 = and i8 %26, 63
-	%28 = or i8 128, %27
+	%26 = or i32 128, %25
+	%27 = trunc i32 %26 to i8
+	%28 = and i8 %27, 63
 	store i8 %28, i8* %24
 	%29 = alloca {[4 x i8], i64}, align 8 
 	store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %29
@@ -330,23 +250,23 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
 	%43 = getelementptr i8, i8* %42, i64 0
 	%44 = load i32, i32* %0
 	%45 = lshr i32 %44, 12
-	%46 = trunc i32 %45 to i8
-	%47 = or i8 224, %46
+	%46 = or i32 224, %45
+	%47 = trunc i32 %46 to i8
 	store i8 %47, i8* %43
 	%48 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%49 = getelementptr i8, i8* %48, i64 1
 	%50 = load i32, i32* %0
 	%51 = lshr i32 %50, 6
-	%52 = trunc i32 %51 to i8
-	%53 = and i8 %52, 63
-	%54 = or i8 128, %53
+	%52 = or i32 128, %51
+	%53 = trunc i32 %52 to i8
+	%54 = and i8 %53, 63
 	store i8 %54, i8* %49
 	%55 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%56 = getelementptr i8, i8* %55, i64 2
 	%57 = load i32, i32* %0
-	%58 = trunc i32 %57 to i8
-	%59 = and i8 %58, 63
-	%60 = or i8 128, %59
+	%58 = or i32 128, %57
+	%59 = trunc i32 %58 to i8
+	%60 = and i8 %59, 63
 	store i8 %60, i8* %56
 	%61 = alloca {[4 x i8], i64}, align 8 
 	store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %61
@@ -363,31 +283,31 @@ define {[4 x i8], i64} @encode_rune(i32 %r) {
 	%67 = getelementptr i8, i8* %66, i64 0
 	%68 = load i32, i32* %0
 	%69 = lshr i32 %68, 18
-	%70 = trunc i32 %69 to i8
-	%71 = or i8 240, %70
+	%70 = or i32 240, %69
+	%71 = trunc i32 %70 to i8
 	store i8 %71, i8* %67
 	%72 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%73 = getelementptr i8, i8* %72, i64 1
 	%74 = load i32, i32* %0
 	%75 = lshr i32 %74, 12
-	%76 = trunc i32 %75 to i8
-	%77 = and i8 %76, 63
-	%78 = or i8 128, %77
+	%76 = or i32 128, %75
+	%77 = trunc i32 %76 to i8
+	%78 = and i8 %77, 63
 	store i8 %78, i8* %73
 	%79 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%80 = getelementptr i8, i8* %79, i64 2
 	%81 = load i32, i32* %0
 	%82 = lshr i32 %81, 6
-	%83 = trunc i32 %82 to i8
-	%84 = and i8 %83, 63
-	%85 = or i8 128, %84
+	%83 = or i32 128, %82
+	%84 = trunc i32 %83 to i8
+	%85 = and i8 %84, 63
 	store i8 %85, i8* %80
 	%86 = getelementptr inbounds [4 x i8], [4 x i8]* %1, i64 0, i64 0
 	%87 = getelementptr i8, i8* %86, i64 3
 	%88 = load i32, i32* %0
-	%89 = trunc i32 %88 to i8
-	%90 = and i8 %89, 63
-	%91 = or i8 128, %90
+	%89 = or i32 128, %88
+	%90 = trunc i32 %89 to i8
+	%91 = and i8 %90, 63
 	store i8 %91, i8* %87
 	%92 = alloca {[4 x i8], i64}, align 8 
 	store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %92
@@ -469,8 +389,8 @@ define void @print_int_base(i64 %i, i64 %base) {
 	%1 = alloca i64, align 8 ; base
 	store i64 zeroinitializer, i64* %1
 	store i64 %base, i64* %1
-	%2 = alloca [21 x i8], align 1 ; buf
-	store [21 x i8] zeroinitializer, [21 x i8]* %2
+	%2 = alloca [65 x i8], align 1 ; buf
+	store [65 x i8] zeroinitializer, [65 x i8]* %2
 	%3 = alloca i64, align 8 ; len
 	store i64 zeroinitializer, i64* %3
 	store i64 0, i64* %3
@@ -494,7 +414,7 @@ define void @print_int_base(i64 %i, i64 %base) {
 	br i1 %10, label %"if.then - 3", label %"if.done - 4"
 
 "if.then - 3":
-	%11 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
+	%11 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
 	%12 = load i64, i64* %3
 	%13 = getelementptr i8, i8* %11, i64 %12
 	store i8 48, i8* %13
@@ -507,10 +427,10 @@ define void @print_int_base(i64 %i, i64 %base) {
 	br label %"for.loop - 6"
 
 "for.body - 5":
-	%16 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
+	%16 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
 	%17 = load i64, i64* %3
 	%18 = getelementptr i8, i8* %16, i64 %17
-	%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0
+	%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str0, i64 0, i64 0
 	%20 = load i64, i64* %1
 	%21 = load i64, i64* %0
 	%22 = srem i64 %21, %20
@@ -536,7 +456,149 @@ define void @print_int_base(i64 %i, i64 %base) {
 	br i1 %32, label %"if.then - 8", label %"if.done - 9"
 
 "if.then - 8":
-	%33 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
+	%33 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
+	%34 = load i64, i64* %3
+	%35 = getelementptr i8, i8* %33, i64 %34
+	store i8 45, i8* %35
+	%36 = load i64, i64* %3
+	%37 = add i64 %36, 1
+	store i64 %37, i64* %3
+	br label %"if.done - 9"
+
+"if.done - 9":
+	%38 = load i64, i64* %3
+	%39 = sub i64 %38, 0
+	%40 = sub i64 65, 0
+	%41 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
+	%42 = getelementptr i8, i8* %41, i64 0
+	%43 = alloca {i8*, i64, i64}, align 8 
+	store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %43
+	%44 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 0
+	store i8* %42, i8** %44
+	%45 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 1
+	store i64 %39, i64* %45
+	%46 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %43, i64 0, i32 2
+	store i64 %40, i64* %46
+	%47 = load {i8*, i64, i64}, {i8*, i64, i64}* %43
+	call void @byte_reverse({i8*, i64, i64} %47)
+	%48 = load i64, i64* %3
+	%49 = sub i64 %48, 0
+	%50 = sub i64 65, 0
+	%51 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
+	%52 = getelementptr i8, i8* %51, i64 0
+	%53 = alloca {i8*, i64, i64}, align 8 
+	store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %53
+	%54 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 0
+	store i8* %52, i8** %54
+	%55 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 1
+	store i64 %49, i64* %55
+	%56 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %53, i64 0, i32 2
+	store i64 %50, i64* %56
+	%57 = load {i8*, i64, i64}, {i8*, i64, i64}* %53
+	%58 = alloca {i8*, i64, i64}, align 8 
+	store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %58
+	store {i8*, i64, i64} %57, {i8*, i64, i64}* %58
+	%59 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %58, i64 0, i32 0
+	%60 = load i8*, i8** %59
+	%61 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %58, i64 0, i32 1
+	%62 = load i64, i64* %61
+	%63 = alloca %.string, align 8 
+	store %.string zeroinitializer, %.string* %63
+	%64 = getelementptr inbounds %.string, %.string* %63, i64 0, i32 0
+	%65 = getelementptr inbounds %.string, %.string* %63, i64 0, i32 1
+	store i8* %60, i8** %64
+	store i64 %62, i64* %65
+	%66 = load %.string, %.string* %63
+	call void @print_string(%.string %66)
+	ret void
+}
+
+define void @print_uint(i64 %i) {
+"entry - 0":
+	%0 = alloca i64, align 8 ; i
+	store i64 zeroinitializer, i64* %0
+	store i64 %i, i64* %0
+	%1 = load i64, i64* %0
+	call void @print_uint_base(i64 %1, i64 10)
+	ret void
+}
+
+define void @print_uint_base(i64 %i, i64 %base) {
+"entry - 0":
+	%0 = alloca i64, align 8 ; i
+	store i64 zeroinitializer, i64* %0
+	store i64 %i, i64* %0
+	%1 = alloca i64, align 8 ; base
+	store i64 zeroinitializer, i64* %1
+	store i64 %base, i64* %1
+	%2 = alloca [65 x i8], align 1 ; buf
+	store [65 x i8] zeroinitializer, [65 x i8]* %2
+	%3 = alloca i64, align 8 ; len
+	store i64 zeroinitializer, i64* %3
+	store i64 0, i64* %3
+	%4 = alloca i1, align 1 ; negative
+	store i1 zeroinitializer, i1* %4
+	store i1 false, i1* %4
+	%5 = load i64, i64* %0
+	%6 = icmp ult i64 %5, 0
+	br i1 %6, label %"if.then - 1", label %"if.done - 2"
+
+"if.then - 1":
+	store i1 true, i1* %4
+	%7 = load i64, i64* %0
+	%8 = sub i64 0, %7
+	store i64 %8, i64* %0
+	br label %"if.done - 2"
+
+"if.done - 2":
+	%9 = load i64, i64* %0
+	%10 = icmp eq i64 %9, 0
+	br i1 %10, label %"if.then - 3", label %"if.done - 4"
+
+"if.then - 3":
+	%11 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
+	%12 = load i64, i64* %3
+	%13 = getelementptr i8, i8* %11, i64 %12
+	store i8 48, i8* %13
+	%14 = load i64, i64* %3
+	%15 = add i64 %14, 1
+	store i64 %15, i64* %3
+	br label %"if.done - 4"
+
+"if.done - 4":
+	br label %"for.loop - 6"
+
+"for.body - 5":
+	%16 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
+	%17 = load i64, i64* %3
+	%18 = getelementptr i8, i8* %16, i64 %17
+	%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0
+	%20 = load i64, i64* %1
+	%21 = load i64, i64* %0
+	%22 = urem i64 %21, %20
+	%23 = getelementptr i8, i8* %19, i64 %22
+	%24 = load i8, i8* %23
+	store i8 %24, i8* %18
+	%25 = load i64, i64* %3
+	%26 = add i64 %25, 1
+	store i64 %26, i64* %3
+	%27 = load i64, i64* %1
+	%28 = load i64, i64* %0
+	%29 = udiv i64 %28, %27
+	store i64 %29, i64* %0
+	br label %"for.loop - 6"
+
+"for.loop - 6":
+	%30 = load i64, i64* %0
+	%31 = icmp ugt i64 %30, 0
+	br i1 %31, label %"for.body - 5", label %"for.done - 7"
+
+"for.done - 7":
+	%32 = load i1, i1* %4
+	br i1 %32, label %"if.then - 8", label %"if.done - 9"
+
+"if.then - 8":
+	%33 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
 	%34 = load i64, i64* %3
 	%35 = getelementptr i8, i8* %33, i64 %34
 	store i8 45, i8* %35
@@ -548,8 +610,8 @@ define void @print_int_base(i64 %i, i64 %base) {
 "if.done - 9":
 	%38 = load i64, i64* %3
 	%39 = sub i64 %38, 0
-	%40 = sub i64 21, 0
-	%41 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
+	%40 = sub i64 65, 0
+	%41 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
 	%42 = getelementptr i8, i8* %41, i64 0
 	%43 = alloca {i8*, i64, i64}, align 8 
 	store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %43
@@ -563,8 +625,8 @@ define void @print_int_base(i64 %i, i64 %base) {
 	call void @byte_reverse({i8*, i64, i64} %47)
 	%48 = load i64, i64* %3
 	%49 = sub i64 %48, 0
-	%50 = sub i64 21, 0
-	%51 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
+	%50 = sub i64 65, 0
+	%51 = getelementptr inbounds [65 x i8], [65 x i8]* %2, i64 0, i64 0
 	%52 = getelementptr i8, i8* %51, i64 0
 	%53 = alloca {i8*, i64, i64}, align 8 
 	store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %53
@@ -593,5 +655,38 @@ define void @print_int_base(i64 %i, i64 %base) {
 	ret void
 }
 
[email protected] = global [2 x i8] c"\2C\20"
+define void @print_f64(double %f) {
+"entry - 0":
+	%0 = alloca double, align 8 ; f
+	store double zeroinitializer, double* %0
+	store double %f, double* %0
+	%1 = alloca [128 x i8], align 1 ; buf
+	store [128 x i8] zeroinitializer, [128 x i8]* %1
+	%2 = load double, double* %0
+	%3 = fcmp oeq double %2, 0x0000000000000000
+	br i1 %3, label %"if.then - 1", label %"if.else - 2"
+
+"if.then - 1":
+	%4 = alloca i64, align 8 ; value
+	store i64 zeroinitializer, i64* %4
+	br label %"if.done - 5"
+
+"if.else - 2":
+	%5 = load double, double* %0
+	%6 = fcmp olt double %5, 0x0000000000000000
+	br i1 %6, label %"if.then - 3", label %"if.done - 4"
+
+"if.then - 3":
+	call void @print_rune(i32 45)
+	br label %"if.done - 4"
+
+"if.done - 4":
+	call void @print_rune(i32 48)
+	br label %"if.done - 5"
+
+"if.done - 5":
+	ret void
+}
+
[email protected] = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"
 @.str1 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"

+ 40 - 45
examples/main.odin

@@ -2,53 +2,48 @@ import "basic"
 
 TWO_HEARTS :: '💕';
 
-
-exec :: proc(p : proc() -> int) {
-	print_int(p());
-	print_rune('\n');
-}
-
 main :: proc() {
-	i := 123;
-	print_int(i);
-	print_rune(TWO_HEARTS);
-	print_rune('\n');
-
-	type Vec2: {2}f32;
-
-	v := Vec2{1, 2};
-	a := [4] int{i, 2, 3, 7};
-	e := [..]int{i, 2, 3, 7};
-	s := []  int{i, 2, 3, 7};
-
-	for i := 0; i < len(a); i++ {
-		print_int(a[i]);
-		print_string(", ");
-	}
-	print_rune('\n');
-
-	exec(proc() -> int {
-		i : int = 1337;
-		print_rune('💕');
-		print_rune('\n');
-		return i;
-	});
+	a, b := {8}f32{1, 2, 3, 4}, {8}f32{1, 2, 3, 4};
+	c := a == b;
+	x := {32}bool{true, false, true};
+	d := ((^x[0]) as ^u32)^;
+	print_int_base(d as int, 2);
+	// print_string("\n");
+	// print_int(x[0] as int);
+	// print_int(x[1] as int);
+	// print_int(x[2] as int);
+	// print_string("\n");
+
+	// for i := 0; false && i < len(x); i++ {
+	// 	v := x[i];
+	// 	print_int(v);
+	// 	print_string("\n");
+	// }
+
+	// for i := 0; i < len(c); i++ {
+	// 	if i > 0 {
+	// 		print_string("\n");
+	// 	}
+	// 	print_int(a[i] as int);
+	// 	print_string(" == ");
+	// 	print_int(b[i] as int);
+	// 	print_string(" => ");
+	// 	print_int(c[i] as int);
+	// }
+	// print_rune('\n');
 }
 
 /*
-if false {
-	print_string("Chinese    - 你好世界\n");
-	print_string("Dutch      - Hello wereld\n");
-	print_string("English    - Hello world\n");
-	print_string("French     - Bonjour monde\n");
-	print_string("German     - Hallo Welt\n");
-	print_string("Greek      - γειά σου κόσμος\n");
-	print_string("Italian    - Ciao mondo\n");
-	print_string("Japanese   - こんにちは世界\n");
-	print_string("Korean     - 여보세요 세계\n");
-	print_string("Portuguese - Olá mundo\n");
-	print_string("Russian    - Здравствулте мир\n");
-	print_string("Spanish    - Hola mundo\n");
-}
+"Chinese    - 你好世界\n"
+"Dutch      - Hello wereld\n"
+"English    - Hello world\n"
+"French     - Bonjour monde\n"
+"German     - Hallo Welt\n"
+"Greek      - γειά σου κόσμος\n"
+"Italian    - Ciao mondo\n"
+"Japanese   - こんにちは世界\n"
+"Korean     - 여보세요 세계\n"
+"Portuguese - Olá mundo\n"
+"Russian    - Здравствулте мир\n"
+"Spanish    - Hola mundo\n"
 */
-

+ 137 - 107
src/checker/expr.cpp

@@ -384,11 +384,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
 		Type *elem = check_type(c, vt->elem);
 		Type *be = get_base_type(elem);
 		i64 count = check_array_count(c, vt->count);
-		if (!is_type_vector(be) &&
-			!(is_type_boolean(be) || is_type_numeric(be))) {
+		if (!is_type_boolean(be) && !is_type_numeric(be)) {
 			err_str = type_to_string(elem);
-			error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be a boolean, numerical, or vector. Got `%s`", err_str);
-		} else {
+			error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be numerical or a boolean. Got `%s`", err_str);
 		}
 		type = make_type_vector(c->allocator, elem, count);
 		set_base_type(named_type, type);
@@ -433,7 +431,7 @@ end:
 
 b32 check_unary_op(Checker *c, Operand *o, Token op) {
 	// TODO(bill): Handle errors correctly
-	Type *type = get_base_type(base_vector_type(o->type));
+	Type *type = get_base_type(base_vector_type(get_base_type(o->type)));
 	gbString str = NULL;
 	defer (gb_string_free(str));
 	switch (op.kind) {
@@ -702,13 +700,11 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
 		update_expr_type(c, y->expr, default_type(y->type), true);
 	}
 
-	if (is_type_vector(x->type)) {
-		Type *vec_bool = NULL;
-		do {
-		} while (is_type_vector(x->type->vector.elem));
+	if (is_type_vector(get_base_type(y->type))) {
+		x->type = make_type_vector(c->allocator, t_bool, get_base_type(y->type)->vector.count);
+	} else {
+		x->type = t_untyped_bool;
 	}
-	x->type = t_untyped_bool;
-
 }
 
 void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
@@ -805,6 +801,101 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 	x->mode = Addressing_Value;
 }
 
+b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
+	if (check_is_assignable_to(c, operand, y))
+		return true;
+
+	Type *x = operand->type;
+	Type *xb = get_base_type(x);
+	Type *yb = get_base_type(y);
+	if (are_types_identical(xb, yb))
+		return true;
+
+
+	// Cast between booleans and integers
+	if (is_type_boolean(x) || is_type_integer(x)) {
+		if (is_type_boolean(y) || is_type_integer(y))
+			return true;
+	}
+
+	// Cast between numbers
+	if (is_type_integer(x) || is_type_float(x)) {
+		if (is_type_integer(y) || is_type_float(y))
+			return true;
+	}
+
+	// Cast between pointers
+	if (is_type_pointer(x)) {
+		if (is_type_pointer(y))
+			return true;
+	}
+
+	// untyped integers -> pointers
+	if (is_type_untyped(xb) && is_type_integer(xb)) {
+		if (is_type_pointer(yb))
+			return true;
+	}
+
+	// (u)int <-> pointer
+	if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
+		if (is_type_pointer(yb))
+			return true;
+	}
+	if (is_type_pointer(xb)) {
+		if (is_type_pointer(yb) || is_type_int_or_uint(yb))
+			return true;
+	}
+
+	// []byte/[]u8 <-> string
+	if (is_type_u8_slice(xb) && is_type_string(yb)) {
+		return true;
+	}
+	if (is_type_string(xb) && is_type_u8_slice(yb)) {
+		return true;
+	}
+
+	return false;
+}
+
+void check_cast_expr(Checker *c, Operand *operand, Type *type) {
+	b32 is_const_expr = operand->mode == Addressing_Constant;
+	b32 can_convert = false;
+
+	if (is_const_expr && is_type_constant_type(type)) {
+		Type *t = get_base_type(type);
+		if (t->kind == Type_Basic) {
+			if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
+				can_convert = true;
+			}
+		}
+	} else if (check_castable_to(c, operand, type)) {
+		operand->mode = Addressing_Value;
+		can_convert = true;
+	}
+
+	if (!can_convert) {
+		gbString expr_str = expr_to_string(operand->expr);
+		gbString type_str = type_to_string(type);
+		defer (gb_string_free(expr_str));
+		defer (gb_string_free(type_str));
+		error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
+
+		operand->mode = Addressing_Invalid;
+		return;
+	}
+
+	if (is_type_untyped(operand->type)) {
+		Type *final_type = type;
+		if (is_const_expr && !is_type_constant_type(type)) {
+			final_type = default_type(operand->type);
+		}
+		update_expr_type(c, operand->expr, final_type, true);
+	}
+
+	operand->type = type;
+}
+
+
 void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	GB_ASSERT(node->kind == AstNode_BinaryExpr);
 	Operand y_ = {}, *y = &y_;
@@ -813,6 +904,15 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 
 	ast_node(be, BinaryExpr, node);
 
+	if (be->op.kind == Token_as) {
+		check_expr(c, x, be->left);
+		Type *cast_type = check_type(c, be->right);
+		if (x->mode == Addressing_Invalid)
+			return;
+		check_cast_expr(c, x, cast_type);
+		return;
+	}
+
 	check_expr(c, x, be->left);
 	check_expr(c, y, be->right);
 	if (x->mode == Addressing_Invalid) {
@@ -890,7 +990,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	}
 
 	if (x->mode == Addressing_Constant &&
-	    y->mode  == Addressing_Constant) {
+	    y->mode == Addressing_Constant) {
 		ExactValue a = x->value;
 		ExactValue b = y->value;
 
@@ -943,7 +1043,18 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
 		found->type = get_base_type(type);
 		map_set(&c->info.untyped, key, *found);
 	} else {
+		ExpressionInfo old = *found;
 		map_remove(&c->info.untyped, key);
+
+		if (old.is_lhs && !is_type_integer(type)) {
+			gbString expr_str = expr_to_string(e);
+			gbString type_str = type_to_string(type);
+			defer (gb_string_free(expr_str));
+			defer (gb_string_free(type_str));
+			error(&c->error_collector, ast_node_token(e), "Shifted operand %s must be an integer, got %s", expr_str, type_str);
+			return;
+		}
+
 		add_type_and_value(&c->info, e, found->mode, type, found->value);
 	}
 }
@@ -1349,6 +1460,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 			value = make_exact_value_integer(t->array.count);
 			break;
 
+		case Type_Vector:
+			mode = Addressing_Constant;
+			value = make_exact_value_integer(t->vector.count);
+			break;
+
 		case Type_Slice:
 			mode = Addressing_Value;
 			break;
@@ -1600,85 +1716,6 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 	return Expression_Statement;
 }
 
-b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
-	if (check_is_assignable_to(c, operand, y))
-		return true;
-
-	Type *x = operand->type;
-	Type *xb = get_base_type(x);
-	Type *yb = get_base_type(y);
-	if (are_types_identical(xb, yb))
-		return true;
-
-	// Cast between numbers
-	if (is_type_integer(x) || is_type_float(x)) {
-		if (is_type_integer(y) || is_type_float(y))
-			return true;
-	}
-
-	// Cast between pointers
-	if (is_type_pointer(x)) {
-		if (is_type_pointer(y))
-			return true;
-	}
-
-	// untyped integers -> pointers
-	if (is_type_untyped(xb) && is_type_integer(xb)) {
-		if (is_type_pointer(yb))
-			return true;
-	}
-
-	// (u)int <-> pointer
-	if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
-		if (is_type_pointer(yb))
-			return true;
-	}
-	if (is_type_pointer(xb)) {
-		if (is_type_pointer(yb) || is_type_int_or_uint(yb))
-			return true;
-	}
-
-	// []byte/[]u8 <-> string
-	if (is_type_u8_slice(xb) && is_type_string(yb)) {
-		return true;
-	}
-	if (is_type_string(xb) && is_type_u8_slice(yb)) {
-		return true;
-	}
-
-	return false;
-}
-
-void check_cast_expr(Checker *c, Operand *operand, Type *type) {
-	b32 is_const_expr = operand->mode == Addressing_Constant;
-	b32 can_convert = false;
-
-	if (is_const_expr && is_type_constant_type(type)) {
-		Type *t = get_base_type(type);
-		if (t->kind == Type_Basic) {
-			if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
-				can_convert = true;
-			}
-		}
-	} else if (check_castable_to(c, operand, type)) {
-		operand->mode = Addressing_Value;
-		can_convert = true;
-	}
-
-	if (!can_convert) {
-		gbString expr_str = expr_to_string(operand->expr);
-		gbString type_str = type_to_string(type);
-		defer (gb_string_free(expr_str));
-		defer (gb_string_free(type_str));
-		error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
-
-		operand->mode = Addressing_Invalid;
-		return;
-	}
-
-	operand->type = type;
-}
-
 void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
 	check_expr_base(c, o, e, t);
 	check_not_tuple(c, o);
@@ -1924,6 +1961,15 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 			o->type = t->array.elem;
 			break;
 
+		case Type_Vector:
+			valid = true;
+			max_count = t->vector.count;
+			if (o->mode != Addressing_Variable)
+				o->mode = Addressing_Value;
+			o->type = t->vector.elem;
+			break;
+
+
 		case Type_Slice:
 			valid = true;
 			o->type = t->slice.elem;
@@ -2039,15 +2085,6 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 	case_end;
 
 
-	case_ast_node(ce, CastExpr, node);
-		Type *cast_type = check_type(c, ce->type);
-		check_expr_or_type(c, o, ce->expr);
-		if (o->mode != Addressing_Invalid)
-			check_cast_expr(c, o, cast_type);
-
-	case_end;
-
-
 	case_ast_node(ce, CallExpr, node);
 		return check_call_expr(c, o, node);
 	case_end;
@@ -2287,13 +2324,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "]");
 	case_end;
 
-	case_ast_node(ce, CastExpr, node);
-		str = gb_string_appendc(str, "cast(");
-		str = write_expr_to_string(str, ce->type);
-		str = gb_string_appendc(str, ")");
-		str = write_expr_to_string(str, ce->expr);
-	case_end;
-
 	case_ast_node(e, Ellipsis, node);
 		str = gb_string_appendc(str, "..");
 	case_end;

+ 21 - 15
src/checker/type.cpp

@@ -39,11 +39,12 @@ enum BasicFlag : u32 {
 	BasicFlag_Float    = GB_BIT(3),
 	BasicFlag_Pointer  = GB_BIT(4),
 	BasicFlag_String   = GB_BIT(5),
-	BasicFlag_Untyped  = GB_BIT(6),
+	BasicFlag_Rune     = GB_BIT(6),
+	BasicFlag_Untyped  = GB_BIT(7),
 
 	BasicFlag_Numeric      = BasicFlag_Integer | BasicFlag_Float,
 	BasicFlag_Ordered      = BasicFlag_Numeric | BasicFlag_String  | BasicFlag_Pointer,
-	BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer,
+	BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_String | BasicFlag_Rune,
 };
 
 struct BasicType {
@@ -130,10 +131,11 @@ struct Type {
 
 Type *get_base_type(Type *t) {
 	while (t->kind == Type_Named || t->kind == Type_Alias) {
-		if (t->kind == Type_Named)
+		if (t->kind == Type_Named) {
 			t = t->named.base;
-		else
+		} else {
 			t = t->alias.base;
+		}
 	}
 	return t;
 }
@@ -381,8 +383,8 @@ b32 is_type_vector(Type *t) {
 	return t->kind == Type_Vector;
 }
 Type *base_vector_type(Type *t) {
-	while (is_type_vector(t)) {
-		t = t->vector.elem;
+	if (is_type_vector(t)) {
+		return t->vector.elem;
 	}
 	return t;
 }
@@ -520,7 +522,7 @@ struct BaseTypeSizes {
 // TODO(bill): Change
 gb_global i64 basic_type_sizes[] = {
 	0,  // Basic_Invalid
-	1,  // Basic_bool // TODO(bill): What size should this be? And should I have different booleans?
+	1,  // Basic_bool
 	1,  // Basic_i8
 	2,  // Basic_i16
 	4,  // Basic_i32
@@ -531,13 +533,10 @@ gb_global i64 basic_type_sizes[] = {
 	4,  // Basic_u32
 	8,  // Basic_u64
 	16, // Basic_u128
-	2,  // Basic_f16
 	4,  // Basic_f32
 	8,  // Basic_f64
-	16, // Basic_f128
 };
 
-
 i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
 i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
 i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index);
@@ -635,11 +634,18 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 		i64 count = t->vector.count;
 		if (count == 0)
 			return 0;
-		count = next_pow2(count);
-		i64 align = type_align_of(s, allocator, t->vector.elem);
-		i64 size  = type_size_of(s,  allocator, t->vector.elem);
-		i64 alignment = align_formula(size, align);
-		return alignment*(count-1) + size;
+		// i64 align = type_align_of(s, allocator, t->vector.elem);
+		i64 bit_size = 8*type_size_of(s,  allocator, t->vector.elem);
+		if (is_type_boolean(t->vector.elem)) {
+			bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
+			              // Silly LLVM spec
+		}
+		i64 total_size_in_bits = bit_size * count;
+		i64 total_size = (total_size_in_bits+7)/8;
+		return total_size;
+
+		// i64 alignment = align_formula(size, align);
+		// return alignment*(count-1) + size;
 	} break;
 
 

+ 1 - 1
src/codegen/codegen.cpp

@@ -94,7 +94,7 @@ void ssa_gen_code(ssaGen *s) {
 			ssa_build_proc(v, NULL);
 	}
 
-	// m->layout = make_string("e-p:64:64:64");
+	// m->layout = make_string("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
 
 	ssa_print_llvm_ir(&s->output_file, &s->module);
 }

+ 29 - 5
src/codegen/print_llvm.cpp

@@ -393,10 +393,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 
 	case ssaInstr_BinaryOp: {
 		auto *bo = &value->instr.binary_op;
-		Type *type = ssa_value_type(bo->left);
+		Type *type = get_base_type(ssa_value_type(bo->left));
 		Type *elem_type = type;
 		while (elem_type->kind == Type_Vector) {
-			elem_type = elem_type->vector.elem;
+			elem_type = get_base_type(elem_type->vector.elem);
 		}
 
 		ssa_fprintf(f, "%%%d = ", value->id);
@@ -535,13 +535,37 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
 			vol_str = "true";
 		}
 		ssa_fprintf(f, ", i32 %d, i1 %s)\n", instr->copy_memory.align, vol_str);
+	} break;
+
+
+	case ssaInstr_InsertElement: {
+		auto *ie = &instr->insert_element;
+		Type *vt = ssa_value_type(ie->vector);
+		ssa_fprintf(f, "%%%d = insertelement ", value->id);
+
+		ssa_print_type(f, m->sizes, vt);
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, ie->vector, vt);
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m->sizes, ssa_value_type(ie->elem));
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, ie->elem, ssa_value_type(ie->elem));
+		ssa_fprintf(f, ", ");
+
+		ssa_print_type(f, m->sizes, ssa_value_type(ie->index));
+		ssa_fprintf(f, " ");
+		ssa_print_value(f, m, ie->index, ssa_value_type(ie->index));
+
+		ssa_fprintf(f, "\n");
 
 	} break;
 
-	default:
+
+	default: {
 		GB_PANIC("<unknown instr> %d\n", instr->kind);
 		ssa_fprintf(f, "; <unknown instr> %d\n", instr->kind);
-		break;
+	} break;
 	}
 }
 
@@ -613,7 +637,7 @@ void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
 
 void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
 	if (m->layout.len > 0) {
-		ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
+		ssa_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
 	}
 
 	ssa_print_encoded_local(f, make_string(".string"));

+ 205 - 95
src/codegen/ssa.cpp

@@ -69,6 +69,9 @@ struct ssaProcedure {
 	SSA_INSTR_KIND(BinaryOp), \
 	SSA_INSTR_KIND(Call), \
 	SSA_INSTR_KIND(CopyMemory), \
+	SSA_INSTR_KIND(ExtractElement), \
+	SSA_INSTR_KIND(InsertElement), \
+	SSA_INSTR_KIND(ShuffleVector), \
 	SSA_INSTR_KIND(Count),
 
 enum ssaInstrKind {
@@ -178,6 +181,16 @@ struct ssaInstr {
 			i32 align;
 			b32 is_volatile;
 		} copy_memory;
+
+		struct {
+			ssaValue *vector;
+			ssaValue *index;
+		} extract_element;
+		struct {
+			ssaValue *vector;
+			ssaValue *elem;
+			ssaValue *index;
+		} insert_element;
 	};
 };
 
@@ -236,36 +249,16 @@ gb_global ssaValue *v_two32   = NULL;
 gb_global ssaValue *v_false   = NULL;
 gb_global ssaValue *v_true    = NULL;
 
-enum ssaLvalueKind {
-	ssaLvalue_Blank,
-	ssaLvalue_Address,
-
-	ssaLvalue_Count,
-};
-
 struct ssaLvalue {
-	ssaLvalueKind kind;
-	union {
-		struct {} blank;
-		struct {
-			ssaValue *value;
-			AstNode *expr;
-		} address;
-	};
-};
-
-
-
-
-
-ssaLvalue ssa_make_lvalue_address(ssaValue *value, AstNode *expr) {
-	ssaLvalue lval = {ssaLvalue_Address};
-	lval.address.value = value;
-	lval.address.expr = expr;
-	return lval;
+	ssaValue *address;
+	AstNode *expr;};
+ssaLvalue ssa_make_lvalue(ssaValue *address, AstNode *expr) {
+	ssaLvalue v = {address, expr};
+	return v;
 }
 
 
+
 void ssa_module_init(ssaModule *m, Checker *c) {
 	isize token_count = c->parser->total_token_count;
 	isize arena_size = 3 * token_count * gb_size_of(ssaValue);
@@ -323,6 +316,13 @@ Type *ssa_instr_type(ssaInstr *instr) {
 	}
 	case ssaInstr_CopyMemory:
 		return t_int;
+
+	case ssaInstr_ExtractElement: {
+		Type *vt = ssa_value_type(instr->extract_element.vector);
+		return base_vector_type(get_base_type(vt));
+	} break;
+	case ssaInstr_InsertElement:
+		return ssa_value_type(instr->insert_element.vector);
 	}
 	return NULL;
 }
@@ -477,8 +477,8 @@ ssaValue *ssa_make_instr_load(ssaProcedure *p, ssaValue *address) {
 }
 
 ssaValue *ssa_make_instr_get_element_ptr(ssaProcedure *p, ssaValue *address,
-                                               ssaValue *index0, ssaValue *index1, isize index_count,
-                                               b32 inbounds) {
+                                         ssaValue *index0, ssaValue *index1, isize index_count,
+                                         b32 inbounds) {
 	ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_GetElementPtr);
 	ssaInstr *i = &v->instr;
 	i->get_element_ptr.address = address;
@@ -598,6 +598,34 @@ ssaValue *ssa_make_instr_conv(ssaProcedure *p, ssaConvKind kind, ssaValue *value
 	return v;
 }
 
+ssaValue *ssa_make_instr_extract_element(ssaProcedure *p, ssaValue *vector, ssaValue *index) {
+	ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_ExtractElement);
+	v->instr.extract_element.vector = vector;
+	v->instr.extract_element.index = index;
+	if (p->curr_block) {
+		gb_array_append(p->curr_block->values, v);
+	}
+	return v;
+}
+
+ssaValue *ssa_make_instr_insert_element(ssaProcedure *p, ssaValue *vector, ssaValue *elem, ssaValue *index) {
+	ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_InsertElement);
+	v->instr.insert_element.vector = vector;
+	v->instr.insert_element.elem   = elem;
+	v->instr.insert_element.index  = index;
+	if (p->curr_block) {
+		gb_array_append(p->curr_block->values, v);
+	}
+	return v;
+}
+
+
+
+
+
+
+
+
 
 
 
@@ -714,36 +742,23 @@ ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
 
 
 ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
-	switch (lval.kind) {
-	case ssaLvalue_Address:
-		return ssa_emit_store(p, lval.address.value, value);
+	if (lval.address != NULL) {
+		return ssa_emit_store(p, lval.address, value);
 	}
 	return NULL;
 }
 
 ssaValue *ssa_lvalue_load(ssaLvalue lval, ssaProcedure *p) {
-	switch (lval.kind) {
-	case ssaLvalue_Address:
-		return ssa_emit_load(p, lval.address.value);
+	if (lval.address != NULL) {
+		return ssa_emit_load(p, lval.address);
 	}
 	GB_PANIC("Illegal lvalue load");
 	return NULL;
 }
 
-
-ssaValue *ssa_lvalue_address(ssaLvalue lval, ssaProcedure *p) {
-	switch (lval.kind) {
-	case ssaLvalue_Address:
-		return lval.address.value;
-	}
-	return NULL;
-}
-
 Type *ssa_lvalue_type(ssaLvalue lval) {
-	switch (lval.kind) {
-	case ssaLvalue_Address:
-		// return type_deref(ssa_value_type(lval.address.value));
-		return ssa_value_type(lval.address.value);
+	if (lval.address != NULL) {
+		return type_deref(ssa_value_type(lval.address));
 	}
 	return NULL;
 }
@@ -921,7 +936,11 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
 	}
 
 	ssaValue *v = ssa_make_instr_binary_op(proc, op, left, right);
-	ssa_value_set_type(v, t_bool);
+	Type *result = t_bool;
+	if (is_type_vector(a)) {
+		result = make_type_vector(proc->module->allocator, t_bool, a->vector.count);
+	}
+	ssa_value_set_type(v, result);
 	return ssa_emit(proc, v);
 }
 
@@ -935,6 +954,15 @@ ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offse
 	return ssa_emit(proc, gep);
 }
 
+ssaValue *ssa_emit_zero_gep(ssaProcedure *proc, ssaValue *s) {
+	ssaValue *gep = NULL;
+	// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
+	gep = ssa_make_instr_get_element_ptr(proc, s, NULL, NULL, 0, true);
+	gep->instr.get_element_ptr.elem_type = ssa_value_type(s);
+	gep->instr.get_element_ptr.result_type = ssa_value_type(s);
+	return ssa_emit(proc, gep);
+}
+
 ssaValue *ssa_emit_struct_gep(ssaProcedure *proc, ssaValue *s, ssaValue *index, Type *result_type) {
 	ssaValue *gep = NULL;
 	// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
@@ -1139,14 +1167,17 @@ ssaValue *ssa_emit_string(ssaProcedure *proc, ssaValue *elem, ssaValue *len) {
 
 ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 	Type *src_type = ssa_value_type(value);
-	if (are_types_identical(t, src_type))
+	if (are_types_identical(t, src_type)) {
 		return value;
+	}
 
 	Type *src = get_base_type(src_type);
 	Type *dst = get_base_type(t);
 	if (are_types_identical(t, src_type))
 		return value;
 
+
+
 	if (value->kind == ssaValue_Constant) {
 		if (dst->kind == Type_Basic) {
 			ExactValue ev = value->constant.value;
@@ -1163,21 +1194,34 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 
 	// integer -> integer
 	if (is_type_integer(src) && is_type_integer(dst)) {
-		i64 sz = basic_type_sizes[src->basic.kind];
-		i64 dz = basic_type_sizes[dst->basic.kind];
-		ssaConvKind kind = ssaConv_trunc;
-		if (dz >= sz) {
-			kind = ssaConv_zext;
-		}
-
+		GB_ASSERT(src->kind == Type_Basic &&
+		          dst->kind == Type_Basic);
+		i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src);
+		i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst);
 		if (sz == dz) {
 			// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
 			return value;
 		}
 
+		ssaConvKind kind = ssaConv_trunc;
+		if (dz >= sz) {
+			kind = ssaConv_zext;
+		}
 		return ssa_emit(proc, ssa_make_instr_conv(proc, kind, value, src, dst));
 	}
 
+	// boolean -> integer
+	if (is_type_boolean(src) && is_type_integer(dst)) {
+		return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_zext, value, src, dst));
+	}
+
+	// integer -> boolean
+	if (is_type_integer(src) && is_type_boolean(dst)) {
+		Token op = {Token_NotEq};
+		return ssa_emit_comp(proc, op, value, v_zero);
+	}
+
+
 	// float -> float
 	if (is_type_float(src) && is_type_float(dst)) {
 		i64 sz = basic_type_sizes[src->basic.kind];
@@ -1238,6 +1282,9 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 	}
 
 
+	gb_printf("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
+
+
 	GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
 
 	return NULL;
@@ -1285,8 +1332,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_ast_node(ue, UnaryExpr, expr);
 		switch (ue->op.kind) {
 		case Token_Pointer: {
-			ssaLvalue lval = ssa_build_addr(proc, ue->expr);
-			return ssa_lvalue_address(lval, proc);
+			ssaValue *v = ssa_emit_zero_gep(proc, ssa_build_addr(proc, ue->expr).address);
+			ssa_value_set_type(v, type_of_expr(proc->module->info, expr));
+			return v;
 		}
 		case Token_Add:
 			return ssa_build_expr(proc, ue->expr);
@@ -1341,6 +1389,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			return ssa_emit_conv(proc, cmp, default_type(tv->type));
 		} break;
 
+		case Token_as:
+			return ssa_emit_conv(proc, ssa_build_expr(proc, be->left), tv->type);
+
 		default:
 			GB_PANIC("Invalid binary expression");
 			break;
@@ -1404,7 +1455,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			}
 
 		} break;
-		case Type_Vector:
 		case Type_Array: {
 			isize index = 0;
 			for (AstNode *elem = cl->elem_list;
@@ -1422,6 +1472,25 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 				}
 			}
 		} break;
+		case Type_Vector: {
+			isize index = 0;
+			ssaValue *result = ssa_emit_load(proc, v);
+			for (AstNode *elem = cl->elem_list;
+				elem != NULL;
+				elem = elem->next) {
+				ssaValue *field_expr = ssa_build_expr(proc, elem);
+				Type *t = ssa_value_type(field_expr);
+				if (t->kind != Type_Tuple) {
+					ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
+					ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(index));
+					result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
+					index++;
+				} else {
+					GB_PANIC("TODO(bill): tuples in vector literals");
+				}
+			}
+			return result;
+		} break;
 		case Type_Slice: {
 			i64 count = cl->elem_count;
 			ssaValue *array = ssa_add_local_generated(proc, make_type_array(proc->module->allocator, et, count));
@@ -1457,10 +1526,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		return ssa_emit_load(proc, v);
 	case_end;
 
-	case_ast_node(ce, CastExpr, expr);
-		return ssa_emit_conv(proc, ssa_build_expr(proc, ce->expr), tv->type);
-	case_end;
-
 	case_ast_node(ce, CallExpr, expr);
 		AstNode *p = unparen_expr(ce->proc);
 		if (p->kind == AstNode_Ident) {
@@ -1471,7 +1536,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 				case BuiltinProc_len: {
 					// len :: proc(Type) -> int
 					// NOTE(bill): len of an array is a constant expression
-					ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, ce->arg_list), proc);
+					ssaValue *v = ssa_build_addr(proc, ce->arg_list).address;
 					Type *t = get_base_type(ssa_value_type(v));
 					if (t == t_string)
 						return ssa_string_len(proc, v);
@@ -1481,7 +1546,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 				case BuiltinProc_cap: {
 					// cap :: proc(Type) -> int
 					// NOTE(bill): cap of an array is a constant expression
-					ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, ce->arg_list), proc);
+					ssaValue *v = ssa_build_addr(proc, ce->arg_list).address;
 					Type *t = get_base_type(ssa_value_type(v));
 					return ssa_slice_cap(proc, v);
 				} break;
@@ -1489,8 +1554,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					// copy :: proc(dst, src: []Type) -> int
 					AstNode *dst_node = ce->arg_list;
 					AstNode *src_node = ce->arg_list->next;
-					ssaValue *dst_slice = ssa_lvalue_address(ssa_build_addr(proc, dst_node), proc);
-					ssaValue *src_slice = ssa_lvalue_address(ssa_build_addr(proc, src_node), proc);
+					ssaValue *dst_slice = ssa_build_addr(proc, dst_node).address;
+					ssaValue *src_slice = ssa_build_addr(proc, src_node).address;
 					Type *slice_type = get_base_type(ssa_value_type(dst_slice));
 					GB_ASSERT(slice_type->kind == Type_Slice);
 					Type *elem_type = slice_type->slice.elem;
@@ -1564,11 +1629,21 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_end;
 
 	case_ast_node(se, SliceExpr, expr);
-		return ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, expr), proc));
+		return ssa_emit_load(proc, ssa_build_addr(proc, expr).address);
 	case_end;
 
 	case_ast_node(ie, IndexExpr, expr);
-		return ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, expr), proc));
+		Type *type = type_of_expr(proc->module->info, ie->expr);
+		type = get_base_type(type);
+		if (is_type_vector(type)) {
+			GB_PANIC("HERE\n");
+			// NOTE(bill): For vectors, use ExtractElement
+			ssaValue *vector = ssa_emit_load(proc, ssa_build_addr(proc, ie->expr).address);
+			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
+			return ssa_emit(proc, ssa_make_instr_extract_element(proc, vector, index));
+		} else {
+			return ssa_emit_load(proc, ssa_build_addr(proc, expr).address);
+		}
 	case_end;
 	}
 
@@ -1608,7 +1683,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	switch (expr->kind) {
 	case_ast_node(i, Ident, expr);
 		if (ssa_is_blank_ident(expr)) {
-			ssaLvalue val = {ssaLvalue_Blank};
+			ssaLvalue val = {};
 			return val;
 		}
 
@@ -1616,7 +1691,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		ssaValue *v = NULL;
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		if (found) v = *found;
-		return ssa_make_lvalue_address(v, expr);
+		return ssa_make_lvalue(v, expr);
 	case_end;
 
 	case_ast_node(pe, ParenExpr, expr);
@@ -1630,7 +1705,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		Entity *entity = lookup_field(type, unparen_expr(se->selector), &field_index);
 		GB_ASSERT(entity != NULL);
 
-		ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
+		ssaValue *e = ssa_build_addr(proc, se->expr).address;
 
 		if (type->kind == Type_Pointer) {
 			// NOTE(bill): Allow x^.y and x.y to be the same
@@ -1639,7 +1714,37 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		}
 
 		ssaValue *v = ssa_emit_struct_gep(proc, e, field_index, entity->type);
-		return ssa_make_lvalue_address(v, expr);
+		return ssa_make_lvalue(v, expr);
+	case_end;
+
+	case_ast_node(ue, UnaryExpr, expr);
+		switch (ue->op.kind) {
+		case Token_Pointer: {
+			ssaLvalue lval = ssa_build_addr(proc, ue->expr);
+			// ssaValue *v = ssa_emit_zero_gep(proc, lval.address);
+			// Type *t = ssa_value_type(lval.address);
+			// ssa_value_set_type(lval.address, make_type_pointer(proc->module->allocator, t));
+			// return ssa_make_lvalue(v, expr);
+			return lval;
+		}
+		default:
+			GB_PANIC("Invalid unary expression for ssa_build_addr");
+		}
+	case_end;
+
+	case_ast_node(be, BinaryExpr, expr);
+		switch (be->op.kind) {
+		case Token_as: {
+			// NOTE(bill): Needed for dereference of pointer conversion
+			Type *type = type_of_expr(proc->module->info, expr);
+			ssaValue *v = ssa_add_local_generated(proc, type);
+			ssa_emit_store(proc, v, ssa_emit_conv(proc, ssa_build_expr(proc, be->left), type));
+			return ssa_make_lvalue(v, expr);
+		}
+		default:
+			GB_PANIC("Invalid binary expression for ssa_build_addr: %.*s\n", LIT(be->op.string));
+			break;
+		}
 	case_end;
 
 	case_ast_node(ie, IndexExpr, expr);
@@ -1648,34 +1753,39 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		ssaValue *elem = NULL;
 		switch (t->kind) {
 		case Type_Array: {
-			ssaValue *array = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
+			ssaValue *array = ssa_build_addr(proc, ie->expr).address;
 			elem = ssa_array_elem(proc, array);
 		} break;
 		case Type_Slice: {
-			ssaValue *slice = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
+			ssaValue *slice = ssa_build_addr(proc, ie->expr).address;
 			elem = ssa_slice_elem(proc, slice);
 		} break;
+		case Type_Vector: {
+			ssaValue *vector = ssa_build_addr(proc, ie->expr).address;
+			Type *t_ptr = make_type_pointer(proc->module->allocator, t->vector.elem);
+			elem = ssa_emit_struct_gep(proc, vector, v_zero32, t_ptr);
+		} break;
 		case Type_Basic: { // Basic_string
 			TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(ie->expr));
 			if (tv->mode == Addressing_Constant) {
 				ssaValue *array = ssa_add_global_string_array(proc, tv->value);
 				elem = ssa_array_elem(proc, array);
 			} else {
-				ssaLvalue lval = ssa_build_addr(proc, ie->expr);
-				ssaValue *str = ssa_lvalue_address(lval, proc);
-				elem = ssa_string_elem(proc, str);
+				elem = ssa_string_elem(proc, ssa_build_addr(proc, ie->expr).address);
 			}
 		} break;
 		case Type_Pointer: {
-			elem = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc));
+			elem = ssa_emit_load(proc, ssa_build_addr(proc, ie->expr).address);
 		} break;
 		}
 
 		ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 		v = ssa_emit_ptr_offset(proc, elem, index);
 
-		ssa_value_set_type(v, type_deref(ssa_value_type(v)));
-		return ssa_make_lvalue_address(v, expr);
+		Type *lval_type = type_deref(ssa_value_type(v));
+		// gb_printf("%s\n", type_to_string(lval_type));
+		ssa_value_set_type(v, lval_type);
+		return ssa_make_lvalue(v, expr);
 	case_end;
 
 	case_ast_node(se, SliceExpr, expr);
@@ -1691,13 +1801,13 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		switch (type->kind) {
 		case Type_Slice:
 		case Type_Array: {
-			ssaValue *base = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
-			return ssa_make_lvalue_address(ssa_emit_slice(proc, type, base, low, high, max), expr);
+			ssaValue *base = ssa_build_addr(proc, se->expr).address;
+			return ssa_make_lvalue(ssa_emit_slice(proc, type, base, low, high, max), expr);
 		} break;
 		case Type_Basic: {
 			// NOTE(bill): max is not needed
-			ssaValue *base = ssa_lvalue_address(ssa_build_addr(proc, se->expr), proc);
-			return ssa_make_lvalue_address(ssa_emit_substring(proc, base, low, high), expr);
+			ssaValue *base = ssa_build_addr(proc, se->expr).address;
+			return ssa_make_lvalue(ssa_emit_substring(proc, base, low, high), expr);
 		} break;
 		}
 
@@ -1705,21 +1815,21 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	case_end;
 
 	case_ast_node(de, DerefExpr, expr);
-		ssaValue *e = ssa_emit_load(proc, ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc));
+		ssaValue *e = ssa_emit_load(proc, ssa_build_addr(proc, de->expr).address);
 		ssaValue *gep = ssa_make_instr_get_element_ptr(proc, e, NULL, NULL, 0, false);
 		Type *t = type_deref(get_base_type(ssa_value_type(e)));
 		gep->instr.get_element_ptr.result_type  = t;
 		gep->instr.get_element_ptr.elem_type = t;
 		ssaValue *v = ssa_emit(proc, gep);
-		return ssa_make_lvalue_address(v, expr);
+		return ssa_make_lvalue(v, expr);
 	case_end;
 	}
 
 	GB_PANIC("Unexpected address expression\n"
 	         "\tAstNode: %.*s\n", LIT(ast_node_strings[expr->kind]));
 
-	ssaLvalue blank = {ssaLvalue_Blank};
-	return blank;
+
+	return ssa_make_lvalue(NULL, NULL);
 }
 
 void ssa_build_assign_op(ssaProcedure *proc, ssaLvalue lhs, ssaValue *value, Token op) {
@@ -1787,11 +1897,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 				defer (gb_array_free(inits));
 
 				for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
-					ssaLvalue lval = {ssaLvalue_Blank};
+					ssaLvalue lval = ssa_make_lvalue(NULL, NULL);
 					if (!ssa_is_blank_ident(name)) {
 						ssa_add_local_for_identifier(proc, name);
 						lval = ssa_build_addr(proc, name);
-						GB_ASSERT(lval.address.value != NULL);
+						GB_ASSERT(lval.address != NULL);
 					}
 
 					gb_array_append(lvals, lval);
@@ -1804,8 +1914,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 				gb_for_array(i, inits) {
-					if (lvals[i].kind != ssaLvalue_Blank) {
-						ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_lvalue_type(lvals[i]));
+					if (lvals[i].address != NULL) {
+						ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_value_type(lvals[i].address));
 						ssa_lvalue_store(lvals[i], proc, v);
 					}
 				}
@@ -1825,7 +1935,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 				defer (gb_array_free(inits));
 
 				for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
-					ssaLvalue lval = {ssaLvalue_Blank};
+					ssaLvalue lval = ssa_make_lvalue(NULL, NULL);
 					if (!ssa_is_blank_ident(name)) {
 						ssa_add_local_for_identifier(proc, name);
 						lval = ssa_build_addr(proc, name);
@@ -1850,7 +1960,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 
 
 				gb_for_array(i, inits) {
-					ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_lvalue_type(lvals[i]));
+					ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_value_type(lvals[i].address));
 					ssa_lvalue_store(lvals[i], proc, v);
 				}
 			}

+ 54 - 79
src/parser.cpp

@@ -96,7 +96,6 @@ AST_NODE_KIND(_ExprBegin,       struct{}) \
 	AST_NODE_KIND(ParenExpr,    struct { AstNode *expr; Token open, close; }) \
 	AST_NODE_KIND(SelectorExpr, struct { Token token; AstNode *expr, *selector; }) \
 	AST_NODE_KIND(IndexExpr,    struct { AstNode *expr, *index; Token open, close; }) \
-	AST_NODE_KIND(CastExpr,     struct { Token token; AstNode *type, *expr; }) \
 	AST_NODE_KIND(DerefExpr,    struct { Token op; AstNode *expr; }) \
 	AST_NODE_KIND(CallExpr, struct { \
 		AstNode *proc, *arg_list; \
@@ -296,8 +295,6 @@ Token ast_node_token(AstNode *node) {
 		return node->SliceExpr.open;
 	case AstNode_Ellipsis:
 		return node->Ellipsis.token;
-	case AstNode_CastExpr:
-		return node->CastExpr.token;
 	case AstNode_DerefExpr:
 		return node->DerefExpr.op;
 	case AstNode_BadStmt:
@@ -537,15 +534,6 @@ gb_inline AstNode *make_slice_expr(AstFile *f, AstNode *expr, Token open, Token
 	return result;
 }
 
-gb_inline AstNode *make_cast_expr(AstFile *f, Token token, AstNode *type, AstNode *expr) {
-	AstNode *result = make_node(f, AstNode_CastExpr);
-	result->CastExpr.token = token;
-	result->CastExpr.type = type;
-	result->CastExpr.expr = expr;
-	return result;
-}
-
-
 gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) {
 	AstNode *result = make_node(f, AstNode_DerefExpr);
 	result->DerefExpr.expr = expr;
@@ -858,6 +846,7 @@ gb_internal void add_ast_entity(AstFile *f, AstScope *scope, AstNode *declaratio
 
 
 void fix_advance_to_next_stmt(AstFile *f) {
+	// TODO(bill): fix_advance_to_next_stmt
 #if 0
 	for (;;) {
 		Token t = f->cursor[0];
@@ -1209,17 +1198,6 @@ AstNode *parse_unary_expr(AstFile *f, b32 lhs) {
 		operand = parse_unary_expr(f, false);
 		return make_unary_expr(f, op, operand);
 	} break;
-
-	case Token_cast: {
-		AstNode *type, *operand;
-		Token token = f->cursor[0];
-		next_token(f);
-		expect_token(f, Token_OpenParen);
-		type = parse_type(f);
-		expect_token(f, Token_CloseParen);
-		operand = parse_unary_expr(f, false);
-		return make_cast_expr(f, token, type, operand);
-	} break;
 	}
 
 	return parse_atom_expr(f, lhs);
@@ -1234,15 +1212,25 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
 			i32 op_prec = token_precedence(op);
 			if (op_prec != prec)
 				break;
-			expect_operator(f); // NOTE(bill): error checks too
+			if (op.kind != Token_as) {
+				expect_operator(f); // NOTE(bill): error checks too
+			}
 			if (lhs) {
 				// TODO(bill): error checking
 				lhs = false;
 			}
-			right = parse_binary_expr(f, false, prec+1);
-			if (!right)
-				ast_file_err(f, op, "Expected expression on the right hand side of the binary operator");
+
+			if (op.kind == Token_as) {
+				next_token(f);
+				right = parse_type(f);
+			} else {
+				right = parse_binary_expr(f, false, prec+1);
+				if (!right) {
+					ast_file_err(f, op, "Expected expression on the right hand side of the binary operator");
+				}
+			}
 			expression = make_binary_expr(f, op, expression, right);
+
 		}
 	}
 	return expression;
@@ -1731,12 +1719,8 @@ AstNode *parse_if_stmt(AstFile *f) {
 		}
 	}
 
-
 	f->expr_level = prev_level;
 
-
-
-
 	if (cond == NULL) {
 		ast_file_err(f, f->cursor[0], "Expected condition for if statement");
 	}
@@ -1846,56 +1830,51 @@ AstNode *parse_defer_stmt(AstFile *f) {
 	return make_defer_stmt(f, token, statement);
 }
 
-AstNode *parse_type_decl(AstFile *f) {
-	Token   token = expect_token(f, Token_type);
-	AstNode *name = parse_identifier(f);
-	expect_token(f, Token_Colon);
-	AstNode *type = parse_type(f);
-
-	AstNode *type_decl = make_type_decl(f, token, name, type);
+AstNode *parse_stmt(AstFile *f) {
+	AstNode *s = NULL;
+	Token token = f->cursor[0];
+	switch (token.kind) {
+	case Token_type: {
+		Token   token = expect_token(f, Token_type);
+		AstNode *name = parse_identifier(f);
+		expect_token(f, Token_Colon);
+		AstNode *type = parse_type(f);
 
-	if (type->kind != AstNode_StructType &&
-	    type->kind != AstNode_ProcType)
-		expect_token(f, Token_Semicolon);
+		AstNode *type_decl = make_type_decl(f, token, name, type);
 
-	return type_decl;
-}
+		if (type->kind != AstNode_StructType &&
+		    type->kind != AstNode_ProcType) {
+			expect_token(f, Token_Semicolon);
+		}
 
-AstNode *parse_alias_decl(AstFile *f) {
-	Token   token = expect_token(f, Token_alias);
-	AstNode *name = parse_identifier(f);
-	expect_token(f, Token_Colon);
-	AstNode *type = parse_type(f);
+		return type_decl;
+	} break;
 
-	AstNode *alias_decl = make_alias_decl(f, token, name, type);
+	case Token_alias: {
+		Token   token = expect_token(f, Token_alias);
+		AstNode *name = parse_identifier(f);
+		expect_token(f, Token_Colon);
+		AstNode *type = parse_type(f);
 
-	if (type->kind != AstNode_StructType &&
-	    type->kind != AstNode_ProcType)
-		expect_token(f, Token_Semicolon);
+		AstNode *alias_decl = make_alias_decl(f, token, name, type);
 
-	return alias_decl;
-}
+		if (type->kind != AstNode_StructType &&
+		    type->kind != AstNode_ProcType) {
+			expect_token(f, Token_Semicolon);
+		}
 
-AstNode *parse_import_decl(AstFile *f) {
-	Token token = expect_token(f, Token_import);
-	Token filepath = expect_token(f, Token_String);
-	if (f->curr_scope == f->file_scope) {
-		return make_import_decl(f, token, filepath);
-	}
-	ast_file_err(f, token, "You cannot `import` within a procedure. This must be done at the file scope.");
-	return make_bad_decl(f, token, filepath);
-}
+		return alias_decl;
+	} break;
 
-AstNode *parse_stmt(AstFile *f) {
-	AstNode *s = NULL;
-	Token token = f->cursor[0];
-	switch (token.kind) {
-	case Token_type:
-		return parse_type_decl(f);
-	case Token_alias:
-		return parse_alias_decl(f);
-	case Token_import:
-		return parse_import_decl(f);
+	case Token_import: {
+		Token token = expect_token(f, Token_import);
+		Token filepath = expect_token(f, Token_String);
+		if (f->curr_scope == f->file_scope) {
+			return make_import_decl(f, token, filepath);
+		}
+		ast_file_err(f, token, "You cannot `import` within a procedure. This must be done at the file scope.");
+		return make_bad_decl(f, token, filepath);
+	} break;
 
 	// Operands
 	case Token_Identifier:
@@ -1910,10 +1889,8 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_Xor:
 	case Token_Not:
 		s = parse_simple_stmt(f);
-		if (s->kind != AstNode_ProcDecl &&
-			!allow_token(f, Token_Semicolon) &&
-			f->cursor[0].kind == Token_CloseBrace) {
-			// TODO(bill): Cleanup semicolon handling in parser
+		if (s->kind != AstNode_ProcDecl && !allow_token(f, Token_Semicolon)) {
+			// CLEANUP(bill): Semicolon handling in parser
 			ast_file_err(f, f->cursor[0],
 			             "Expected `;` after statement, got `%.*s`",
 			             LIT(token_strings[f->cursor[0].kind]));
@@ -1946,8 +1923,6 @@ AstNode *parse_stmt(AstFile *f) {
 		s = make_empty_stmt(f, token);
 		next_token(f);
 		return s;
-
-
 	}
 
 	ast_file_err(f, token,

+ 0 - 6
src/printer.cpp

@@ -70,12 +70,6 @@ void print_ast(AstNode *node, isize indent) {
 		print_ast(node->IndexExpr.expr, indent+1);
 		print_ast(node->IndexExpr.index, indent+1);
 		break;
-	case AstNode_CastExpr:
-		print_indent(indent);
-		gb_printf("(cast)\n");
-		print_ast(node->CastExpr.type, indent+1);
-		print_ast(node->CastExpr.expr, indent+1);
-		break;
 	case AstNode_DerefExpr:
 		print_indent(indent);
 		gb_printf("(deref)\n");

+ 16 - 10
src/tokenizer.cpp

@@ -54,6 +54,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
 	TOKEN_KIND(Token_AndNot, "&~"), \
 	TOKEN_KIND(Token_Shl, "<<"), \
 	TOKEN_KIND(Token_Shr, ">>"), \
+	TOKEN_KIND(Token_as, "as"), \
 TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
 	TOKEN_KIND(Token_AddEq, "+="), \
 	TOKEN_KIND(Token_SubEq, "-="), \
@@ -71,6 +72,7 @@ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
 	TOKEN_KIND(Token_Decrement, "--"), \
 	TOKEN_KIND(Token_ArrowRight, "->"), \
 	TOKEN_KIND(Token_ArrowLeft, "<-"), \
+\
 	TOKEN_KIND(Token_CmpAnd, "&&"), \
 	TOKEN_KIND(Token_CmpOr, "||"), \
 	TOKEN_KIND(Token_CmpAndEq, "&&="), \
@@ -113,7 +115,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_defer, "defer"), \
 	TOKEN_KIND(Token_return, "return"), \
 	TOKEN_KIND(Token_import, "import"), \
-	TOKEN_KIND(Token_cast, "cast"), \
 	TOKEN_KIND(Token_struct, "struct"), \
 	TOKEN_KIND(Token_union, "union"), \
 	TOKEN_KIND(Token_enum, "enum"), \
@@ -199,9 +200,10 @@ gb_no_inline void warning(Token token, char *fmt, ...) {
 
 i32 token_precedence(Token t) {
 	switch (t.kind) {
-	case Token_CmpOr:  return 1;
-	case Token_CmpAnd: return 2;
-
+	case Token_CmpOr:
+		return 1;
+	case Token_CmpAnd:
+		return 2;
 	case Token_CmpEq:
 	case Token_NotEq:
 	case Token_Lt:
@@ -209,13 +211,11 @@ i32 token_precedence(Token t) {
 	case Token_LtEq:
 	case Token_GtEq:
 		return 3;
-
 	case Token_Add:
 	case Token_Sub:
 	case Token_Or:
 	case Token_Xor:
 		return 4;
-
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Mod:
@@ -224,6 +224,8 @@ i32 token_precedence(Token t) {
 	case Token_Shl:
 	case Token_Shr:
 		return 5;
+	case Token_as:
+		return 6;
 	}
 
 	return 0;
@@ -641,10 +643,14 @@ Token tokenizer_get_token(Tokenizer *t) {
 
 		// NOTE(bill): ALL identifiers are > 1
 		if (token.string.len > 1) {
-			for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
-				if (are_strings_equal(token.string, token_strings[k])) {
-					token.kind = cast(TokenKind)k;
-					break;
+			if (are_strings_equal(token.string, token_strings[Token_as])) {
+				token.kind = Token_as;
+			} else {
+				for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
+					if (are_strings_equal(token.string, token_strings[k])) {
+						token.kind = cast(TokenKind)k;
+						break;
+					}
 				}
 			}
 		}