mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-04 01:34:39 +00:00
Begin work on const llvm aggregate literals
This commit is contained in:
@@ -4,16 +4,14 @@
|
||||
#import "mem.odin"
|
||||
|
||||
|
||||
A :: struct { using e: [12]int }
|
||||
Vector2 :: raw_union {
|
||||
using _xy: struct #ordered { x, y: f32 }
|
||||
using v: {2}f32
|
||||
e: [2]f32
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
v: Vector2
|
||||
v.x = 123
|
||||
v[1] = 321
|
||||
Vec3 :: struct {
|
||||
x, y: i16
|
||||
z: int
|
||||
}
|
||||
|
||||
z := 123
|
||||
v := Vec3{x = 4, y = 5, z = z}
|
||||
fmt.println(v)
|
||||
}
|
||||
|
||||
@@ -619,9 +619,11 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode
|
||||
return;
|
||||
|
||||
if (mode == Addressing_Constant) {
|
||||
GB_ASSERT(value.kind != ExactValue_Invalid);
|
||||
if (!(type != t_invalid || is_type_constant_type(type))) {
|
||||
compiler_error("add_type_and_value - invalid type: %s", type_to_string(type));
|
||||
if (is_type_constant_type(type)) {
|
||||
GB_ASSERT(value.kind != ExactValue_Invalid);
|
||||
if (!(type != t_invalid || is_type_constant_type(type))) {
|
||||
compiler_error("add_type_and_value - invalid type: %s", type_to_string(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ struct Entity {
|
||||
b8 anonymous; // Variable is an anonymous
|
||||
b8 is_using; // `using` variable
|
||||
|
||||
i32 field_index; // Order in source
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
b8 is_field; // Is struct field
|
||||
} Variable;
|
||||
struct {
|
||||
@@ -124,9 +125,10 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, b32 is_anonymous, i32 field_index) {
|
||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, b32 is_anonymous, i32 field_src_index) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
||||
entity->Variable.field_index = field_index;
|
||||
entity->Variable.field_src_index = field_src_index;
|
||||
entity->Variable.field_index = field_src_index;
|
||||
entity->Variable.is_field = true;
|
||||
entity->Variable.anonymous = cast(b8)is_anonymous;
|
||||
entity->Variable.is_using = cast(b8)is_anonymous;
|
||||
|
||||
@@ -501,13 +501,16 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke
|
||||
}
|
||||
|
||||
// NOTE(bill): Hacky thing
|
||||
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
||||
__checker_sizes = c->sizes;
|
||||
__checker_allocator = c->allocator;
|
||||
// TODO(bill): Figure out rules more
|
||||
// sorting rules
|
||||
// compound literal order must match source not layout
|
||||
// NOTE(bill): compound literal order must match source not layout
|
||||
gb_sort_array(reordered_fields, field_count, cmp_struct_entity_size);
|
||||
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
reordered_fields[i]->Variable.field_index = i;
|
||||
}
|
||||
|
||||
struct_type->Record.fields = reordered_fields;
|
||||
}
|
||||
|
||||
@@ -3256,6 +3259,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
case_ast_node(cl, CompoundLit, node);
|
||||
Type *type = type_hint;
|
||||
b32 ellipsis_array = false;
|
||||
b32 is_constant = true;
|
||||
if (cl->type != NULL) {
|
||||
type = NULL;
|
||||
|
||||
@@ -3297,15 +3301,15 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
"Mixture of `field = value` and value elements in a structure literal is not allowed");
|
||||
continue;
|
||||
}
|
||||
ast_node(kv, FieldValue, elem);
|
||||
if (kv->field->kind != AstNode_Ident) {
|
||||
gbString expr_str = expr_to_string(kv->field);
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (fv->field->kind != AstNode_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(ast_node_token(elem),
|
||||
"Invalid field name `%s` in structure literal", expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = kv->field->Ident.string;
|
||||
String name = fv->field->Ident.string;
|
||||
|
||||
Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
@@ -3321,7 +3325,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
|
||||
Entity *field = t->Record.fields[sel.index[0]];
|
||||
add_entity_use(c, kv->field, field);
|
||||
add_entity_use(c, fv->field, field);
|
||||
|
||||
if (fields_visited[sel.index[0]]) {
|
||||
error(ast_node_token(elem),
|
||||
@@ -3330,7 +3334,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
|
||||
fields_visited[sel.index[0]] = true;
|
||||
check_expr(c, o, kv->value);
|
||||
check_expr(c, o, fv->value);
|
||||
|
||||
if (is_constant) {
|
||||
is_constant = o->mode == Addressing_Constant;
|
||||
}
|
||||
|
||||
check_assignment(c, o, field->type, make_string("structure literal"));
|
||||
}
|
||||
} else {
|
||||
@@ -3348,6 +3357,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
error(ast_node_token(o->expr), "Too many values in structure literal, expected %td", field_count);
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_constant) {
|
||||
is_constant = o->mode == Addressing_Constant;
|
||||
}
|
||||
|
||||
check_assignment(c, o, field->type, make_string("structure literal"));
|
||||
}
|
||||
if (gb_array_count(cl->elems) < field_count) {
|
||||
@@ -3358,7 +3372,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
} break;
|
||||
|
||||
case Type_Slice:
|
||||
// case Type_Slice:
|
||||
case Type_Array:
|
||||
case Type_Vector:
|
||||
{
|
||||
@@ -3401,6 +3415,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, e, elem_type);
|
||||
check_assignment(c, &o, elem_type, context_name);
|
||||
|
||||
if (is_constant) {
|
||||
is_constant = o.mode == Addressing_Constant;
|
||||
}
|
||||
}
|
||||
if (max < index)
|
||||
max = index;
|
||||
@@ -3419,13 +3437,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
default: {
|
||||
gbString str = type_to_string(type);
|
||||
error(ast_node_token(node), "Invalid compound literal type `%s`", str);
|
||||
error(ast_node_token(node), "Invalid or unyet supported compound literal type `%s`", str);
|
||||
gb_string_free(str);
|
||||
goto error;
|
||||
} break;
|
||||
}
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
if (is_constant) {
|
||||
o->mode = Addressing_Constant;
|
||||
o->value = make_exact_value_compound(node);
|
||||
} else {
|
||||
o->mode = Addressing_Value;
|
||||
}
|
||||
o->type = type;
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -151,13 +151,12 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
|
||||
if (decl->init_expr != NULL) {
|
||||
TypeAndValue *tav = map_get(&info->types, hash_pointer(decl->init_expr));
|
||||
if (tav != NULL && tav->value.kind != ExactValue_Invalid) {
|
||||
ExactValue v = tav->value;
|
||||
if (v.kind == ExactValue_String) {
|
||||
// NOTE(bill): The printer will fix the value correctly
|
||||
// g->Global.value = ssa_add_global_string_array(m, v.value_string);
|
||||
} else {
|
||||
g->Global.value = ssa_make_value_constant(a, tav->type, v);
|
||||
if (tav != NULL) {
|
||||
if (tav->value.kind != ExactValue_Invalid) {
|
||||
ExactValue v = tav->value;
|
||||
if (v.kind != ExactValue_String) {
|
||||
g->Global.value = ssa_add_module_constant(m, tav->type, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,10 +443,10 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
|
||||
type_set_offsets(m->sizes, a, t); // NOTE(bill): Just incase the offsets have not been set yet
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
// NOTE(bill): Order fields in source order not layout order
|
||||
Entity *f = t->Record.fields[i];
|
||||
// TODO(bill): Order fields in source order not layout order
|
||||
Entity *f = t->Record.fields_in_src_order[i];
|
||||
ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type);
|
||||
i64 foffset = t->Record.struct_offsets[i];
|
||||
i64 foffset = t->Record.struct_offsets[f->Variable.field_index];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
isize source_index = f->Variable.field_index;
|
||||
|
||||
|
||||
@@ -263,6 +263,8 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
|
||||
}
|
||||
}
|
||||
|
||||
void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint);
|
||||
|
||||
void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type) {
|
||||
type = base_type(type);
|
||||
if (is_type_float(type)) {
|
||||
@@ -320,6 +322,122 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
|
||||
ssa_fprintf(f, ")");
|
||||
}
|
||||
break;
|
||||
|
||||
case ExactValue_Compound: {
|
||||
// ssa_fprintf(f, "%s", (value.value_bool ? "true" : "false"));
|
||||
type = base_type(type);
|
||||
if (is_type_array(type)) {
|
||||
ssa_fprintf(f, "[");
|
||||
Type *elem_type = type->Array.elem;
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
for (isize i = 0; i < type->Array.count; i++) {
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
}
|
||||
ssa_print_type(f, m, elem_type);
|
||||
ssa_fprintf(f, " ");
|
||||
|
||||
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems[i]);
|
||||
GB_ASSERT(tav != NULL);
|
||||
ssa_print_exact_value(f, m, tav->value, elem_type);
|
||||
}
|
||||
|
||||
ssa_fprintf(f, "]");
|
||||
} else if (is_type_struct(type)) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
if (cl->elems == NULL || gb_array_count(cl->elems) == 0) {
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
isize value_count = type->Record.field_count;
|
||||
ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count);
|
||||
|
||||
|
||||
if (cl->elems[0]->kind == AstNode_FieldValue) {
|
||||
isize elem_count = gb_array_count(cl->elems);
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
ast_node(fv, FieldValue, cl->elems[i]);
|
||||
String name = fv->field->Ident.string;
|
||||
|
||||
TypeAndValue *tav = type_and_value_of_expression(m->info, fv->value);
|
||||
GB_ASSERT(tav != NULL);
|
||||
|
||||
Selection sel = lookup_field(m->allocator, type, name, false);
|
||||
Entity *f = type->Record.fields[sel.index[0]];
|
||||
|
||||
values[f->Variable.field_index] = tav->value;
|
||||
}
|
||||
} else {
|
||||
for (isize i = 0; i < value_count; i++) {
|
||||
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems[i]);
|
||||
GB_ASSERT(tav != NULL);
|
||||
|
||||
Entity *f = type->Record.fields_in_src_order[i];
|
||||
|
||||
values[f->Variable.field_index] = tav->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (type->Record.struct_is_packed) {
|
||||
ssa_fprintf(f, "<");
|
||||
}
|
||||
ssa_fprintf(f, "{");
|
||||
|
||||
|
||||
for (isize i = 0; i < value_count; i++) {
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
}
|
||||
Type *elem_type = type->Record.fields[i]->type;
|
||||
|
||||
ssa_print_type(f, m, elem_type);
|
||||
ssa_fprintf(f, " ");
|
||||
|
||||
ExactValue v = values[i];
|
||||
if (v.kind == ExactValue_Invalid) {
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
} else if (v.kind == ExactValue_String) {
|
||||
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
|
||||
// of the .ll file
|
||||
ssaValue *str_array = ssa_add_global_string_array(m, v.value_string);
|
||||
|
||||
ssa_fprintf(f, "{i8* getelementptr inbounds (");
|
||||
ssa_print_type(f, m, str_array->Global.entity->type);
|
||||
ssa_fprintf(f, ", ");
|
||||
ssa_print_type(f, m, str_array->Global.entity->type);
|
||||
ssa_fprintf(f, "* ");
|
||||
ssa_print_encoded_global(f, str_array->Global.entity->token.string, false);
|
||||
ssa_fprintf(f, ", ");
|
||||
ssa_print_type(f, m, t_int);
|
||||
ssa_fprintf(f, " 0, i32 0), ");
|
||||
ssa_print_type(f, m, t_int);
|
||||
ssa_fprintf(f, " %lld}", cast(i64)v.value_string.len);
|
||||
|
||||
} else {
|
||||
ssa_print_exact_value(f, m, v, elem_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ssa_fprintf(f, "}");
|
||||
if (type->Record.struct_is_packed) {
|
||||
ssa_fprintf(f, ">");
|
||||
}
|
||||
} else {
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
GB_PANIC("Invalid ExactValue: %d", value.kind);
|
||||
break;
|
||||
|
||||
@@ -64,6 +64,7 @@ struct ssaModule {
|
||||
i32 global_string_index;
|
||||
|
||||
gbArray(ssaValue *) procs; // NOTE(bill): Procedures to generate
|
||||
gbArray(ssaValue *) const_compound_lits;
|
||||
};
|
||||
|
||||
|
||||
@@ -290,6 +291,7 @@ enum ssaValueKind {
|
||||
ssaValue_Invalid,
|
||||
|
||||
ssaValue_Constant,
|
||||
ssaValue_ConstantArray,
|
||||
ssaValue_TypeName,
|
||||
ssaValue_Global,
|
||||
ssaValue_Param,
|
||||
@@ -310,9 +312,13 @@ struct ssaValue {
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
} Constant;
|
||||
struct {
|
||||
Type *type;
|
||||
gbArray(ssaValue *) values;
|
||||
} ConstantArray;
|
||||
struct {
|
||||
String name;
|
||||
Type * type;
|
||||
Type * type;
|
||||
} TypeName;
|
||||
struct {
|
||||
b32 is_constant;
|
||||
@@ -409,6 +415,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
|
||||
map_init(&m->debug_info, gb_heap_allocator());
|
||||
map_init(&m->type_names, gb_heap_allocator());
|
||||
gb_array_init(m->procs, gb_heap_allocator());
|
||||
gb_array_init(m->const_compound_lits, gb_heap_allocator());
|
||||
|
||||
// Default states
|
||||
m->stmt_state_flags = 0;
|
||||
@@ -473,6 +480,7 @@ void ssa_destroy_module(ssaModule *m) {
|
||||
map_destroy(&m->type_names);
|
||||
map_destroy(&m->debug_info);
|
||||
gb_array_free(m->procs);
|
||||
gb_array_free(m->const_compound_lits);
|
||||
gb_arena_free(&m->arena);
|
||||
}
|
||||
|
||||
@@ -808,6 +816,16 @@ ssaValue *ssa_make_const_bool(gbAllocator a, b32 b) {
|
||||
return ssa_make_value_constant(a, t_bool, make_exact_value_bool(b != 0));
|
||||
}
|
||||
|
||||
ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) {
|
||||
ssaValue *v = ssa_make_value_constant(m->allocator, type, value);
|
||||
|
||||
if (!is_type_constant_type(type)) {
|
||||
gb_array_append(m->const_compound_lits, v);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
ssaValue *ssa_make_value_procedure(gbAllocator a, ssaModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) {
|
||||
ssaValue *v = ssa_alloc_value(a, ssaValue_Proc);
|
||||
@@ -1201,7 +1219,7 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue
|
||||
case Token_AndNot: {
|
||||
// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
|
||||
// NOTE(bill): "not" `x` == `x` "xor" `-1`
|
||||
ssaValue *neg = ssa_make_value_constant(proc->module->allocator, type, make_exact_value_integer(-1));
|
||||
ssaValue *neg = ssa_add_module_constant(proc->module, type, make_exact_value_integer(-1));
|
||||
op.kind = Token_Xor;
|
||||
right = ssa_emit_arith(proc, op, right, neg, type);
|
||||
GB_ASSERT(right->Instr.kind == ssaInstr_BinaryOp);
|
||||
@@ -1270,7 +1288,7 @@ ssaValue *ssa_emit_struct_gep(ssaProcedure *proc, ssaValue *s, ssaValue *index,
|
||||
}
|
||||
|
||||
ssaValue *ssa_emit_struct_gep(ssaProcedure *proc, ssaValue *s, i32 index, Type *result_type) {
|
||||
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_i32, make_exact_value_integer(index));
|
||||
ssaValue *i = ssa_make_const_i32(proc->module->allocator, index);
|
||||
return ssa_emit_struct_gep(proc, s, i, result_type);
|
||||
}
|
||||
|
||||
@@ -1540,7 +1558,7 @@ ssaValue *ssa_add_global_string_array(ssaModule *m, String string) {
|
||||
Type *type = make_type_array(a, t_u8, string.len);
|
||||
ExactValue ev = make_exact_value_string(string);
|
||||
Entity *entity = make_entity_constant(a, NULL, token, type, ev);
|
||||
ssaValue *g = ssa_make_value_global(a, entity, ssa_make_value_constant(a, type, ev));
|
||||
ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev));
|
||||
g->Global.is_private = true;
|
||||
// g->Global.is_constant = true;
|
||||
|
||||
@@ -1628,10 +1646,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
ev = exact_value_to_integer(ev);
|
||||
} else if (is_type_pointer(dst)) {
|
||||
// IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect `null`
|
||||
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_uint, ev);
|
||||
ssaValue *i = ssa_add_module_constant(proc->module, t_uint, ev);
|
||||
return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_inttoptr, i, t_uint, dst));
|
||||
}
|
||||
return ssa_make_value_constant(proc->module->allocator, t, ev);
|
||||
return ssa_add_module_constant(proc->module, t, ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2007,7 +2025,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
// NOTE(bill): "not" `x` == `x` "xor" `-1`
|
||||
ExactValue neg_one = make_exact_value_integer(-1);
|
||||
ssaValue *left = ssa_build_expr(proc, ue->expr);
|
||||
ssaValue *right = ssa_make_value_constant(proc->module->allocator, tv->type, neg_one);
|
||||
ssaValue *right = ssa_add_module_constant(proc->module, tv->type, neg_one);
|
||||
return ssa_emit_arith(proc, ue->op, left, right, tv->type);
|
||||
} break;
|
||||
}
|
||||
@@ -2105,9 +2123,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
|
||||
|
||||
case Type_Vector: {
|
||||
isize index = 0;
|
||||
|
||||
ssaValue *result = ssa_emit_load(proc, v);
|
||||
for (; index < gb_array_count(cl->elems); index++) {
|
||||
for (isize index = 0; index < gb_array_count(cl->elems); index++) {
|
||||
AstNode *elem = cl->elems[index];
|
||||
ssaValue *field_elem = ssa_build_expr(proc, elem);
|
||||
Type *t = ssa_type(field_elem);
|
||||
@@ -2116,7 +2134,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
ssaValue *i = ssa_make_const_int(proc->module->allocator, index);
|
||||
result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
|
||||
}
|
||||
if (index == 1 && bt->Vector.count > 1) {
|
||||
|
||||
if (gb_array_count(cl->elems) == 1 && bt->Vector.count > 1) {
|
||||
isize index_count = bt->Vector.count;
|
||||
i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
|
||||
for (isize i = 0; i < index_count; i++) {
|
||||
@@ -2677,7 +2696,7 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
return ssa_make_value_constant(proc->module->allocator, tv->type, tv->value);
|
||||
return ssa_add_module_constant(proc->module, tv->type, tv->value);
|
||||
}
|
||||
|
||||
ssaValue *value = NULL;
|
||||
|
||||
@@ -26,6 +26,7 @@ String get_module_dir(gbAllocator a) {
|
||||
path.len--;
|
||||
}
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -211,7 +212,7 @@ gb_inline void map_destroy(Map<T> *h) {
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
|
||||
MapEntry<T> e = {0};
|
||||
MapEntry<T> e = {};
|
||||
e.key = key;
|
||||
e.next = -1;
|
||||
gb_array_append(h->entries, e);
|
||||
@@ -267,7 +268,7 @@ gb_inline void map_grow(Map<T> *h) {
|
||||
template <typename T>
|
||||
void map_rehash(Map<T> *h, isize new_count) {
|
||||
isize i, j;
|
||||
Map<T> nh = {0};
|
||||
Map<T> nh = {};
|
||||
map_init(&nh, gb_array_allocator(h->hashes));
|
||||
gb_array_resize(nh.hashes, new_count);
|
||||
gb_array_reserve(nh.entries, gb_array_count(h->entries));
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// TODO(bill): Big numbers
|
||||
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
|
||||
|
||||
struct AstNode;
|
||||
|
||||
enum ExactValueKind {
|
||||
ExactValue_Invalid,
|
||||
|
||||
@@ -11,6 +13,7 @@ enum ExactValueKind {
|
||||
ExactValue_Integer,
|
||||
ExactValue_Float,
|
||||
ExactValue_Pointer, // TODO(bill): Handle ExactValue_Pointer correctly
|
||||
ExactValue_Compound,
|
||||
|
||||
ExactValue_Count,
|
||||
};
|
||||
@@ -18,11 +21,12 @@ enum ExactValueKind {
|
||||
struct ExactValue {
|
||||
ExactValueKind kind;
|
||||
union {
|
||||
b32 value_bool;
|
||||
String value_string;
|
||||
i64 value_integer;
|
||||
f64 value_float;
|
||||
void * value_pointer;
|
||||
b32 value_bool;
|
||||
String value_string;
|
||||
i64 value_integer;
|
||||
f64 value_float;
|
||||
void * value_pointer;
|
||||
AstNode *value_compound;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,6 +34,13 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||
}
|
||||
|
||||
|
||||
ExactValue make_exact_value_compound(AstNode *node) {
|
||||
ExactValue result = {ExactValue_Compound};
|
||||
result.value_compound = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue make_exact_value_bool(b32 b) {
|
||||
ExactValue result = {ExactValue_Bool};
|
||||
result.value_bool = (b != 0);
|
||||
|
||||
13
src/main.cpp
13
src/main.cpp
@@ -1,4 +1,4 @@
|
||||
// #define DISPLAY_TIMING
|
||||
#define DISPLAY_TIMING
|
||||
|
||||
#include "common.cpp"
|
||||
#include "unicode.cpp"
|
||||
@@ -106,13 +106,17 @@ ArchData make_arch_data(ArchKind kind) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
gb_printf_err("using: %s [run] <filename> \n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 1
|
||||
init_string_buffer_memory();
|
||||
init_global_error_collector();
|
||||
|
||||
String module_dir = get_module_dir(gb_heap_allocator());
|
||||
// defer (gb_free(gb_heap_allocator(), module_dir.text));
|
||||
@@ -163,11 +167,11 @@ int main(int argc, char **argv) {
|
||||
ssa_gen_tree(&ssa);
|
||||
|
||||
PRINT_TIMER("SSA Tree");
|
||||
|
||||
// TODO(bill): Speedup writing to file for IR code
|
||||
ssa_gen_ir(&ssa);
|
||||
|
||||
PRINT_TIMER("SSA IR");
|
||||
#if 1
|
||||
|
||||
char const *output_name = ssa.output_file.filename;
|
||||
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
|
||||
@@ -230,12 +234,13 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
PRINT_TIMER("msvc-link");
|
||||
#endif
|
||||
PRINT_ACCUMULATION();
|
||||
|
||||
if (run_output) {
|
||||
win32_exec_command_line_app("%.*s.exe", cast(int)base_name_len, output_name);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -54,12 +54,12 @@ struct ImportedFile {
|
||||
|
||||
struct Parser {
|
||||
String init_fullpath;
|
||||
gbArray(AstFile) files;
|
||||
gbArray(AstFile) files;
|
||||
gbArray(ImportedFile) imports;
|
||||
gbArray(String) libraries;
|
||||
gbArray(String) system_libraries;
|
||||
isize load_index;
|
||||
gbAtomic32 import_index;
|
||||
gbArray(String) system_libraries;
|
||||
isize total_token_count;
|
||||
gbMutex mutex;
|
||||
};
|
||||
|
||||
enum ProcTag : u64 {
|
||||
@@ -1586,6 +1586,44 @@ AstNode *parse_unary_expr(AstFile *f, b32 lhs) {
|
||||
return parse_atom_expr(f, lhs);
|
||||
}
|
||||
|
||||
// NOTE(bill): result == priority
|
||||
i32 token_precedence(Token t) {
|
||||
switch (t.kind) {
|
||||
case Token_CmpOr:
|
||||
return 1;
|
||||
case Token_CmpAnd:
|
||||
return 2;
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
case Token_Lt:
|
||||
case Token_Gt:
|
||||
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:
|
||||
case Token_And:
|
||||
case Token_AndNot:
|
||||
case Token_Shl:
|
||||
case Token_Shr:
|
||||
return 5;
|
||||
case Token_DoublePrime:
|
||||
return 6;
|
||||
case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
return 7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
|
||||
AstNode *expression = parse_unary_expr(f, lhs);
|
||||
for (i32 prec = token_precedence(f->curr_token); prec >= prec_in; prec--) {
|
||||
@@ -2826,8 +2864,8 @@ void destroy_ast_file(AstFile *f) {
|
||||
b32 init_parser(Parser *p) {
|
||||
gb_array_init(p->files, gb_heap_allocator());
|
||||
gb_array_init(p->imports, gb_heap_allocator());
|
||||
gb_array_init(p->libraries, gb_heap_allocator());
|
||||
gb_array_init(p->system_libraries, gb_heap_allocator());
|
||||
gb_mutex_init(&p->mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2843,12 +2881,15 @@ void destroy_parser(Parser *p) {
|
||||
#endif
|
||||
gb_array_free(p->files);
|
||||
gb_array_free(p->imports);
|
||||
gb_array_free(p->libraries);
|
||||
gb_array_free(p->system_libraries);
|
||||
gb_mutex_destroy(&p->mutex);
|
||||
}
|
||||
|
||||
// NOTE(bill): Returns true if it's added
|
||||
b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
||||
gb_mutex_lock(&p->mutex);
|
||||
defer (gb_mutex_unlock(&p->mutex));
|
||||
|
||||
gb_for_array(i, p->imports) {
|
||||
String import = p->imports[i].path;
|
||||
if (import == path) {
|
||||
@@ -2900,6 +2941,9 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
|
||||
// NOTE(bill): Returns true if it's added
|
||||
b32 try_add_foreign_system_library_path(Parser *p, String import_file) {
|
||||
gb_mutex_lock(&p->mutex);
|
||||
defer (gb_mutex_unlock(&p->mutex));
|
||||
|
||||
gb_for_array(i, p->system_libraries) {
|
||||
String import = p->system_libraries[i];
|
||||
if (import == import_file) {
|
||||
@@ -2981,7 +3025,6 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
base_dir.len--;
|
||||
}
|
||||
|
||||
gbAllocator allocator = gb_heap_allocator(); // TODO(bill): Change this allocator
|
||||
|
||||
f->decls = parse_stmt_list(f);
|
||||
|
||||
@@ -3008,6 +3051,8 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gbAllocator allocator = gb_heap_allocator(); // TODO(bill): Change this allocator
|
||||
|
||||
String rel_path = get_fullpath_relative(allocator, base_dir, file_str);
|
||||
String import_file = rel_path;
|
||||
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
|
||||
@@ -3038,6 +3083,7 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
|
||||
String init_fullpath = make_string(fullpath_str);
|
||||
@@ -3053,9 +3099,10 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
}
|
||||
|
||||
gb_for_array(i, p->imports) {
|
||||
String import_path = p->imports[i].path;
|
||||
String import_rel_path = p->imports[i].rel_path;
|
||||
TokenPos pos = p->imports[i].pos;
|
||||
ImportedFile imported_file = p->imports[i];
|
||||
String import_path = imported_file.path;
|
||||
String import_rel_path = imported_file.rel_path;
|
||||
TokenPos pos = imported_file.pos;
|
||||
AstFile file = {};
|
||||
ParseFileError err = init_ast_file(&file, import_path);
|
||||
|
||||
@@ -3088,9 +3135,18 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
return err;
|
||||
}
|
||||
parse_file(p, &file);
|
||||
file.id = gb_array_count(p->files);
|
||||
gb_array_append(p->files, file);
|
||||
p->total_token_count += gb_array_count(file.tokens);
|
||||
|
||||
{
|
||||
gb_mutex_lock(&p->mutex);
|
||||
defer (gb_mutex_unlock(&p->mutex));
|
||||
|
||||
file.id = gb_array_count(p->files);
|
||||
gb_array_append(p->files, file);
|
||||
}
|
||||
}
|
||||
|
||||
gb_for_array(i, p->files) {
|
||||
p->total_token_count += gb_array_count(p->files[i].tokens);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,12 +166,20 @@ struct ErrorCollector {
|
||||
TokenPos prev;
|
||||
i64 count;
|
||||
i64 warning_count;
|
||||
gbMutex mutex;
|
||||
};
|
||||
|
||||
gb_global ErrorCollector global_error_collector;
|
||||
|
||||
void init_global_error_collector(void) {
|
||||
gb_mutex_init(&global_error_collector.mutex);
|
||||
}
|
||||
|
||||
|
||||
void warning(Token token, char *fmt, ...) {
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
||||
|
||||
global_error_collector.warning_count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
||||
@@ -188,6 +196,9 @@ void warning(Token token, char *fmt, ...) {
|
||||
}
|
||||
|
||||
void error(Token token, char *fmt, ...) {
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
||||
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
||||
@@ -204,6 +215,9 @@ void error(Token token, char *fmt, ...) {
|
||||
}
|
||||
|
||||
void syntax_error(Token token, char *fmt, ...) {
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
defer (gb_mutex_unlock(&global_error_collector.mutex));
|
||||
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
|
||||
@@ -232,43 +246,6 @@ void compiler_error(char *fmt, ...) {
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): result == priority
|
||||
i32 token_precedence(Token t) {
|
||||
switch (t.kind) {
|
||||
case Token_CmpOr:
|
||||
return 1;
|
||||
case Token_CmpAnd:
|
||||
return 2;
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
case Token_Lt:
|
||||
case Token_Gt:
|
||||
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:
|
||||
case Token_And:
|
||||
case Token_AndNot:
|
||||
case Token_Shl:
|
||||
case Token_Shr:
|
||||
return 5;
|
||||
case Token_DoublePrime:
|
||||
return 6;
|
||||
case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
return 7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gb_inline b32 token_is_literal(Token t) {
|
||||
|
||||
Reference in New Issue
Block a user