mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-12 22:31:25 -07:00
expr as type; {N}bool is still causing problems
This commit is contained in:
+137
-107
@@ -384,11 +384,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
Type *elem = check_type(c, vt->elem);
|
||||
Type *be = get_base_type(elem);
|
||||
i64 count = check_array_count(c, vt->count);
|
||||
if (!is_type_vector(be) &&
|
||||
!(is_type_boolean(be) || is_type_numeric(be))) {
|
||||
if (!is_type_boolean(be) && !is_type_numeric(be)) {
|
||||
err_str = type_to_string(elem);
|
||||
error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be a boolean, numerical, or vector. Got `%s`", err_str);
|
||||
} else {
|
||||
error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be numerical or a boolean. Got `%s`", err_str);
|
||||
}
|
||||
type = make_type_vector(c->allocator, elem, count);
|
||||
set_base_type(named_type, type);
|
||||
@@ -433,7 +431,7 @@ end:
|
||||
|
||||
b32 check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = get_base_type(base_vector_type(o->type));
|
||||
Type *type = get_base_type(base_vector_type(get_base_type(o->type)));
|
||||
gbString str = NULL;
|
||||
defer (gb_string_free(str));
|
||||
switch (op.kind) {
|
||||
@@ -702,13 +700,11 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
update_expr_type(c, y->expr, default_type(y->type), true);
|
||||
}
|
||||
|
||||
if (is_type_vector(x->type)) {
|
||||
Type *vec_bool = NULL;
|
||||
do {
|
||||
} while (is_type_vector(x->type->vector.elem));
|
||||
if (is_type_vector(get_base_type(y->type))) {
|
||||
x->type = make_type_vector(c->allocator, t_bool, get_base_type(y->type)->vector.count);
|
||||
} else {
|
||||
x->type = t_untyped_bool;
|
||||
}
|
||||
x->type = t_untyped_bool;
|
||||
|
||||
}
|
||||
|
||||
void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
@@ -805,6 +801,101 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
if (check_is_assignable_to(c, operand, y))
|
||||
return true;
|
||||
|
||||
Type *x = operand->type;
|
||||
Type *xb = get_base_type(x);
|
||||
Type *yb = get_base_type(y);
|
||||
if (are_types_identical(xb, yb))
|
||||
return true;
|
||||
|
||||
|
||||
// Cast between booleans and integers
|
||||
if (is_type_boolean(x) || is_type_integer(x)) {
|
||||
if (is_type_boolean(y) || is_type_integer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between numbers
|
||||
if (is_type_integer(x) || is_type_float(x)) {
|
||||
if (is_type_integer(y) || is_type_float(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between pointers
|
||||
if (is_type_pointer(x)) {
|
||||
if (is_type_pointer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// untyped integers -> pointers
|
||||
if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// (u)int <-> pointer
|
||||
if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb) || is_type_int_or_uint(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// []byte/[]u8 <-> string
|
||||
if (is_type_u8_slice(xb) && is_type_string(yb)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_u8_slice(yb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_cast_expr(Checker *c, Operand *operand, Type *type) {
|
||||
b32 is_const_expr = operand->mode == Addressing_Constant;
|
||||
b32 can_convert = false;
|
||||
|
||||
if (is_const_expr && is_type_constant_type(type)) {
|
||||
Type *t = get_base_type(type);
|
||||
if (t->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
} else if (check_castable_to(c, operand, type)) {
|
||||
operand->mode = Addressing_Value;
|
||||
can_convert = true;
|
||||
}
|
||||
|
||||
if (!can_convert) {
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_untyped(operand->type)) {
|
||||
Type *final_type = type;
|
||||
if (is_const_expr && !is_type_constant_type(type)) {
|
||||
final_type = default_type(operand->type);
|
||||
}
|
||||
update_expr_type(c, operand->expr, final_type, true);
|
||||
}
|
||||
|
||||
operand->type = type;
|
||||
}
|
||||
|
||||
|
||||
void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_BinaryExpr);
|
||||
Operand y_ = {}, *y = &y_;
|
||||
@@ -813,6 +904,15 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
|
||||
ast_node(be, BinaryExpr, node);
|
||||
|
||||
if (be->op.kind == Token_as) {
|
||||
check_expr(c, x, be->left);
|
||||
Type *cast_type = check_type(c, be->right);
|
||||
if (x->mode == Addressing_Invalid)
|
||||
return;
|
||||
check_cast_expr(c, x, cast_type);
|
||||
return;
|
||||
}
|
||||
|
||||
check_expr(c, x, be->left);
|
||||
check_expr(c, y, be->right);
|
||||
if (x->mode == Addressing_Invalid) {
|
||||
@@ -890,7 +990,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
}
|
||||
|
||||
if (x->mode == Addressing_Constant &&
|
||||
y->mode == Addressing_Constant) {
|
||||
y->mode == Addressing_Constant) {
|
||||
ExactValue a = x->value;
|
||||
ExactValue b = y->value;
|
||||
|
||||
@@ -943,7 +1043,18 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
|
||||
found->type = get_base_type(type);
|
||||
map_set(&c->info.untyped, key, *found);
|
||||
} else {
|
||||
ExpressionInfo old = *found;
|
||||
map_remove(&c->info.untyped, key);
|
||||
|
||||
if (old.is_lhs && !is_type_integer(type)) {
|
||||
gbString expr_str = expr_to_string(e);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(e), "Shifted operand %s must be an integer, got %s", expr_str, type_str);
|
||||
return;
|
||||
}
|
||||
|
||||
add_type_and_value(&c->info, e, found->mode, type, found->value);
|
||||
}
|
||||
}
|
||||
@@ -1349,6 +1460,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
value = make_exact_value_integer(t->array.count);
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
mode = Addressing_Constant;
|
||||
value = make_exact_value_integer(t->vector.count);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
mode = Addressing_Value;
|
||||
break;
|
||||
@@ -1600,85 +1716,6 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
return Expression_Statement;
|
||||
}
|
||||
|
||||
b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
if (check_is_assignable_to(c, operand, y))
|
||||
return true;
|
||||
|
||||
Type *x = operand->type;
|
||||
Type *xb = get_base_type(x);
|
||||
Type *yb = get_base_type(y);
|
||||
if (are_types_identical(xb, yb))
|
||||
return true;
|
||||
|
||||
// Cast between numbers
|
||||
if (is_type_integer(x) || is_type_float(x)) {
|
||||
if (is_type_integer(y) || is_type_float(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between pointers
|
||||
if (is_type_pointer(x)) {
|
||||
if (is_type_pointer(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// untyped integers -> pointers
|
||||
if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// (u)int <-> pointer
|
||||
if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb) || is_type_int_or_uint(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// []byte/[]u8 <-> string
|
||||
if (is_type_u8_slice(xb) && is_type_string(yb)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_u8_slice(yb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_cast_expr(Checker *c, Operand *operand, Type *type) {
|
||||
b32 is_const_expr = operand->mode == Addressing_Constant;
|
||||
b32 can_convert = false;
|
||||
|
||||
if (is_const_expr && is_type_constant_type(type)) {
|
||||
Type *t = get_base_type(type);
|
||||
if (t->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, operand->value, t, &operand->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
} else if (check_castable_to(c, operand, type)) {
|
||||
operand->mode = Addressing_Value;
|
||||
can_convert = true;
|
||||
}
|
||||
|
||||
if (!can_convert) {
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(expr_str));
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
operand->type = type;
|
||||
}
|
||||
|
||||
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
||||
check_expr_base(c, o, e, t);
|
||||
check_not_tuple(c, o);
|
||||
@@ -1924,6 +1961,15 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
o->type = t->array.elem;
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
valid = true;
|
||||
max_count = t->vector.count;
|
||||
if (o->mode != Addressing_Variable)
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t->vector.elem;
|
||||
break;
|
||||
|
||||
|
||||
case Type_Slice:
|
||||
valid = true;
|
||||
o->type = t->slice.elem;
|
||||
@@ -2039,15 +2085,6 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(ce, CastExpr, node);
|
||||
Type *cast_type = check_type(c, ce->type);
|
||||
check_expr_or_type(c, o, ce->expr);
|
||||
if (o->mode != Addressing_Invalid)
|
||||
check_cast_expr(c, o, cast_type);
|
||||
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(ce, CallExpr, node);
|
||||
return check_call_expr(c, o, node);
|
||||
case_end;
|
||||
@@ -2287,13 +2324,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, "]");
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CastExpr, node);
|
||||
str = gb_string_appendc(str, "cast(");
|
||||
str = write_expr_to_string(str, ce->type);
|
||||
str = gb_string_appendc(str, ")");
|
||||
str = write_expr_to_string(str, ce->expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(e, Ellipsis, node);
|
||||
str = gb_string_appendc(str, "..");
|
||||
case_end;
|
||||
|
||||
+21
-15
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -393,10 +393,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
|
||||
case ssaInstr_BinaryOp: {
|
||||
auto *bo = &value->instr.binary_op;
|
||||
Type *type = ssa_value_type(bo->left);
|
||||
Type *type = get_base_type(ssa_value_type(bo->left));
|
||||
Type *elem_type = type;
|
||||
while (elem_type->kind == Type_Vector) {
|
||||
elem_type = elem_type->vector.elem;
|
||||
elem_type = get_base_type(elem_type->vector.elem);
|
||||
}
|
||||
|
||||
ssa_fprintf(f, "%%%d = ", value->id);
|
||||
@@ -535,13 +535,37 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
vol_str = "true";
|
||||
}
|
||||
ssa_fprintf(f, ", i32 %d, i1 %s)\n", instr->copy_memory.align, vol_str);
|
||||
} break;
|
||||
|
||||
|
||||
case ssaInstr_InsertElement: {
|
||||
auto *ie = &instr->insert_element;
|
||||
Type *vt = ssa_value_type(ie->vector);
|
||||
ssa_fprintf(f, "%%%d = insertelement ", value->id);
|
||||
|
||||
ssa_print_type(f, m->sizes, vt);
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->vector, vt);
|
||||
ssa_fprintf(f, ", ");
|
||||
|
||||
ssa_print_type(f, m->sizes, ssa_value_type(ie->elem));
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->elem, ssa_value_type(ie->elem));
|
||||
ssa_fprintf(f, ", ");
|
||||
|
||||
ssa_print_type(f, m->sizes, ssa_value_type(ie->index));
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, ie->index, ssa_value_type(ie->index));
|
||||
|
||||
ssa_fprintf(f, "\n");
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
ssa_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +637,7 @@ void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
|
||||
|
||||
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
if (m->layout.len > 0) {
|
||||
ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
|
||||
ssa_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
|
||||
}
|
||||
|
||||
ssa_print_encoded_local(f, make_string(".string"));
|
||||
|
||||
+205
-95
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+58
-83
@@ -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,
|
||||
|
||||
@@ -70,12 +70,6 @@ void print_ast(AstNode *node, isize indent) {
|
||||
print_ast(node->IndexExpr.expr, indent+1);
|
||||
print_ast(node->IndexExpr.index, indent+1);
|
||||
break;
|
||||
case AstNode_CastExpr:
|
||||
print_indent(indent);
|
||||
gb_printf("(cast)\n");
|
||||
print_ast(node->CastExpr.type, indent+1);
|
||||
print_ast(node->CastExpr.expr, indent+1);
|
||||
break;
|
||||
case AstNode_DerefExpr:
|
||||
print_indent(indent);
|
||||
gb_printf("(deref)\n");
|
||||
|
||||
+16
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user