mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
ret, unreachable, param, deref
This commit is contained in:
+5
-8
@@ -1,11 +1,8 @@
|
|||||||
|
void test(void) {
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int x = 15;
|
void (*f)(void) = test;
|
||||||
int y = 4;
|
|
||||||
x = x & (~y);
|
|
||||||
if (x > 0) {
|
|
||||||
x = 123;
|
|
||||||
} else {
|
|
||||||
x = 321;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-15
@@ -1,17 +1,6 @@
|
|||||||
|
; ModuleID = '..\examples/test.bc'
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
entry:
|
"entry - 0":
|
||||||
%0 = alloca i64, align 8 ; x
|
ret void
|
||||||
store i64 zeroinitializer, i64* %0
|
|
||||||
store i64 15, i64* %0
|
|
||||||
%1 = load i64, i64* %0
|
|
||||||
%2 = icmp sgt i64 %1, 0
|
|
||||||
br i1 %2, label %if-then, label %if-else
|
|
||||||
if-then:
|
|
||||||
store i64 123, i64* %0
|
|
||||||
br label %if-end
|
|
||||||
if-else:
|
|
||||||
store i64 321, i64* %0
|
|
||||||
br label %if-end
|
|
||||||
if-end:
|
|
||||||
ret void
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,2 @@
|
|||||||
main :: proc() {
|
main :: proc() {
|
||||||
x : int = 15;
|
|
||||||
if x > 0 {
|
|
||||||
x = 123;
|
|
||||||
} else {
|
|
||||||
x = 321;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
rem del "..\examples\test.bc"
|
rem del "..\examples\test.bc"
|
||||||
call ..\bin\odin.exe ..\examples/test.odin
|
call ..\bin\odin.exe ..\examples/test.odin && lli ..\examples/test.ll
|
||||||
call lli ..\examples/test.ll
|
call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
|
||||||
rem call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc
|
call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
|
||||||
rem call llvm-dis ..\examples/test.bc -o ..\examples/test.ll
|
|
||||||
call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll
|
call clang ..\examples/test.c -O0 -S -emit-llvm -o ..\examples/test-c.ll
|
||||||
|
|||||||
+10
-2
@@ -101,6 +101,7 @@ struct Scope {
|
|||||||
Scope *prev, *next;
|
Scope *prev, *next;
|
||||||
Scope *first_child, *last_child;
|
Scope *first_child, *last_child;
|
||||||
Map<Entity *> elements; // Key: String
|
Map<Entity *> elements; // Key: String
|
||||||
|
gbArray(AstNode *) deferred_stmts;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExpressionKind {
|
enum ExpressionKind {
|
||||||
@@ -154,13 +155,14 @@ struct CheckerContext {
|
|||||||
DeclInfo *decl;
|
DeclInfo *decl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE(bill): Symbol tables
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
||||||
Map<Entity *> definitions; // Key: AstNode * | Identifier -> Entity
|
Map<Entity *> definitions; // Key: AstNode * | Identifier -> Entity
|
||||||
Map<Entity *> uses; // Key: AstNode * | Identifier -> Entity
|
Map<Entity *> uses; // Key: AstNode * | Identifier -> Entity
|
||||||
Map<Scope *> scopes; // Key: AstNode * | Node -> Scope
|
Map<Scope *> scopes; // Key: AstNode * | Node -> Scope
|
||||||
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
||||||
Map<DeclInfo *> entities; // Key: Entity *
|
Map<DeclInfo *> entities; // Key: Entity *
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Checker {
|
struct Checker {
|
||||||
@@ -190,6 +192,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) {
|
|||||||
Scope *s = gb_alloc_item(allocator, Scope);
|
Scope *s = gb_alloc_item(allocator, Scope);
|
||||||
s->parent = parent;
|
s->parent = parent;
|
||||||
map_init(&s->elements, gb_heap_allocator());
|
map_init(&s->elements, gb_heap_allocator());
|
||||||
|
gb_array_init(s->deferred_stmts, gb_heap_allocator());
|
||||||
if (parent != NULL && parent != universal_scope) {
|
if (parent != NULL && parent != universal_scope) {
|
||||||
DLIST_APPEND(parent->first_child, parent->last_child, s);
|
DLIST_APPEND(parent->first_child, parent->last_child, s);
|
||||||
}
|
}
|
||||||
@@ -504,6 +507,12 @@ void check_close_scope(Checker *c) {
|
|||||||
c->context.scope = c->context.scope->parent;
|
c->context.scope = c->context.scope->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_add_deferred_stmt(Checker *c, AstNode *stmt) {
|
||||||
|
GB_ASSERT(stmt != NULL);
|
||||||
|
GB_ASSERT(is_ast_node_stmt(stmt));
|
||||||
|
gb_array_append(c->context.scope->deferred_stmts, stmt);
|
||||||
|
}
|
||||||
|
|
||||||
void push_procedure(Checker *c, Type *procedure_type) {
|
void push_procedure(Checker *c, Type *procedure_type) {
|
||||||
gb_array_append(c->procedure_stack, procedure_type);
|
gb_array_append(c->procedure_stack, procedure_type);
|
||||||
}
|
}
|
||||||
@@ -512,7 +521,6 @@ void pop_procedure(Checker *c) {
|
|||||||
gb_array_pop(c->procedure_stack);
|
gb_array_pop(c->procedure_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void add_curr_ast_file(Checker *c, AstFile *file) {
|
void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||||
gb_zero_item(&c->error_collector);
|
gb_zero_item(&c->error_collector);
|
||||||
c->curr_ast_file = file;
|
c->curr_ast_file = file;
|
||||||
|
|||||||
@@ -724,7 +724,6 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fs, ForStmt, node);
|
case_ast_node(fs, ForStmt, node);
|
||||||
flags |= Statement_BreakAllowed | Statement_ContinueAllowed;
|
|
||||||
check_open_scope(c, node);
|
check_open_scope(c, node);
|
||||||
defer (check_close_scope(c));
|
defer (check_close_scope(c));
|
||||||
|
|
||||||
@@ -739,9 +738,9 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
"Non-boolean condition in `for` statement");
|
"Non-boolean condition in `for` statement");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fs->end != NULL)
|
if (fs->post != NULL)
|
||||||
check_stmt(c, fs->end, 0);
|
check_stmt(c, fs->post, 0);
|
||||||
check_stmt(c, fs->body, flags);
|
check_stmt(c, fs->body, flags | Statement_BreakAllowed | Statement_ContinueAllowed);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ds, DeferStmt, node);
|
case_ast_node(ds, DeferStmt, node);
|
||||||
@@ -752,6 +751,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
c->in_defer = true;
|
c->in_defer = true;
|
||||||
check_stmt(c, ds->stmt, 0);
|
check_stmt(c, ds->stmt, 0);
|
||||||
c->in_defer = out_in_defer;
|
c->in_defer = out_in_defer;
|
||||||
|
check_add_deferred_stmt(c, ds->stmt);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ void ssa_gen_code(ssaGen *s) {
|
|||||||
ssaModule *m = &s->module;
|
ssaModule *m = &s->module;
|
||||||
CheckerInfo *info = m->info;
|
CheckerInfo *info = m->info;
|
||||||
gbAllocator a = m->allocator;
|
gbAllocator a = m->allocator;
|
||||||
|
|
||||||
gb_for_array(i, info->entities.entries) {
|
gb_for_array(i, info->entities.entries) {
|
||||||
auto *entry = &info->entities.entries[i];
|
auto *entry = &info->entities.entries[i];
|
||||||
Entity *e = cast(Entity *)cast(uintptr)entry->key;
|
Entity *e = cast(Entity *)cast(uintptr)entry->key;
|
||||||
@@ -66,8 +67,8 @@ void ssa_gen_code(ssaGen *s) {
|
|||||||
gb_for_array(i, m->members.entries) {
|
gb_for_array(i, m->members.entries) {
|
||||||
auto *entry = &m->members.entries[i];
|
auto *entry = &m->members.entries[i];
|
||||||
ssaValue *v = entry->value;
|
ssaValue *v = entry->value;
|
||||||
if (v->kind == ssaValue_Procedure)
|
if (v->kind == ssaValue_Proc)
|
||||||
ssa_build_procedure(v);
|
ssa_build_proc(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_print_llvm_ir(&s->output_file, &s->module);
|
ssa_print_llvm_ir(&s->output_file, &s->module);
|
||||||
|
|||||||
+49
-15
@@ -146,7 +146,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
|
|||||||
if (i > 0) ssa_fprintf(f, ", ");
|
if (i > 0) ssa_fprintf(f, ", ");
|
||||||
ssa_print_type(f, s, &t->procedure.params[i]);
|
ssa_print_type(f, s, &t->procedure.params[i]);
|
||||||
}
|
}
|
||||||
ssa_fprintf(f, ") ");
|
ssa_fprintf(f, ")*");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +201,12 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ssa_print_block_name(gbFile *f, ssaBlock *b) {
|
||||||
|
ssa_fprintf(f, "\"");
|
||||||
|
ssa_print_escape_string(f, b->label);
|
||||||
|
ssa_fprintf(f, " - %d", b->id);
|
||||||
|
ssa_fprintf(f, "\"");
|
||||||
|
}
|
||||||
|
|
||||||
void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) {
|
void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) {
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
@@ -208,18 +214,21 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (value->kind) {
|
switch (value->kind) {
|
||||||
|
case ssaValue_Constant:
|
||||||
|
ssa_print_exact_value(f, m, value->constant.value, type_hint);
|
||||||
|
break;
|
||||||
case ssaValue_TypeName:
|
case ssaValue_TypeName:
|
||||||
ssa_print_encoded_local(f, value->type_name.entity->token.string);
|
ssa_print_encoded_local(f, value->type_name.entity->token.string);
|
||||||
break;
|
break;
|
||||||
case ssaValue_Global:
|
case ssaValue_Global:
|
||||||
ssa_print_encoded_global(f, value->global.entity->token.string);
|
ssa_print_encoded_global(f, value->global.entity->token.string);
|
||||||
break;
|
break;
|
||||||
case ssaValue_Procedure:
|
case ssaValue_Param:
|
||||||
|
ssa_print_encoded_local(f, value->param.entity->token.string);
|
||||||
|
break;
|
||||||
|
case ssaValue_Proc:
|
||||||
ssa_print_encoded_global(f, value->proc.entity->token.string);
|
ssa_print_encoded_global(f, value->proc.entity->token.string);
|
||||||
break;
|
break;
|
||||||
case ssaValue_Constant: {
|
|
||||||
ssa_print_exact_value(f, m, value->constant.value, type_hint);
|
|
||||||
} break;
|
|
||||||
case ssaValue_Instr:
|
case ssaValue_Instr:
|
||||||
ssa_fprintf(f, "%%%d", value->id);
|
ssa_fprintf(f, "%%%d", value->id);
|
||||||
break;
|
break;
|
||||||
@@ -301,14 +310,34 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
|||||||
ssa_fprintf(f, ", ", instr->br.cond->id);
|
ssa_fprintf(f, ", ", instr->br.cond->id);
|
||||||
}
|
}
|
||||||
ssa_fprintf(f, "label ");
|
ssa_fprintf(f, "label ");
|
||||||
ssa_print_encoded_local(f, instr->br.true_block->label);
|
ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.true_block);
|
||||||
if (instr->br.false_block != NULL) {
|
if (instr->br.false_block != NULL) {
|
||||||
ssa_fprintf(f, ", label ");
|
ssa_fprintf(f, ", label ");
|
||||||
ssa_print_encoded_local(f, instr->br.false_block->label);
|
ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.false_block);
|
||||||
}
|
}
|
||||||
ssa_fprintf(f, "\n");
|
ssa_fprintf(f, "\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ssaInstr_Ret: {
|
||||||
|
auto *ret = &instr->ret;
|
||||||
|
ssa_fprintf(f, "ret ");
|
||||||
|
if (ret->value == NULL) {
|
||||||
|
ssa_fprintf(f, "void");
|
||||||
|
} else {
|
||||||
|
Type *t = ssa_value_type(ret->value);
|
||||||
|
ssa_print_type(f, m->sizes, t);
|
||||||
|
ssa_fprintf(f, " ");
|
||||||
|
ssa_print_value(f, m, ret->value, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssa_fprintf(f, "\n");
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ssaInstr_Unreachable: {
|
||||||
|
ssa_fprintf(f, "unreachable\n");
|
||||||
|
} break;
|
||||||
|
|
||||||
case ssaInstr_BinaryOp: {
|
case ssaInstr_BinaryOp: {
|
||||||
auto *bo = &value->instr.binary_op;
|
auto *bo = &value->instr.binary_op;
|
||||||
Type *type = ssa_value_type(bo->left);
|
Type *type = ssa_value_type(bo->left);
|
||||||
@@ -391,6 +420,10 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||||
|
if (m->layout.len > 0) {
|
||||||
|
ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
|
||||||
|
}
|
||||||
|
|
||||||
gb_for_array(member_index, m->members.entries) {
|
gb_for_array(member_index, m->members.entries) {
|
||||||
auto *entry = &m->members.entries[member_index];
|
auto *entry = &m->members.entries[member_index];
|
||||||
ssaValue *v = entry->value;
|
ssaValue *v = entry->value;
|
||||||
@@ -412,7 +445,7 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
|||||||
ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type));
|
ssa_fprintf(f, ", align %td\n", type_align_of(m->sizes, gb_heap_allocator(), g->entity->type));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ssaValue_Procedure: {
|
case ssaValue_Proc: {
|
||||||
ssaProcedure *proc = &v->proc;
|
ssaProcedure *proc = &v->proc;
|
||||||
if (proc->body == NULL) {
|
if (proc->body == NULL) {
|
||||||
ssa_fprintf(f, "declare ");
|
ssa_fprintf(f, "declare ");
|
||||||
@@ -450,19 +483,20 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
|||||||
ssa_fprintf(f, "\n");
|
ssa_fprintf(f, "\n");
|
||||||
} else {
|
} else {
|
||||||
ssa_fprintf(f, "{\n");
|
ssa_fprintf(f, "{\n");
|
||||||
gb_for_array(i, proc->blocks.entries) {
|
gb_for_array(i, proc->blocks) {
|
||||||
ssaBlock *block = &proc->blocks.entries[i].value->block;
|
ssaBlock *block = proc->blocks[i];
|
||||||
ssa_fprintf(f, "%.*s:\n", LIT(block->label));
|
|
||||||
|
if (i > 0) ssa_fprintf(f, "\n");
|
||||||
|
ssa_print_block_name(f, block);
|
||||||
|
ssa_fprintf(f, ":\n");
|
||||||
|
|
||||||
gb_for_array(j, block->instrs) {
|
gb_for_array(j, block->instrs) {
|
||||||
ssaValue *value = block->instrs[j];
|
ssaValue *value = block->instrs[j];
|
||||||
ssa_print_instr(f, m, value);
|
ssa_print_instr(f, m, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc_type->result_count == 0) {
|
ssa_fprintf(f, "}\n\n");
|
||||||
ssa_fprintf(f, "\tret void\n");
|
|
||||||
}
|
|
||||||
ssa_fprintf(f, "}\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
+329
-154
@@ -9,6 +9,8 @@ struct ssaModule {
|
|||||||
BaseTypeSizes sizes;
|
BaseTypeSizes sizes;
|
||||||
gbAllocator allocator;
|
gbAllocator allocator;
|
||||||
|
|
||||||
|
String layout;
|
||||||
|
|
||||||
Map<ssaValue *> values; // Key: Entity *
|
Map<ssaValue *> values; // Key: Entity *
|
||||||
Map<ssaValue *> members; // Key: String
|
Map<ssaValue *> members; // Key: String
|
||||||
i32 global_string_index;
|
i32 global_string_index;
|
||||||
@@ -26,6 +28,13 @@ struct ssaBlock {
|
|||||||
gbArray(ssaValue *) values;
|
gbArray(ssaValue *) values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ssaTargetList {
|
||||||
|
ssaTargetList *prev;
|
||||||
|
ssaBlock *break_;
|
||||||
|
ssaBlock *continue_;
|
||||||
|
ssaBlock *fallthrough_;
|
||||||
|
};
|
||||||
|
|
||||||
struct ssaProcedure {
|
struct ssaProcedure {
|
||||||
ssaModule *module;
|
ssaModule *module;
|
||||||
String name;
|
String name;
|
||||||
@@ -35,8 +44,10 @@ struct ssaProcedure {
|
|||||||
AstNode *type_expr;
|
AstNode *type_expr;
|
||||||
AstNode *body;
|
AstNode *body;
|
||||||
|
|
||||||
Map<ssaValue *> blocks;
|
gbArray(ssaBlock *) blocks;
|
||||||
ssaBlock *curr_block;
|
ssaBlock *curr_block;
|
||||||
|
ssaTargetList *target_list;
|
||||||
|
|
||||||
gbArray(ssaValue *) anonymous_procedures;
|
gbArray(ssaValue *) anonymous_procedures;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,6 +61,8 @@ struct ssaProcedure {
|
|||||||
SSA_INSTR_KIND(GetElementPtr), \
|
SSA_INSTR_KIND(GetElementPtr), \
|
||||||
SSA_INSTR_KIND(Convert), \
|
SSA_INSTR_KIND(Convert), \
|
||||||
SSA_INSTR_KIND(Br), \
|
SSA_INSTR_KIND(Br), \
|
||||||
|
SSA_INSTR_KIND(Ret), \
|
||||||
|
SSA_INSTR_KIND(Unreachable), \
|
||||||
SSA_INSTR_KIND(BinaryOp), \
|
SSA_INSTR_KIND(BinaryOp), \
|
||||||
SSA_INSTR_KIND(Count),
|
SSA_INSTR_KIND(Count),
|
||||||
|
|
||||||
@@ -109,12 +122,13 @@ struct ssaInstr {
|
|||||||
isize index_count;
|
isize index_count;
|
||||||
b32 inbounds;
|
b32 inbounds;
|
||||||
} get_element_ptr;
|
} get_element_ptr;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
ssaValue *cond;
|
ssaValue *cond;
|
||||||
ssaBlock *true_block;
|
ssaBlock *true_block;
|
||||||
ssaBlock *false_block;
|
ssaBlock *false_block;
|
||||||
} br;
|
} br;
|
||||||
|
struct { ssaValue *value; } ret;
|
||||||
|
struct {} unreachable;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Type *type;
|
Type *type;
|
||||||
@@ -137,8 +151,9 @@ enum ssaValueKind {
|
|||||||
ssaValue_Constant,
|
ssaValue_Constant,
|
||||||
ssaValue_TypeName,
|
ssaValue_TypeName,
|
||||||
ssaValue_Global,
|
ssaValue_Global,
|
||||||
ssaValue_Procedure,
|
ssaValue_Param,
|
||||||
|
|
||||||
|
ssaValue_Proc,
|
||||||
ssaValue_Block,
|
ssaValue_Block,
|
||||||
ssaValue_Instr,
|
ssaValue_Instr,
|
||||||
|
|
||||||
@@ -164,9 +179,14 @@ struct ssaValue {
|
|||||||
Type * type;
|
Type * type;
|
||||||
ssaValue *value;
|
ssaValue *value;
|
||||||
} global;
|
} global;
|
||||||
ssaProcedure proc;
|
struct {
|
||||||
ssaBlock block;
|
ssaProcedure *parent;
|
||||||
ssaInstr instr;
|
Entity *entity;
|
||||||
|
Type * type;
|
||||||
|
} param;
|
||||||
|
ssaProcedure proc;
|
||||||
|
ssaBlock block;
|
||||||
|
ssaInstr instr;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -256,14 +276,16 @@ void ssa_instr_set_type(ssaInstr *instr, Type *type) {
|
|||||||
|
|
||||||
Type *ssa_value_type(ssaValue *value) {
|
Type *ssa_value_type(ssaValue *value) {
|
||||||
switch (value->kind) {
|
switch (value->kind) {
|
||||||
|
case ssaValue_Constant:
|
||||||
|
return value->constant.type;
|
||||||
case ssaValue_TypeName:
|
case ssaValue_TypeName:
|
||||||
return value->type_name.type;
|
return value->type_name.type;
|
||||||
case ssaValue_Global:
|
case ssaValue_Global:
|
||||||
return value->global.type;
|
return value->global.type;
|
||||||
case ssaValue_Procedure:
|
case ssaValue_Param:
|
||||||
|
return value->param.type;
|
||||||
|
case ssaValue_Proc:
|
||||||
return value->proc.type;
|
return value->proc.type;
|
||||||
case ssaValue_Constant:
|
|
||||||
return value->constant.type;
|
|
||||||
case ssaValue_Instr:
|
case ssaValue_Instr:
|
||||||
return ssa_instr_type(&value->instr);
|
return ssa_instr_type(&value->instr);
|
||||||
}
|
}
|
||||||
@@ -279,7 +301,7 @@ void ssa_value_set_type(ssaValue *value, Type *type) {
|
|||||||
case ssaValue_Global:
|
case ssaValue_Global:
|
||||||
value->global.type = type;
|
value->global.type = type;
|
||||||
break;
|
break;
|
||||||
case ssaValue_Procedure:
|
case ssaValue_Proc:
|
||||||
value->proc.type = type;
|
value->proc.type = type;
|
||||||
break;
|
break;
|
||||||
case ssaValue_Constant:
|
case ssaValue_Constant:
|
||||||
@@ -329,7 +351,13 @@ ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value) {
|
|||||||
v->global.value = value;
|
v->global.value = value;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
ssaValue *ssa_make_value_param(gbAllocator a, ssaProcedure *parent, Entity *e) {
|
||||||
|
ssaValue *v = ssa_alloc_value(a, ssaValue_Param);
|
||||||
|
v->param.parent = parent;
|
||||||
|
v->param.entity = e;
|
||||||
|
v->param.type = e->type;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e) {
|
ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e) {
|
||||||
@@ -408,6 +436,25 @@ ssaValue *ssa_make_instr_br(ssaProcedure *p, ssaValue *cond, ssaBlock *true_bloc
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) {
|
||||||
|
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Unreachable);
|
||||||
|
if (p->curr_block) {
|
||||||
|
gb_array_append(p->curr_block->values, v);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssaValue *ssa_make_instr_ret(ssaProcedure *p, ssaValue *value) {
|
||||||
|
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_Ret);
|
||||||
|
v->instr.ret.value = value;
|
||||||
|
if (p->curr_block) {
|
||||||
|
gb_array_append(p->curr_block->values, v);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
|
ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
|
||||||
ssaValue *v = ssa_alloc_value(a, ssaValue_Constant);
|
ssaValue *v = ssa_alloc_value(a, ssaValue_Constant);
|
||||||
v->constant.type = type;
|
v->constant.type = type;
|
||||||
@@ -416,7 +463,7 @@ ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclInfo *decl, ssaModule *m) {
|
ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclInfo *decl, ssaModule *m) {
|
||||||
ssaValue *v = ssa_alloc_value(a, ssaValue_Procedure);
|
ssaValue *v = ssa_alloc_value(a, ssaValue_Proc);
|
||||||
v->proc.module = m;
|
v->proc.module = m;
|
||||||
v->proc.entity = e;
|
v->proc.entity = e;
|
||||||
v->proc.type = e->type;
|
v->proc.type = e->type;
|
||||||
@@ -433,7 +480,7 @@ ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope,
|
|||||||
v->block.parent = proc;
|
v->block.parent = proc;
|
||||||
|
|
||||||
gb_array_init(v->block.instrs, gb_heap_allocator());
|
gb_array_init(v->block.instrs, gb_heap_allocator());
|
||||||
gb_array_init(v->block.values, gb_heap_allocator());
|
gb_array_init(v->block.values, gb_heap_allocator());
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -467,48 +514,6 @@ ssaValue *ssa_add_global_string(ssaProcedure *proc, ExactValue value) {
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssaValue *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) {
|
|
||||||
Scope *scope = NULL;
|
|
||||||
Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
|
|
||||||
if (found) scope = *found;
|
|
||||||
|
|
||||||
// IMPORTANT TODO(bill): Check for duplicate labels and replace in a sane way
|
|
||||||
// if (map_get(&proc->blocks, hash_string(label)) != NULL) {
|
|
||||||
// GB_PANIC("Block of name `%.*s` already exists", LIT(label));
|
|
||||||
// }
|
|
||||||
|
|
||||||
ssaValue *block = ssa_make_value_block(proc, node, scope, label);
|
|
||||||
map_set(&proc->blocks, hash_string(label), block);
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ssa_begin_procedure_body(ssaProcedure *proc) {
|
|
||||||
map_init(&proc->blocks, gb_heap_allocator());
|
|
||||||
ssaValue *b = ssa_add_block(proc, proc->body, make_string("entry"));
|
|
||||||
proc->curr_block = &b->block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ssa_end_procedure_body(ssaProcedure *proc) {
|
|
||||||
// Number registers
|
|
||||||
i32 reg_id = 0;
|
|
||||||
gb_for_array(i, proc->blocks.entries) {
|
|
||||||
ssaBlock *b = &proc->blocks.entries[i].value->block;
|
|
||||||
gb_for_array(j, b->instrs) {
|
|
||||||
ssaValue *value = b->instrs[j];
|
|
||||||
ssaInstr *instr = &value->instr;
|
|
||||||
switch (instr->kind) {
|
|
||||||
case ssaInstr_Store:
|
|
||||||
case ssaInstr_Br:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value->id = reg_id;
|
|
||||||
reg_id++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
b32 ssa_is_blank_ident(AstNode *node) {
|
b32 ssa_is_blank_ident(AstNode *node) {
|
||||||
if (node->kind == AstNode_Ident) {
|
if (node->kind == AstNode_Ident) {
|
||||||
@@ -519,15 +524,25 @@ b32 ssa_is_blank_ident(AstNode *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) {
|
ssaValue *ssa_block_emit(ssaBlock *b, ssaValue *instr) {
|
||||||
instr->instr.parent = b;
|
instr->instr.parent = b;
|
||||||
gb_array_append(b->instrs, instr);
|
if (b) {
|
||||||
|
gb_array_append(b->instrs, instr);
|
||||||
|
}
|
||||||
return instr;
|
return instr;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
|
ssaValue *ssa_emit(ssaProcedure *proc, ssaValue *instr) {
|
||||||
return ssa_block_emit(proc->curr_block, instr);
|
return ssa_block_emit(proc->curr_block, instr);
|
||||||
}
|
}
|
||||||
|
ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) {
|
||||||
|
return ssa_emit(p, ssa_make_instr_store(p, address, value));
|
||||||
|
}
|
||||||
|
ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) {
|
||||||
|
return ssa_emit(p, ssa_make_instr_load(p, address));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e) {
|
ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e) {
|
||||||
@@ -542,14 +557,13 @@ ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
|
||||||
ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) {
|
ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e);
|
||||||
return ssa_emit(p, ssa_make_instr_store(p, address, value));
|
ssaValue *l = ssa_add_local(proc, e);
|
||||||
|
ssa_emit_store(proc, l, v);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) {
|
|
||||||
return ssa_emit(p, ssa_make_instr_load(p, address));
|
|
||||||
}
|
|
||||||
|
|
||||||
ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
|
ssaValue *ssa_lvalue_store(ssaLvalue lval, ssaProcedure *p, ssaValue *value) {
|
||||||
switch (lval.kind) {
|
switch (lval.kind) {
|
||||||
@@ -585,6 +599,128 @@ Type *ssa_lvalue_type(ssaLvalue lval) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ssa_build_stmt(ssaProcedure *proc, AstNode *s);
|
||||||
|
|
||||||
|
void ssa_emit_defer_stmts(ssaProcedure *proc, ssaBlock *block) {
|
||||||
|
if (block == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// IMPORTANT TODO(bill): ssa defer - Place where needed!!!
|
||||||
|
|
||||||
|
Scope *curr_scope = block->scope;
|
||||||
|
if (curr_scope == NULL) {
|
||||||
|
GB_PANIC("No scope found for deferred statements");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Scope *s = curr_scope; s != NULL; s = s->parent) {
|
||||||
|
isize count = gb_array_count(s->deferred_stmts);
|
||||||
|
for (isize i = count-1; i >= 0; i--) {
|
||||||
|
ssa_build_stmt(proc, s->deferred_stmts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_emit_unreachable(ssaProcedure *proc) {
|
||||||
|
ssa_emit(proc, ssa_make_instr_unreachable(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_emit_ret(ssaProcedure *proc, ssaValue *v) {
|
||||||
|
ssa_emit_defer_stmts(proc, proc->curr_block);
|
||||||
|
ssa_emit(proc, ssa_make_instr_ret(proc, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) {
|
||||||
|
ssa_emit(proc, ssa_make_instr_br(proc, NULL, block, NULL));
|
||||||
|
proc->curr_block = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) {
|
||||||
|
ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block);
|
||||||
|
ssa_emit(proc, br);
|
||||||
|
proc->curr_block = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
|
||||||
|
Scope *scope = NULL;
|
||||||
|
Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
|
||||||
|
if (found) {
|
||||||
|
scope = *found;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Block scope not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
ssaValue *block = ssa_make_value_block(proc, node, scope, label);
|
||||||
|
return &block->block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) {
|
||||||
|
ssaBlock *block = ssa__make_block(proc, node, label);
|
||||||
|
gb_array_append(proc->blocks, block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ssa_begin_procedure_body(ssaProcedure *proc) {
|
||||||
|
gb_array_init(proc->blocks, gb_heap_allocator());
|
||||||
|
proc->curr_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
|
||||||
|
|
||||||
|
if (proc->type->procedure.params != NULL) {
|
||||||
|
auto *params = &proc->type->procedure.params->tuple;
|
||||||
|
for (isize i = 0; i < params->variable_count; i++) {
|
||||||
|
Entity *e = params->variables[i];
|
||||||
|
ssa_add_param(proc, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_end_procedure_body(ssaProcedure *proc) {
|
||||||
|
if (proc->type->procedure.result_count == 0) {
|
||||||
|
ssa_emit_ret(proc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number blocks and registers
|
||||||
|
i32 reg_id = 0;
|
||||||
|
gb_for_array(i, proc->blocks) {
|
||||||
|
ssaBlock *b = proc->blocks[i];
|
||||||
|
b->id = i;
|
||||||
|
gb_for_array(j, b->instrs) {
|
||||||
|
ssaValue *value = b->instrs[j];
|
||||||
|
GB_ASSERT(value->kind == ssaValue_Instr);
|
||||||
|
ssaInstr *instr = &value->instr;
|
||||||
|
// NOTE(bill): Ignore non-returning instructions
|
||||||
|
switch (instr->kind) {
|
||||||
|
case ssaInstr_Store:
|
||||||
|
case ssaInstr_Br:
|
||||||
|
case ssaInstr_Ret:
|
||||||
|
case ssaInstr_Unreachable:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
value->id = reg_id;
|
||||||
|
reg_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_push_target_list(ssaProcedure *proc, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) {
|
||||||
|
ssaTargetList *tl = gb_alloc_item(proc->module->allocator, ssaTargetList);
|
||||||
|
tl->prev = proc->target_list;
|
||||||
|
tl->break_ = break_;
|
||||||
|
tl->continue_ = continue_;
|
||||||
|
tl->fallthrough_ = fallthrough_;
|
||||||
|
proc->target_list = tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssa_pop_target_list(ssaProcedure *proc) {
|
||||||
|
proc->target_list = proc->target_list->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||||
Type *src_type = ssa_value_type(value);
|
Type *src_type = ssa_value_type(value);
|
||||||
if (are_types_identical(t, src_type))
|
if (are_types_identical(t, src_type))
|
||||||
@@ -632,18 +768,10 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue
|
|||||||
return ssa_emit(proc, v);
|
return ssa_emit(proc, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
|
ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
|
||||||
Type *a = get_base_type(ssa_value_type(left));
|
Type *a = get_base_type(ssa_value_type(left));
|
||||||
Type *b = get_base_type(ssa_value_type(right));
|
Type *b = get_base_type(ssa_value_type(right));
|
||||||
|
|
||||||
if (op.kind == Token_CmpEq &&
|
|
||||||
left->kind == ssaValue_Constant && left->constant.value.kind == ExactValue_Bool) {
|
|
||||||
if (left->constant.value.value_bool) {
|
|
||||||
if (is_type_boolean(b))
|
|
||||||
return right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (are_types_identical(a, b)) {
|
if (are_types_identical(a, b)) {
|
||||||
// NOTE(bill): No need for a conversion
|
// NOTE(bill): No need for a conversion
|
||||||
} else if (left->kind == ssaValue_Constant) {
|
} else if (left->kind == ssaValue_Constant) {
|
||||||
@@ -658,21 +786,6 @@ ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block) {
|
|
||||||
ssaValue *br = ssa_make_instr_br(proc, NULL, block, NULL);
|
|
||||||
ssa_emit(proc, br);
|
|
||||||
proc->curr_block = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) {
|
|
||||||
ssaValue *br = ssa_make_instr_br(proc, cond, true_block, false_block);
|
|
||||||
ssa_emit(proc, br);
|
|
||||||
proc->curr_block = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
|
ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
|
||||||
@@ -690,7 +803,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
|
|
||||||
auto *found = map_get(&proc->module->values, hash_pointer(e));
|
auto *found = map_get(&proc->module->values, hash_pointer(e));
|
||||||
if (found) {
|
if (found) {
|
||||||
return ssa_emit_load(proc, *found);
|
ssaValue *v = *found;
|
||||||
|
if (v->kind == ssaValue_Proc)
|
||||||
|
return v;
|
||||||
|
return ssa_emit_load(proc, v);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -699,9 +815,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(de, DerefExpr, expr);
|
case_ast_node(de, DerefExpr, expr);
|
||||||
ssaValue *load = ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
|
return ssa_lvalue_load(ssa_build_addr(proc, expr), proc);
|
||||||
ssa_value_set_type(load, type_deref(ssa_value_type(load)));
|
|
||||||
return load;
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ue, UnaryExpr, expr);
|
case_ast_node(ue, UnaryExpr, expr);
|
||||||
@@ -754,9 +868,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
case Token_LtEq:
|
case Token_LtEq:
|
||||||
case Token_Gt:
|
case Token_Gt:
|
||||||
case Token_GtEq: {
|
case Token_GtEq: {
|
||||||
ssaValue *cmp = ssa_emit_compare(proc, be->op,
|
ssaValue *left = ssa_build_expr(proc, be->left);
|
||||||
ssa_build_expr(proc, be->left),
|
ssaValue *right = ssa_build_expr(proc, be->right);
|
||||||
ssa_build_expr(proc, be->right));
|
ssaValue *cmp = ssa_emit_comp(proc, be->op, left, right);
|
||||||
return ssa_emit_conv(proc, cmp, default_type(tv->type));
|
return ssa_emit_conv(proc, cmp, default_type(tv->type));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -789,16 +903,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
// TODO(bill): Strings AstNode_IndexExpression
|
// TODO(bill): Strings AstNode_IndexExpression
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Slice: {
|
case Type_Slice:
|
||||||
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
|
case Type_Array:
|
||||||
return ssa_emit_load(proc, v);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Type_Array: {
|
|
||||||
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
|
|
||||||
return ssa_emit_load(proc, v);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Type_Pointer: {
|
case Type_Pointer: {
|
||||||
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
|
ssaValue *v = ssa_lvalue_address(ssa_build_addr(proc, expr), proc);
|
||||||
return ssa_emit_load(proc, v);
|
return ssa_emit_load(proc, v);
|
||||||
@@ -807,6 +913,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SelectorExpr, expr);
|
case_ast_node(se, SelectorExpr, expr);
|
||||||
|
return ssa_build_expr(proc, se->selector);
|
||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,6 +953,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
case_ast_node(i, Ident, expr);
|
case_ast_node(i, Ident, expr);
|
||||||
if (ssa_is_blank_ident(expr)) {
|
if (ssa_is_blank_ident(expr)) {
|
||||||
ssaLvalue val = {ssaLvalue_Blank};
|
ssaLvalue val = {ssaLvalue_Blank};
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *e = entity_of_ident(proc->module->info, expr);
|
Entity *e = entity_of_ident(proc->module->info, expr);
|
||||||
@@ -855,18 +963,10 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
return ssa_make_lvalue_address(v, expr);
|
return ssa_make_lvalue_address(v, expr);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(cl, CompoundLit, expr);
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(pe, ParenExpr, expr);
|
case_ast_node(pe, ParenExpr, expr);
|
||||||
return ssa_build_addr(proc, unparen_expr(expr));
|
return ssa_build_addr(proc, unparen_expr(expr));
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(de, DerefExpr, expr);
|
|
||||||
ssaValue *v = ssa_build_expr(proc, de->expr);
|
|
||||||
return ssa_make_lvalue_address(v, expr);
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(se, SelectorExpr, expr);
|
case_ast_node(se, SelectorExpr, expr);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -889,6 +989,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
case Type_Pointer: {
|
case Type_Pointer: {
|
||||||
ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
|
ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, ie->expr), proc);
|
||||||
ssaValue *load = ssa_emit_load(proc, e);
|
ssaValue *load = ssa_emit_load(proc, e);
|
||||||
|
gb_printf("load: %s\n", type_to_string(ssa_value_type(load)));
|
||||||
ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
|
ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
|
||||||
ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load,
|
ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load,
|
||||||
index, NULL, 1, false);
|
index, NULL, 1, false);
|
||||||
@@ -896,6 +997,7 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
gep->instr.get_element_ptr.result_type = t->pointer.element;
|
gep->instr.get_element_ptr.result_type = t->pointer.element;
|
||||||
gep->instr.get_element_ptr.element_type = t->pointer.element;
|
gep->instr.get_element_ptr.element_type = t->pointer.element;
|
||||||
v = gep;
|
v = gep;
|
||||||
|
gb_printf("gep: %s\n", type_to_string(ssa_value_type(gep)));
|
||||||
} break;
|
} break;
|
||||||
case Type_Slice: {
|
case Type_Slice: {
|
||||||
GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice");
|
GB_PANIC("ssa_build_addr AstNode_IndexExpression Type_Slice");
|
||||||
@@ -906,6 +1008,18 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
return ssa_make_lvalue_address(ssa_emit(proc, v), expr);
|
return ssa_make_lvalue_address(ssa_emit(proc, v), expr);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(de, DerefExpr, expr);
|
||||||
|
// TODO(bill): Clean up
|
||||||
|
Type *t = type_of_expr(proc->module->info, de->expr);
|
||||||
|
t = type_deref(get_base_type(t));
|
||||||
|
ssaValue *e = ssa_lvalue_address(ssa_build_addr(proc, de->expr), proc);
|
||||||
|
ssaValue *load = ssa_emit_load(proc, e);
|
||||||
|
ssaValue *gep = ssa_make_instr_get_element_ptr(proc, load, NULL, NULL, 0, false);
|
||||||
|
gep->instr.get_element_ptr.result_type = t;
|
||||||
|
gep->instr.get_element_ptr.element_type = t;
|
||||||
|
return ssa_make_lvalue_address(ssa_emit(proc, gep), expr);
|
||||||
|
case_end;
|
||||||
|
|
||||||
// TODO(bill): Others address
|
// TODO(bill): Others address
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,15 +1052,13 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
|
|||||||
|
|
||||||
case_ast_node(be, BinaryExpr, cond);
|
case_ast_node(be, BinaryExpr, cond);
|
||||||
if (be->op.kind == Token_CmpAnd) {
|
if (be->op.kind == Token_CmpAnd) {
|
||||||
ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-true"));
|
ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-true"));
|
||||||
ssaBlock *block = &b->block;
|
|
||||||
ssa_build_cond(proc, be->left, block, false_block);
|
ssa_build_cond(proc, be->left, block, false_block);
|
||||||
proc->curr_block = block;
|
proc->curr_block = block;
|
||||||
ssa_build_cond(proc, be->right, true_block, false_block);
|
ssa_build_cond(proc, be->right, true_block, false_block);
|
||||||
return;
|
return;
|
||||||
} else if (be->op.kind == Token_CmpOr) {
|
} else if (be->op.kind == Token_CmpOr) {
|
||||||
ssaValue *b = ssa_add_block(proc, NULL, make_string("logical-false"));
|
ssaBlock *block = ssa_add_block(proc, NULL, make_string("logical-false"));
|
||||||
ssaBlock *block = &b->block;
|
|
||||||
ssa_build_cond(proc, be->left, true_block, block);
|
ssa_build_cond(proc, be->left, true_block, block);
|
||||||
proc->curr_block = block;
|
proc->curr_block = block;
|
||||||
ssa_build_cond(proc, be->right, true_block, false_block);
|
ssa_build_cond(proc, be->right, true_block, false_block);
|
||||||
@@ -960,7 +1072,6 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ssa_build_stmt(ssaProcedure *proc, AstNode *s);
|
|
||||||
|
|
||||||
void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) {
|
void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) {
|
||||||
for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next)
|
for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next)
|
||||||
@@ -1090,64 +1201,133 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *s) {
|
|||||||
ssa_build_expr(proc, es->expr);
|
ssa_build_expr(proc, es->expr);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(bs, BlockStmt, s);
|
case_ast_node(bs, BlockStmt, s)
|
||||||
ssa_build_stmt_list(proc, bs->list);
|
ssa_build_stmt_list(proc, bs->list);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(bs, DeferStmt, s);
|
||||||
|
// NOTE(bill): is already handled with scope
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(rs, ReturnStmt, s);
|
||||||
|
ssaValue *v = NULL;
|
||||||
|
auto *return_type_tuple = &proc->type->procedure.results->tuple;
|
||||||
|
isize return_count = proc->type->procedure.result_count;
|
||||||
|
if (rs->result_count == 1 && return_count > 1) {
|
||||||
|
GB_PANIC("ReturnStmt tuple return statement");
|
||||||
|
} else if (return_count == 1) {
|
||||||
|
Entity *e = return_type_tuple->variables[0];
|
||||||
|
v = ssa_emit_conv(proc, ssa_build_expr(proc, rs->result_list), e->type);
|
||||||
|
} else if (return_count == 0) {
|
||||||
|
// No return values
|
||||||
|
} else {
|
||||||
|
// 1:1 multiple return values
|
||||||
|
}
|
||||||
|
|
||||||
|
ssa_emit_ret(proc, v);
|
||||||
|
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(is, IfStmt, s);
|
case_ast_node(is, IfStmt, s);
|
||||||
if (is->init != NULL) {
|
if (is->init != NULL) {
|
||||||
ssa_build_stmt(proc, is->init);
|
ssa_build_stmt(proc, is->init);
|
||||||
}
|
}
|
||||||
ssaValue *then_block = ssa_add_block(proc, is->body, make_string("if-then"));
|
ssaBlock *then = ssa_add_block(proc, s, make_string("if.then"));
|
||||||
ssaValue *else_block = NULL;
|
ssaBlock *done = ssa__make_block(proc, s, make_string("if.done"));
|
||||||
|
ssaBlock *else_ = done;
|
||||||
if (is->else_stmt != NULL) {
|
if (is->else_stmt != NULL) {
|
||||||
else_block = ssa_add_block(proc, is->else_stmt, make_string("if-else"));
|
else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else"));
|
||||||
}
|
|
||||||
ssaValue *end_block = ssa_add_block(proc, is->body, make_string("if-end"));
|
|
||||||
if (else_block == NULL) {
|
|
||||||
else_block = end_block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssa_build_cond(proc, is->cond, &then_block->block, &else_block->block);
|
ssa_build_cond(proc, is->cond, then, else_);
|
||||||
proc->curr_block = &then_block->block;
|
proc->curr_block = then;
|
||||||
ssa_build_stmt(proc, is->body);
|
ssa_build_stmt(proc, is->body);
|
||||||
ssa_emit_jump(proc, &end_block->block);
|
ssa_emit_jump(proc, done);
|
||||||
|
|
||||||
if (is->else_stmt != NULL) {
|
if (is->else_stmt != NULL) {
|
||||||
proc->curr_block = &else_block->block;
|
proc->curr_block = else_;
|
||||||
ssa_build_stmt(proc, is->else_stmt);
|
ssa_build_stmt(proc, is->else_stmt);
|
||||||
ssa_emit_jump(proc, &end_block->block);
|
ssa_emit_jump(proc, done);
|
||||||
}
|
}
|
||||||
|
gb_array_append(proc->blocks, done);
|
||||||
proc->curr_block = &end_block->block;
|
proc->curr_block = done;
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(rs, ReturnStmt, s);
|
|
||||||
GB_PANIC("AstNode_ReturnStmt");
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fs, ForStmt, s);
|
case_ast_node(fs, ForStmt, s);
|
||||||
GB_PANIC("AstNode_ForStmt");
|
if (fs->init != NULL) {
|
||||||
case_end;
|
ssa_build_stmt(proc, fs->init);
|
||||||
|
}
|
||||||
|
ssaBlock *body = ssa_add_block(proc, s, make_string("for.body"));
|
||||||
|
ssaBlock *done = ssa__make_block(proc, s, make_string("for.done")); // NOTE(bill): Append later
|
||||||
|
|
||||||
|
ssaBlock *loop = body;
|
||||||
|
|
||||||
|
if (fs->cond != NULL) {
|
||||||
|
loop = ssa_add_block(proc, fs->cond, make_string("for.loop"));
|
||||||
|
}
|
||||||
|
ssaBlock *cont = loop;
|
||||||
|
if (fs->post != NULL) {
|
||||||
|
cont = ssa_add_block(proc, fs->cond, make_string("for.post"));
|
||||||
|
}
|
||||||
|
ssa_emit_jump(proc, loop);
|
||||||
|
proc->curr_block = loop;
|
||||||
|
if (loop != body) {
|
||||||
|
ssa_build_cond(proc, fs->cond, body, done);
|
||||||
|
proc->curr_block = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssa_push_target_list(proc, done, cont, NULL);
|
||||||
|
ssa_build_stmt(proc, fs->body);
|
||||||
|
ssa_pop_target_list(proc);
|
||||||
|
ssa_emit_jump(proc, cont);
|
||||||
|
|
||||||
|
if (fs->post != NULL) {
|
||||||
|
proc->curr_block = cont;
|
||||||
|
ssa_build_stmt(proc, fs->post);
|
||||||
|
ssa_emit_jump(proc, loop);
|
||||||
|
}
|
||||||
|
gb_array_append(proc->blocks, done);
|
||||||
|
proc->curr_block = done;
|
||||||
|
|
||||||
case_ast_node(bs, DeferStmt, s);
|
|
||||||
GB_PANIC("AstNode_DeferStmt");
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(bs, BranchStmt, s);
|
case_ast_node(bs, BranchStmt, s);
|
||||||
GB_PANIC("AstNode_BranchStmt");
|
ssaBlock *block = NULL;
|
||||||
|
switch (bs->token.kind) {
|
||||||
|
case Token_break: {
|
||||||
|
for (ssaTargetList *t = proc->target_list;
|
||||||
|
t != NULL && block == NULL;
|
||||||
|
t = t->prev) {
|
||||||
|
block = t->break_;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Token_continue: {
|
||||||
|
for (ssaTargetList *t = proc->target_list;
|
||||||
|
t != NULL && block == NULL;
|
||||||
|
t = t->prev) {
|
||||||
|
block = t->continue_;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Token_fallthrough: {
|
||||||
|
for (ssaTargetList *t = proc->target_list;
|
||||||
|
t != NULL && block == NULL;
|
||||||
|
t = t->prev) {
|
||||||
|
block = t->fallthrough_;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ssa_emit_jump(proc, block);
|
||||||
|
ssa_emit_unreachable(proc);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ssa_build_procedure(ssaValue *value) {
|
void ssa_build_proc(ssaValue *value) {
|
||||||
ssaProcedure *proc = &value->proc;
|
ssaProcedure *proc = &value->proc;
|
||||||
|
|
||||||
// gb_printf("Building %.*s: %.*s\n", LIT(entity_strings[proc->entity->kind]), LIT(proc->name));
|
|
||||||
|
|
||||||
|
|
||||||
AstNode *proc_decl = proc->decl->proc_decl;
|
AstNode *proc_decl = proc->decl->proc_decl;
|
||||||
switch (proc_decl->kind) {
|
switch (proc_decl->kind) {
|
||||||
case_ast_node(pd, ProcDecl, proc_decl);
|
case_ast_node(pd, ProcDecl, proc_decl);
|
||||||
@@ -1158,16 +1338,11 @@ void ssa_build_procedure(ssaValue *value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc->body == NULL) {
|
if (proc->body != NULL) {
|
||||||
// TODO(bill): External procedure
|
ssa_begin_procedure_body(proc);
|
||||||
return;
|
ssa_build_stmt(proc, proc->body);
|
||||||
|
ssa_end_procedure_body(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssa_begin_procedure_body(proc);
|
|
||||||
ssa_build_stmt(proc, proc->body);
|
|
||||||
ssa_end_procedure_body(proc);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -144,7 +144,7 @@ AST_NODE_KIND(_ComplexStmtBegin, struct{}) \
|
|||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ForStmt, struct { \
|
AST_NODE_KIND(ForStmt, struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
AstNode *init, *cond, *end; \
|
AstNode *init, *cond, *post; \
|
||||||
AstNode *body; \
|
AstNode *body; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(DeferStmt, struct { Token token; AstNode *stmt; }) \
|
AST_NODE_KIND(DeferStmt, struct { Token token; AstNode *stmt; }) \
|
||||||
@@ -638,12 +638,12 @@ gb_inline AstNode *make_return_stmt(AstFile *f, Token token, AstNode *result_lis
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *end, AstNode *body) {
|
gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
|
||||||
AstNode *result = make_node(f, AstNode_ForStmt);
|
AstNode *result = make_node(f, AstNode_ForStmt);
|
||||||
result->ForStmt.token = token;
|
result->ForStmt.token = token;
|
||||||
result->ForStmt.init = init;
|
result->ForStmt.init = init;
|
||||||
result->ForStmt.cond = cond;
|
result->ForStmt.cond = cond;
|
||||||
result->ForStmt.end = end;
|
result->ForStmt.post = post;
|
||||||
result->ForStmt.body = body;
|
result->ForStmt.body = body;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ void print_ast(AstNode *node, isize indent) {
|
|||||||
gb_printf("(for)\n");
|
gb_printf("(for)\n");
|
||||||
print_ast(node->ForStmt.init, indent+1);
|
print_ast(node->ForStmt.init, indent+1);
|
||||||
print_ast(node->ForStmt.cond, indent+1);
|
print_ast(node->ForStmt.cond, indent+1);
|
||||||
print_ast(node->ForStmt.end, indent+1);
|
print_ast(node->ForStmt.post, indent+1);
|
||||||
print_ast(node->ForStmt.body, indent+1);
|
print_ast(node->ForStmt.body, indent+1);
|
||||||
break;
|
break;
|
||||||
case AstNode_DeferStmt:
|
case AstNode_DeferStmt:
|
||||||
|
|||||||
Reference in New Issue
Block a user