diff --git a/examples/basic.odin b/examples/basic.odin index e0863188a..ea22ca663 100644 --- a/examples/basic.odin +++ b/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'); + } + +} + diff --git a/examples/main.ll b/examples/main.ll index 9985d0d68..463373712 100644 --- a/examples/main.ll +++ b/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,7 @@ 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 @@ -548,8 +468,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 +483,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 +513,180 @@ define void @print_int_base(i64 %i, i64 %base) { ret void } -@.str0 = global [2 x i8] c"\2C\20" +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 + %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_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 +} + +@.str0 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" @.str1 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" diff --git a/examples/main.odin b/examples/main.odin index 35807a47c..851724773 100644 --- a/examples/main.odin +++ b/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'); + 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"); - type Vec2: {2}f32; + // for i := 0; false && i < len(x); i++ { + // v := x[i]; + // print_int(v); + // print_string("\n"); + // } - 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; - }); + // 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" */ - diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 77854a603..a4931ed94 100644 --- a/src/checker/expr.cpp +++ b/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; diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 368e276af..12a96e1a5 100644 --- a/src/checker/type.cpp +++ b/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; diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index c530b350b..4cb4a98be 100644 --- a/src/codegen/codegen.cpp +++ b/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); } diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index d05cd0272..1535638b0 100644 --- a/src/codegen/print_llvm.cpp +++ b/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(" %d\n", instr->kind); ssa_fprintf(f, "; %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")); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index c229156b7..42e7046cf 100644 --- a/src/codegen/ssa.cpp +++ b/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); } } diff --git a/src/parser.cpp b/src/parser.cpp index 62d6ea35e..40a970fc6 100644 --- a/src/parser.cpp +++ b/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); - - if (type->kind != AstNode_StructType && - type->kind != AstNode_ProcType) - expect_token(f, Token_Semicolon); - - return type_decl; -} - -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); - - AstNode *alias_decl = make_alias_decl(f, token, name, type); - - if (type->kind != AstNode_StructType && - type->kind != AstNode_ProcType) - expect_token(f, Token_Semicolon); - - return alias_decl; -} - -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); -} - 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_type: { + 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); + + if (type->kind != AstNode_StructType && + type->kind != AstNode_ProcType) { + expect_token(f, Token_Semicolon); + } + + return type_decl; + } break; + + 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); + + AstNode *alias_decl = make_alias_decl(f, token, name, type); + + if (type->kind != AstNode_StructType && + type->kind != AstNode_ProcType) { + expect_token(f, Token_Semicolon); + } + + return alias_decl; + } break; + + 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, diff --git a/src/printer.cpp b/src/printer.cpp index 8dd61e0ca..465714783 100644 --- a/src/printer.cpp +++ b/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"); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 6f319959c..d025d0879 100644 --- a/src/tokenizer.cpp +++ b/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; + } } } }