diff --git a/examples/basic.odin b/examples/basic.odin index ea22ca663..9141aed87 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -1,5 +1,3 @@ -putchar :: proc(c: i32) -> i32 #foreign - print_string :: proc(s: string) { for i := 0; i < len(s); i++ { putchar(s[i] as i32); @@ -22,8 +20,8 @@ encode_rune :: proc(r : rune) -> ([4]byte, int) { return buf, 1; } if i <= 1<<11-1 { - buf[0] = (0xc0 | r>>6) as byte; - buf[1] = (0x80 | r) as byte & mask; + buf[0] = 0xc0 | (r>>6) as byte; + buf[1] = 0x80 | (r) as byte & mask; return buf, 2; } @@ -34,16 +32,16 @@ encode_rune :: proc(r : rune) -> ([4]byte, int) { } if i <= 1<<16-1 { - buf[0] = (0xe0 | r>>12) as byte ; - buf[1] = (0x80 | r>>6) as byte & mask; - buf[2] = (0x80 | r) as byte & 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 | 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; + 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; } diff --git a/examples/main.ll b/examples/main.ll index 463373712..29dcd852f 100644 --- a/examples/main.ll +++ b/examples/main.ll @@ -6,62 +6,149 @@ declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) define void @main() { "entry - 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) + %0 = alloca %.rawptr, align 8 ; data + store %.rawptr zeroinitializer, %.rawptr* %0 + %1 = call %.rawptr @malloc(i64 100) + store %.rawptr %1, %.rawptr* %0 + %2 = alloca {i8*, i64, i64}, align 8 ; slice + store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %2 + %3 = alloca i8*, align 8 + store i8* zeroinitializer, i8** %3 + %4 = load %.rawptr, %.rawptr* %0 + %5 = bitcast %.rawptr %4 to i8* + store i8* %5, i8** %3 + %6 = sub i64 0, 0 + %7 = sub i64 100, 0 + %8 = load i8*, i8** %3 + %9 = getelementptr i8, i8* %8, i64 0 + %10 = alloca {i8*, i64, i64}, align 8 + store {i8*, i64, i64} zeroinitializer, {i8*, i64, i64}* %10 + %11 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %10, i64 0, i32 0 + store i8* %9, i8** %11 + %12 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %10, i64 0, i32 1 + store i64 %6, i64* %12 + %13 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %10, i64 0, i32 2 + store i64 %7, i64* %13 + %14 = load {i8*, i64, i64}, {i8*, i64, i64}* %10 + store {i8*, i64, i64} %14, {i8*, i64, i64}* %2 + %15 = alloca i64, align 8 ; i + store i64 zeroinitializer, i64* %15 + store i64 0, i64* %15 + br label %"for.loop - 2" + +"for.body - 1": + %16 = alloca i1, align 1 ; ok + store i1 zeroinitializer, i1* %16 + %17 = alloca i8, align 1 + store i8 zeroinitializer, i8* %17 + %18 = load i64, i64* %15 + %19 = load i64, i64* %15 + %20 = mul i64 %19, %18 + %21 = trunc i64 %20 to i8 + store i8 %21, i8* %17 + %22 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 0 + %23 = load i8*, i8** %22 + %24 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 1 + %25 = load i64, i64* %24 + %26 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 2 + %27 = load i64, i64* %26 + %28 = icmp slt i64 %25, %27 + br i1 %28, label %"builtin.append.able - 4", label %"builtin.append.done - 5" + +"for.loop - 2": + %29 = load i64, i64* %15 + %30 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 2 + %31 = load i64, i64* %30 + %32 = icmp slt i64 %29, %31 + br i1 %32, label %"for.body - 1", label %"for.done - 6" + +"for.post - 3": + %33 = load i64, i64* %15 + %34 = add i64 %33, 1 + store i64 %34, i64* %15 + br label %"for.loop - 2" + +"builtin.append.able - 4": + %35 = getelementptr i8, i8* %23, i64 %25 + call void @llvm.memmove.p0i8.p0i8.i64(i8* %35, i8* %17, i64 1, i32 1, i1 false) + %36 = add i64 %25, 1 + %37 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 1 + store i64 %36, i64* %37 + br label %"builtin.append.done - 5" + +"builtin.append.done - 5": + store i1 %28, i1* %16 + br label %"for.post - 3" + +"for.done - 6": + %38 = alloca i64, align 8 ; i + store i64 zeroinitializer, i64* %38 + store i64 0, i64* %38 + br label %"for.loop - 8" + +"for.body - 7": + %39 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 0 + %40 = load i8*, i8** %39 + %41 = load i64, i64* %38 + %42 = getelementptr i8, i8* %40, i64 %41 + %43 = load i8, i8* %42 + %44 = zext i8 %43 to i64 + call void @print_int(i64 %44) + %45 = getelementptr inbounds [2 x i8], [2 x i8]* @.str0, i64 0, i64 0 + %46 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %46 + %47 = getelementptr inbounds %.string, %.string* %46, i64 0, i32 0 + %48 = getelementptr inbounds %.string, %.string* %46, i64 0, i32 1 + store i8* %45, i8** %47 + store i64 2, i64* %48 + %49 = load %.string, %.string* %46 + call void @print_string(%.string %49) + %50 = load i64, i64* %38 + %51 = add i64 %50, 1 + %52 = srem i64 %51, 8 + %53 = icmp eq i64 %52, 0 + br i1 %53, label %"if.then - 10", label %"if.done - 11" + +"for.loop - 8": + %54 = load i64, i64* %38 + %55 = getelementptr inbounds {i8*, i64, i64}, {i8*, i64, i64}* %2, i64 0, i32 1 + %56 = load i64, i64* %55 + %57 = icmp slt i64 %54, %56 + br i1 %57, label %"for.body - 7", label %"for.done - 12" + +"for.post - 9": + %58 = load i64, i64* %38 + %59 = add i64 %58, 1 + store i64 %59, i64* %38 + br label %"for.loop - 8" + +"if.then - 10": + %60 = getelementptr inbounds [1 x i8], [1 x i8]* @.str1, i64 0, i64 0 + %61 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %61 + %62 = getelementptr inbounds %.string, %.string* %61, i64 0, i32 0 + %63 = getelementptr inbounds %.string, %.string* %61, i64 0, i32 1 + store i8* %60, i8** %62 + store i64 1, i64* %63 + %64 = load %.string, %.string* %61 + call void @print_string(%.string %64) + br label %"if.done - 11" + +"if.done - 11": + br label %"for.post - 9" + +"for.done - 12": + %65 = load %.rawptr, %.rawptr* %0 + call void @free(%.rawptr %65) ret void } declare i32 @putchar(i32 %c) ; foreign procedure +declare %.rawptr @malloc(i64 %sz) ; foreign procedure + +declare void @free(%.rawptr %ptr) ; foreign procedure + define void @print_string(%.string %s) { "entry - 0": %0 = alloca %.string, align 8 ; s @@ -201,15 +288,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 = or i32 192, %20 - %22 = trunc i32 %21 to i8 + %21 = trunc i32 %20 to i8 + %22 = or i8 192, %21 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 = or i32 128, %25 - %27 = trunc i32 %26 to i8 - %28 = and i8 %27, 63 + %26 = trunc i32 %25 to i8 + %27 = and i8 %26, 63 + %28 = or i8 128, %27 store i8 %28, i8* %24 %29 = alloca {[4 x i8], i64}, align 8 store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %29 @@ -250,23 +337,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 = or i32 224, %45 - %47 = trunc i32 %46 to i8 + %46 = trunc i32 %45 to i8 + %47 = or i8 224, %46 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 = or i32 128, %51 - %53 = trunc i32 %52 to i8 - %54 = and i8 %53, 63 + %52 = trunc i32 %51 to i8 + %53 = and i8 %52, 63 + %54 = or i8 128, %53 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 = or i32 128, %57 - %59 = trunc i32 %58 to i8 - %60 = and i8 %59, 63 + %58 = trunc i32 %57 to i8 + %59 = and i8 %58, 63 + %60 = or i8 128, %59 store i8 %60, i8* %56 %61 = alloca {[4 x i8], i64}, align 8 store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %61 @@ -283,31 +370,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 = or i32 240, %69 - %71 = trunc i32 %70 to i8 + %70 = trunc i32 %69 to i8 + %71 = or i8 240, %70 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 = or i32 128, %75 - %77 = trunc i32 %76 to i8 - %78 = and i8 %77, 63 + %76 = trunc i32 %75 to i8 + %77 = and i8 %76, 63 + %78 = or i8 128, %77 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 = or i32 128, %82 - %84 = trunc i32 %83 to i8 - %85 = and i8 %84, 63 + %83 = trunc i32 %82 to i8 + %84 = and i8 %83, 63 + %85 = or i8 128, %84 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 = or i32 128, %88 - %90 = trunc i32 %89 to i8 - %91 = and i8 %90, 63 + %89 = trunc i32 %88 to i8 + %90 = and i8 %89, 63 + %91 = or i8 128, %90 store i8 %91, i8* %87 %92 = alloca {[4 x i8], i64}, align 8 store {[4 x i8], i64} zeroinitializer, {[4 x i8], i64}* %92 @@ -430,7 +517,7 @@ define void @print_int_base(i64 %i, i64 %base) { %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]* @.str0, i64 0, i64 0 + %19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str2, i64 0, i64 0 %20 = load i64, i64* %1 %21 = load i64, i64* %0 %22 = srem i64 %21, %20 @@ -572,7 +659,7 @@ define void @print_uint_base(i64 %i, i64 %base) { %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]* @.str3, i64 0, i64 0 %20 = load i64, i64* %1 %21 = load i64, i64* %0 %22 = urem i64 %21, %20 @@ -688,5 +775,7 @@ define void @print_f64(double %f) { ret void } -@.str0 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" -@.str1 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" +@.str0 = global [2 x i8] c"\2C\20" +@.str1 = global [1 x i8] c"\0A" +@.str2 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" +@.str3 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" diff --git a/examples/main.odin b/examples/main.odin index 851724773..c406fa9a9 100644 --- a/examples/main.odin +++ b/examples/main.odin @@ -1,36 +1,25 @@ +import "c_runtime" import "basic" TWO_HEARTS :: '💕'; main :: proc() { - 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"); + DATA_SIZE :: 100; + data := malloc(DATA_SIZE); - // for i := 0; false && i < len(x); i++ { - // v := x[i]; - // print_int(v); - // print_string("\n"); - // } + slice := (data as ^u8)[:0:DATA_SIZE]; + for i := 0; i < cap(slice); i++ { + ok := append(^slice, (i*i) as u8); + } - // 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'); + for i := 0; i < len(slice); i++ { + print_int(slice[i] as int); + print_string(", "); + if (i+1) % 8 == 0 { + print_string("\n"); + } + } + free(data); } /* diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index a4931ed94..ced7402af 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -857,45 +857,6 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) { 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_; @@ -906,10 +867,82 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (be->op.kind == Token_as) { check_expr(c, x, be->left); - Type *cast_type = check_type(c, be->right); + Type *type = check_type(c, be->right); if (x->mode == Addressing_Invalid) return; - check_cast_expr(c, x, cast_type); + + b32 is_const_expr = x->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, x->value, t, &x->value)) { + can_convert = true; + } + } + } else if (check_castable_to(c, x, type)) { + x->mode = Addressing_Value; + can_convert = true; + } + + if (!can_convert) { + gbString expr_str = expr_to_string(x->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(x->expr), "Cannot cast `%s` to `%s`", expr_str, type_str); + + x->mode = Addressing_Invalid; + return; + } + + if (is_type_untyped(x->type)) { + Type *final_type = type; + if (is_const_expr && !is_type_constant_type(type)) { + final_type = default_type(x->type); + } + update_expr_type(c, x->expr, final_type, true); + } + + x->type = type; + return; + } else if (be->op.kind == Token_transmute) { + check_expr(c, x, be->left); + Type *type = check_type(c, be->right); + if (x->mode == Addressing_Invalid) + return; + + if (x->mode == Addressing_Constant) { + gbString expr_str = expr_to_string(x->expr); + defer (gb_string_free(expr_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute constant expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + if (is_type_untyped(x->type)) { + gbString expr_str = expr_to_string(x->expr); + defer (gb_string_free(expr_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute untyped expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + i64 otz = type_size_of(c->sizes, c->allocator, x->type); + i64 ttz = type_size_of(c->sizes, c->allocator, type); + if (otz != ttz) { + gbString expr_str = expr_to_string(x->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(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, otz, ttz); + x->mode = Addressing_Invalid; + return; + } + + x->type = type; + return; } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 12a96e1a5..4504cd06f 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -438,6 +438,11 @@ b32 are_types_identical(Type *x, Type *y) { return (x->vector.count == y->vector.count) && are_types_identical(x->vector.elem, y->vector.elem); break; + case Type_Slice: + if (y->kind == Type_Slice) + return are_types_identical(x->slice.elem, y->slice.elem); + break; + case Type_Structure: if (y->kind == Type_Structure) { if (x->structure.field_count == y->structure.field_count) { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 42e7046cf..1b70b2678 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -401,6 +401,7 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr); ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv); ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr); ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *a_type); +ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *a_type); void ssa_build_proc(ssaValue *value, ssaProcedure *parent); @@ -1077,7 +1078,7 @@ ssaValue *ssa_emit_slice(ssaProcedure *proc, Type *slice_type, ssaValue *base, s switch (base_type->kind) { case Type_Array: elem = ssa_array_elem(proc, base); break; case Type_Slice: elem = ssa_slice_elem(proc, base); break; - case Type_Pointer: elem = base; break; + case Type_Pointer: elem = ssa_emit_load(proc, base); break; } elem = ssa_emit_ptr_offset(proc, elem, low); @@ -1176,8 +1177,6 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, 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; @@ -1291,6 +1290,31 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { } +ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { + Type *src_type = ssa_value_type(value); + 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; + + 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) { + return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + } + + + GB_PANIC("Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); + + return NULL; +} + + @@ -1392,6 +1416,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case Token_as: return ssa_emit_conv(proc, ssa_build_expr(proc, be->left), tv->type); + case Token_transmute: + return ssa_emit_transmute(proc, ssa_build_expr(proc, be->left), tv->type); + default: GB_PANIC("Invalid binary expression"); break; @@ -1583,8 +1610,44 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return len; } break; case BuiltinProc_append: { - // copy :: proc(s: ^[]Type, value: Type) -> bool - GB_PANIC("TODO(bill): BuiltinProc_append"); + // append :: proc(s: ^[]Type, item: Type) -> bool + AstNode *sptr_node = ce->arg_list; + AstNode *item_node = ce->arg_list->next; + ssaValue *slice = ssa_build_addr(proc, sptr_node).address; + ssaValue *item = ssa_build_addr(proc, item_node).address; + Type *item_type = type_deref(ssa_value_type(item)); + + ssaValue *elem = ssa_slice_elem(proc, slice); + ssaValue *len = ssa_slice_len(proc, slice); + ssaValue *cap = ssa_slice_cap(proc, slice); + + // NOTE(bill): Check if can append is possible + Token lt = {Token_Lt}; + ssaValue *cond = ssa_emit_comp(proc, lt, len, cap); + ssaBlock *able = ssa_add_block(proc, NULL, make_string("builtin.append.able")); + ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.append.done")); + + ssa_emit_if(proc, cond, able, done); + proc->curr_block = able; + + // Add new slice item + ssaValue *offset = ssa_emit_ptr_offset(proc, elem, len); + i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, item_type); + ssaValue *byte_count = ssa_make_value_constant(proc->module->allocator, t_int, + make_exact_value_integer(item_size)); + ssa_emit(proc, ssa_make_instr_copy_memory(proc, offset, item, byte_count, 1, false)); + + // Increment slice length + Token add = {Token_Add}; + ssaValue *new_len = ssa_emit_arith(proc, add, len, v_one, t_int); + ssaValue *gep = ssa_emit_struct_gep(proc, slice, v_one32, t_int); + ssa_emit_store(proc, gep, new_len); + + ssa_emit_jump(proc, done); + gb_array_append(proc->blocks, done); + proc->curr_block = done; + + return ssa_emit_conv(proc, cond, t_bool); } break; case BuiltinProc_print: { // print :: proc(...) @@ -1735,12 +1798,21 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(be, BinaryExpr, expr); switch (be->op.kind) { case Token_as: { + // HACK(bill): Do have to make new variable to do this? // 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); } + case Token_transmute: { + // HACK(bill): Do have to make new variable to do this? + // 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_transmute(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; @@ -1971,33 +2043,48 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { if (proc->children == NULL) { gb_array_init(proc->children, gb_heap_allocator()); } - // NOTE(bill): Generate a new name - // parent$name - String pd_name = pd->name->Ident.token.string; - isize name_len = proc->name.len + 1 + pd_name.len + 1; - u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s", LIT(proc->name), LIT(pd_name)); - String name = make_string(name_text, name_len-1); + if (pd->body != NULL) { + // NOTE(bill): Generate a new name + // parent$name-guid + String pd_name = pd->name->Ident.token.string; + isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + i32 guid = cast(i32)gb_array_count(proc->children); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s-%d", LIT(proc->name), LIT(pd_name), guid); + String name = make_string(name_text, name_len-1); - Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); - GB_ASSERT(found != NULL); - Entity *e = *found; - ssaValue *value = ssa_make_value_procedure(proc->module->allocator, - proc->module, e->type, pd->type, pd->body, name); + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; + ssaValue *value = ssa_make_value_procedure(proc->module->allocator, + proc->module, e->type, pd->type, pd->body, name); - ssa_module_add_value(proc->module, e, value); - gb_array_append(proc->children, &value->proc); - ssa_build_proc(value, proc); + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->children, &value->proc); + ssa_build_proc(value, proc); + } else { + String name = pd->name->Ident.token.string; + + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; + ssaValue *value = ssa_make_value_procedure(proc->module->allocator, + proc->module, e->type, pd->type, pd->body, name); + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->children, &value->proc); + ssa_build_proc(value, proc); + } case_end; case_ast_node(td, TypeDecl, node); // NOTE(bill): Generate a new name - // parent_proc.name + // parent_proc.name-guid String td_name = td->name->Ident.token.string; - isize name_len = proc->name.len + 1 + td_name.len + 1; + isize name_len = proc->name.len + 1 + td_name.len + 1 + 10 + 1; u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s", LIT(proc->name), LIT(td_name)); + i32 guid = cast(i32)gb_array_count(proc->module->nested_type_names); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(td_name), guid); String name = make_string(name_text, name_len-1); Entity **found = map_get(&proc->module->info->definitions, hash_pointer(td->name)); diff --git a/src/main.cpp b/src/main.cpp index 85c5912fc..f8416a8c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,6 +39,8 @@ int main(int argc, char **argv) { ssa_gen_code(&ssa); success = 0; + } else { + gb_printf("Failed to build: %s\n", init_filename); } } } diff --git a/src/parser.cpp b/src/parser.cpp index 40a970fc6..9e9992fa5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1212,16 +1212,13 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { i32 op_prec = token_precedence(op); if (op_prec != prec) break; - if (op.kind != Token_as) { - expect_operator(f); // NOTE(bill): error checks too - } + expect_operator(f); // NOTE(bill): error checks too if (lhs) { // TODO(bill): error checking lhs = false; } - if (op.kind == Token_as) { - next_token(f); + if (op.kind == Token_as || op.kind == Token_transmute) { right = parse_type(f); } else { right = parse_binary_expr(f, false, prec+1); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d025d0879..848dd7ab6 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -54,7 +54,10 @@ 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_transmute, "transmute"), \ +\ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token_AddEq, "+="), \ TOKEN_KIND(Token_SubEq, "-="), \ @@ -101,23 +104,23 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ - TOKEN_KIND(Token_type, "type"), \ - TOKEN_KIND(Token_alias, "alias"), \ - TOKEN_KIND(Token_proc, "proc"), \ - TOKEN_KIND(Token_match, "match"), \ - TOKEN_KIND(Token_break, "break"), \ - TOKEN_KIND(Token_continue, "continue"), \ + TOKEN_KIND(Token_type, "type"), \ + TOKEN_KIND(Token_alias, "alias"), \ + TOKEN_KIND(Token_proc, "proc"), \ + TOKEN_KIND(Token_match, "match"), \ + TOKEN_KIND(Token_break, "break"), \ + TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_fallthrough, "fallthrough"), \ - TOKEN_KIND(Token_case, "case"), \ - TOKEN_KIND(Token_if, "if"), \ - TOKEN_KIND(Token_else, "else"), \ - TOKEN_KIND(Token_for, "for"), \ - TOKEN_KIND(Token_defer, "defer"), \ - TOKEN_KIND(Token_return, "return"), \ - TOKEN_KIND(Token_import, "import"), \ - TOKEN_KIND(Token_struct, "struct"), \ - TOKEN_KIND(Token_union, "union"), \ - TOKEN_KIND(Token_enum, "enum"), \ + TOKEN_KIND(Token_case, "case"), \ + TOKEN_KIND(Token_if, "if"), \ + TOKEN_KIND(Token_else, "else"), \ + TOKEN_KIND(Token_for, "for"), \ + TOKEN_KIND(Token_defer, "defer"), \ + TOKEN_KIND(Token_return, "return"), \ + TOKEN_KIND(Token_import, "import"), \ + TOKEN_KIND(Token_struct, "struct"), \ + TOKEN_KIND(Token_union, "union"), \ + TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token_Count, "") @@ -225,6 +228,7 @@ i32 token_precedence(Token t) { case Token_Shr: return 5; case Token_as: + case Token_transmute: return 6; } @@ -645,6 +649,8 @@ Token tokenizer_get_token(Tokenizer *t) { if (token.string.len > 1) { if (are_strings_equal(token.string, token_strings[Token_as])) { token.kind = Token_as; + } else if (are_strings_equal(token.string, token_strings[Token_transmute])) { + token.kind = Token_transmute; } else { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { if (are_strings_equal(token.string, token_strings[k])) { @@ -730,6 +736,7 @@ Token tokenizer_get_token(Tokenizer *t) { if (valid && len != 1) tokenizer_err(t, "Illegal rune literal"); token.string.len = t->curr - token.string.text; + i32 success = unquote_string(gb_heap_allocator(), &token.string); if (success > 0) { if (success == 2) {