aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-03-12 16:42:51 +0000
committerGinger Bill <bill@gingerbill.org>2017-03-12 16:42:51 +0000
commitaaec8bf423a40f887d43d12403c2e40f187d424c (patch)
tree98958a8c7db53197a0176fcc7607bdcad0a4d8c3 /src
parent0fcbda951aea462248304a7e16f5c4eb9da9939d (diff)
windows.odin TYPE_NAME to Type_Name; More SSA work and SSA printing for debugging
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.c53
-rw-r--r--src/check_expr.c46
-rw-r--r--src/checker.c11
-rw-r--r--src/entity.c11
-rw-r--r--src/gb/gb.h4
-rw-r--r--src/ir.c52
-rw-r--r--src/parser.c14
-rw-r--r--src/ssa.c1573
8 files changed, 1415 insertions, 349 deletions
diff --git a/src/check_decl.c b/src/check_decl.c
index bc49e36c1..a89460123 100644
--- a/src/check_decl.c
+++ b/src/check_decl.c
@@ -408,6 +408,56 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
+void check_alias_decl(Checker *c, Entity *e, AstNode *expr) {
+ GB_ASSERT(e->type == NULL);
+ GB_ASSERT(e->kind == Entity_Alias);
+
+ if (e->flags & EntityFlag_Visited) {
+ e->type = t_invalid;
+ return;
+ }
+ e->flags |= EntityFlag_Visited;
+ e->type = t_invalid;
+
+ expr = unparen_expr(expr);
+
+ if (expr->kind == AstNode_Alias) {
+ error_node(expr, "#alias of an #alias is not allowed");
+ return;
+ }
+
+ if (expr->kind == AstNode_Ident) {
+ Operand o = {0};
+ Entity *f = check_ident(c, &o, expr, NULL, NULL, true);
+ if (f != NULL) {
+ e->Alias.original = f;
+ e->type = f->type;
+ }
+ return;
+ } else if (expr->kind == AstNode_SelectorExpr) {
+ Operand o = {0};
+ Entity *f = check_selector(c, &o, expr, NULL);
+ if (f != NULL) {
+ e->Alias.original = f;
+ e->type = f->type;
+ }
+ return;
+ }
+
+ Operand o = {0};
+ check_expr_or_type(c, &o, expr);
+ if (o.mode == Addressing_Invalid) {
+ return;
+ }
+ switch (o.mode) {
+ case Addressing_Type:
+ e->type = o.type;
+ break;
+ default:
+ error_node(expr, "#alias declarations only allow types");
+ }
+}
+
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
@@ -443,6 +493,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
case Entity_Procedure:
check_proc_lit(c, e, d);
break;
+ case Entity_Alias:
+ check_alias_decl(c, e, d->init_expr);
+ break;
}
c->context = prev;
diff --git a/src/check_expr.c b/src/check_expr.c
index 3f6e591c0..75105462b 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -1028,7 +1028,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
}
-void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint) {
+Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
GB_ASSERT(n->kind == AstNode_Ident);
o->mode = Addressing_Invalid;
o->expr = n;
@@ -1046,7 +1046,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
if (named_type != NULL) {
set_base_type(named_type, t_invalid);
}
- return;
+ return NULL;
}
bool is_overloaded = false;
@@ -1095,7 +1095,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
o->type = t_invalid;
o->overload_count = overload_count;
o->overload_entities = procs;
- return;
+ return NULL;
}
gb_free(heap_allocator(), procs);
}
@@ -1106,20 +1106,26 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
if (e->type == NULL) {
compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(name));
- return;
+ return NULL;
}
- Type *type = e->type;
+ e->flags |= EntityFlag_Used;
+
+ Entity *original_e = e;
+ while (e->kind == Entity_Alias && e->Alias.original != NULL) {
+ e = e->Alias.original;
+ }
+ Type *type = e->type;
switch (e->kind) {
case Entity_Constant:
if (type == t_invalid) {
o->type = t_invalid;
- return;
+ return e;
}
o->value = e->Constant.value;
if (o->value.kind == ExactValue_Invalid) {
- return;
+ return e;
}
o->mode = Addressing_Constant;
break;
@@ -1128,7 +1134,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
e->flags |= EntityFlag_Used;
if (type == t_invalid) {
o->type = t_invalid;
- return;
+ return e;
}
o->mode = Addressing_Variable;
if (e->Variable.is_immutable) {
@@ -1151,22 +1157,25 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
break;
case Entity_ImportName:
- error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
- return;
+ if (!allow_import_name) {
+ error_node(n, "Use of import `%.*s` not in selector", LIT(name));
+ }
+ return e;
case Entity_LibraryName:
- error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name));
- return;
+ error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(name));
+ return e;
case Entity_Nil:
o->mode = Addressing_Value;
break;
default:
- compiler_error("Compiler error: Unknown EntityKind");
+ compiler_error("Unknown EntityKind");
break;
}
o->type = type;
+ return e;
}
i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
@@ -1342,7 +1351,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
switch (e->kind) {
case_ast_node(i, Ident, e);
Operand o = {0};
- check_ident(c, &o, e, named_type, NULL);
+ check_ident(c, &o, e, named_type, NULL, false);
switch (o.mode) {
case Addressing_Invalid:
@@ -2679,6 +2688,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
add_entity_use(c, op_expr, e);
expr_entity = e;
+ Entity *original_e = e;
+ while (e->kind == Entity_Alias && e->Alias.original != NULL) {
+ e = e->Alias.original;
+ }
+
if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) {
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
// It pretty much needs to be in this order and this way
@@ -4413,7 +4427,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case_end;
case_ast_node(i, Ident, node);
- check_ident(c, o, node, NULL, type_hint);
+ check_ident(c, o, node, NULL, type_hint, false);
case_end;
case_ast_node(bl, BasicLit, node);
@@ -5626,7 +5640,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_end;
case_ast_node(ht, HelperType, node);
- str = gb_string_appendc(str, "type ");
+ str = gb_string_appendc(str, "#type ");
str = write_expr_to_string(str, ht->type);
case_end;
}
diff --git a/src/checker.c b/src/checker.c
index 2e2eceefc..881e86c8b 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -816,7 +816,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
- "Redeclararation of `%.*s` in this scope through `using`\n"
+ "Redeclaration of `%.*s` in this scope through `using`\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
@@ -827,7 +827,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
- "Redeclararation of `%.*s` in this scope\n"
+ "Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
@@ -1467,7 +1467,12 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
// TODO(bill): What if vd->type != NULL??? How to handle this case?
d->type_expr = init;
d->init_expr = init;
- } else if (init != NULL && up_init->kind == AstNode_ProcLit) {
+ } else if (up_init != NULL && up_init->kind == AstNode_Alias) {
+ error_node(up_init, "#alias declarations are not yet supported");
+ continue;
+ // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, NULL);
+ // d->init_expr = init->Alias.expr;
+ }else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_lit = up_init;
d->type_expr = vd->type;
diff --git a/src/entity.c b/src/entity.c
index 32d070953..446edfa54 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -13,6 +13,7 @@ typedef struct Type Type;
ENTITY_KIND(Builtin) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
+ ENTITY_KIND(Alias) \
ENTITY_KIND(Nil) \
ENTITY_KIND(Count)
@@ -95,6 +96,9 @@ struct Entity {
String name;
bool used;
} LibraryName;
+ struct {
+ Entity *original;
+ } Alias;
i32 Nil;
};
};
@@ -218,6 +222,13 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
return entity;
}
+Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
+ Entity *original) {
+ Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
+ entity->Alias.original = original;
+ return entity;
+}
+
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
diff --git a/src/gb/gb.h b/src/gb/gb.h
index d30e5d129..9a665e050 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -806,6 +806,10 @@ GB_DEF void const *gb_memchr (void const *data, u8 byte_value, isize size);
GB_DEF void const *gb_memrchr (void const *data, u8 byte_value, isize size);
+#ifndef gb_memcopy_array
+#define gb_memcopy_array(dst, src, count) gb_memcopy((dst), (src), gb_size_of(*(dst))*(count))
+#endif
+
// NOTE(bill): Very similar to doing `*cast(T *)(&u)`
#ifndef GB_BIT_CAST
#define GB_BIT_CAST(dest, source) do { \
diff --git a/src/ir.c b/src/ir.c
index a5bb58111..44f24d5d6 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -2916,8 +2916,21 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts);
-irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv) {
+
+irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
expr = unparen_expr(expr);
+
+ TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr));
+ GB_ASSERT_NOT_NULL(tv);
+
+ if (tv->value.kind != ExactValue_Invalid) {
+ return ir_add_module_constant(proc->module, tv->type, tv->value);
+ }
+
+ if (tv->mode == Addressing_Variable) {
+ return ir_addr_load(proc, ir_build_addr(proc, expr));
+ }
+
switch (expr->kind) {
case_ast_node(bl, BasicLit, expr);
TokenPos pos = bl->pos;
@@ -3782,27 +3795,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
return NULL;
}
-
-irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
- expr = unparen_expr(expr);
-
- TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr));
- GB_ASSERT_NOT_NULL(tv);
-
- if (tv->value.kind != ExactValue_Invalid) {
- return ir_add_module_constant(proc->module, tv->type, tv->value);
- }
-
- irValue *value = NULL;
- if (tv->mode == Addressing_Variable) {
- value = ir_addr_load(proc, ir_build_addr(proc, expr));
- } else {
- value = ir_build_single_expr(proc, expr, tv);
- }
-
- return value;
-}
-
irValue *ir_get_using_variable(irProcedure *proc, Entity *e) {
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous);
String name = e->token.string;
@@ -5192,9 +5184,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
if (fs->cond != NULL) {
loop = ir_new_block(proc, node, "for.loop");
}
- irBlock *cont = loop;
+ irBlock *post = loop;
if (fs->post != NULL) {
- cont = ir_new_block(proc, node, "for.post");
+ post = ir_new_block(proc, node, "for.post");
}
ir_emit_jump(proc, loop);
ir_start_block(proc, loop);
@@ -5204,7 +5196,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_start_block(proc, body);
}
- ir_push_target_list(proc, done, cont, NULL);
+ ir_push_target_list(proc, done, post, NULL);
ir_open_scope(proc);
ir_build_stmt(proc, fs->body);
@@ -5212,10 +5204,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_pop_target_list(proc);
- ir_emit_jump(proc, cont);
+ ir_emit_jump(proc, post);
if (fs->post != NULL) {
- ir_start_block(proc, cont);
+ ir_start_block(proc, post);
ir_build_stmt(proc, fs->post);
ir_emit_jump(proc, loop);
}
@@ -5646,7 +5638,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
case_end;
- case_ast_node(pa, PushContext, node);
+ case_ast_node(pc, PushContext, node);
ir_emit_comment(proc, str_lit("PushContext"));
ir_open_scope(proc);
@@ -5656,9 +5648,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context)));
- ir_emit_store(proc, context_ptr, ir_build_expr(proc, pa->expr));
+ ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr));
- ir_build_stmt(proc, pa->body);
+ ir_build_stmt(proc, pc->body);
ir_close_scope(proc, irDeferExit_Default, NULL);
case_end;
diff --git a/src/parser.c b/src/parser.c
index 160b72ef3..2905489d6 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -139,6 +139,10 @@ AstNodeArray make_ast_node_array(AstFile *f) {
AstNodeArray elems; \
Token open, close; \
}) \
+ AST_NODE_KIND(Alias, "alias", struct { \
+ Token token; \
+ AstNode *expr; \
+ }) \
AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \
@@ -445,6 +449,8 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->CompoundLit.type);
}
return node->CompoundLit.open;
+ case AstNode_Alias: return node->Alias.token;
+
case AstNode_TagExpr: return node->TagExpr.token;
case AstNode_RunExpr: return node->RunExpr.token;
case AstNode_BadExpr: return node->BadExpr.begin;
@@ -771,6 +777,13 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
result->CompoundLit.close = close;
return result;
}
+AstNode *ast_alias(AstFile *f, Token token, AstNode *expr) {
+ AstNode *result = make_ast_node(f, AstNode_Alias);
+ result->Alias.token = token;
+ result->Alias.expr = expr;
+ return result;
+}
+
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
@@ -1762,6 +1775,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f));
+ } else if (!lhs && str_eq(name.string, str_lit("alias"))) { return ast_alias(f, token, parse_expr(f, false));
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
diff --git a/src/ssa.c b/src/ssa.c
index 2448ffdd9..7bccf027d 100644
--- a/src/ssa.c
+++ b/src/ssa.c
@@ -1,12 +1,13 @@
-typedef enum ssaOp ssaOp;
-typedef struct ssaModule ssaModule;
-typedef struct ssaValue ssaValue;
-typedef struct ssaBlock ssaBlock;
-typedef struct ssaProc ssaProc;
-typedef struct ssaEdge ssaEdge;
-typedef struct ssaRegister ssaRegister;
-typedef enum ssaBlockKind ssaBlockKind;
-typedef enum ssaBranchPrediction ssaBranchPrediction;
+typedef enum ssaOp ssaOp;
+typedef struct ssaModule ssaModule;
+typedef struct ssaValue ssaValue;
+typedef struct ssaBlock ssaBlock;
+typedef struct ssaProc ssaProc;
+typedef struct ssaEdge ssaEdge;
+typedef struct ssaRegister ssaRegister;
+typedef struct ssaTargetList ssaTargetList;
+typedef enum ssaBlockKind ssaBlockKind;
+typedef enum ssaBranchPrediction ssaBranchPrediction;
String ssa_mangle_name(ssaModule *m, String path, Entity *e);
@@ -17,265 +18,280 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e);
typedef Array(ssaValue *) ssaValueArray;
+
+#define SSA_OPS \
+ SSA_OP(Invalid)\
+\
+ SSA_OP(Unknown)\
+\
+ SSA_OP(Comment) /* Does nothing */\
+\
+ SSA_OP(SP) /* Stack Pointer */\
+ SSA_OP(SB) /* Stack Base */\
+ SSA_OP(Addr) /* Address of something - special rules for certain types when loading and storing (e.g. Maps) */\
+\
+ SSA_OP(Local)\
+ SSA_OP(Global)\
+ SSA_OP(Proc)\
+\
+ SSA_OP(Load)\
+ SSA_OP(Store)\
+ SSA_OP(Move)\
+ SSA_OP(Zero) /* Zero initialize */\
+\
+ SSA_OP(ArrayIndex) /* Index for a fixed array */\
+ SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
+ SSA_OP(OffsetPtr)\
+ SSA_OP(ValueIndex) /* Extract for a value from a register */\
+\
+ SSA_OP(Phi)\
+ SSA_OP(Copy)\
+\
+ /* TODO(bill): calling conventions */\
+ SSA_OP(CallOdin)\
+ SSA_OP(CallC)\
+ SSA_OP(CallStd)\
+ SSA_OP(CallFast)\
+\
+ SSA_OP(BoundsCheck)\
+ SSA_OP(SliceBoundsCheck)\
+\
+ /* Built in operations/procedures */\
+ SSA_OP(Bswap16)\
+ SSA_OP(Bswap32)\
+ SSA_OP(Bswap64)\
+\
+ SSA_OP(Assume)\
+ SSA_OP(DebugTrap)\
+ SSA_OP(Trap)\
+ SSA_OP(ReadCycleCounter)\
+\
+\
+ SSA_OP(ConstBool)\
+ SSA_OP(ConstString)\
+ SSA_OP(ConstSlice)\
+ SSA_OP(ConstNil)\
+ SSA_OP(Const8)\
+ SSA_OP(Const16)\
+ SSA_OP(Const32)\
+ SSA_OP(Const64)\
+ SSA_OP(Const32F)\
+ SSA_OP(Const64F)\
+\
+ /* These should be all the operations I could possibly need for the mean time */\
+ SSA_OP(Add8)\
+ SSA_OP(Add16)\
+ SSA_OP(Add32)\
+ SSA_OP(Add64)\
+ SSA_OP(AddPtr)\
+ SSA_OP(Add32F)\
+ SSA_OP(Add64F)\
+ SSA_OP(Sub8)\
+ SSA_OP(Sub16)\
+ SSA_OP(Sub32)\
+ SSA_OP(Sub64)\
+ SSA_OP(SubPtr)\
+ SSA_OP(Sub32F)\
+ SSA_OP(Sub64F)\
+ SSA_OP(Mul8)\
+ SSA_OP(Mul16)\
+ SSA_OP(Mul32)\
+ SSA_OP(Mul64)\
+ SSA_OP(Mul32F)\
+ SSA_OP(Mul64F)\
+ SSA_OP(Div8)\
+ SSA_OP(Div8U)\
+ SSA_OP(Div16)\
+ SSA_OP(Div16U)\
+ SSA_OP(Div32)\
+ SSA_OP(Div32U)\
+ SSA_OP(Div64)\
+ SSA_OP(Div64U)\
+ SSA_OP(Div32F)\
+ SSA_OP(Div64F)\
+ SSA_OP(Mod8)\
+ SSA_OP(Mod8U)\
+ SSA_OP(Mod16)\
+ SSA_OP(Mod16U)\
+ SSA_OP(Mod32)\
+ SSA_OP(Mod32U)\
+ SSA_OP(Mod64)\
+ SSA_OP(Mod64U)\
+\
+ SSA_OP(And8)\
+ SSA_OP(And16)\
+ SSA_OP(And32)\
+ SSA_OP(And64)\
+ SSA_OP(Or8)\
+ SSA_OP(Or16)\
+ SSA_OP(Or32)\
+ SSA_OP(Or64)\
+ SSA_OP(Xor8)\
+ SSA_OP(Xor16)\
+ SSA_OP(Xor32)\
+ SSA_OP(Xor64)\
+ SSA_OP(AndNot8)\
+ SSA_OP(AndNot16)\
+ SSA_OP(AndNot32)\
+ SSA_OP(AndNot64)\
+\
+ SSA_OP(Lsh8x8)\
+ SSA_OP(Lsh8x16)\
+ SSA_OP(Lsh8x32)\
+ SSA_OP(Lsh8x64)\
+ SSA_OP(Lsh16x8)\
+ SSA_OP(Lsh16x16)\
+ SSA_OP(Lsh16x32)\
+ SSA_OP(Lsh16x64)\
+ SSA_OP(Lsh32x8)\
+ SSA_OP(Lsh32x16)\
+ SSA_OP(Lsh32x32)\
+ SSA_OP(Lsh32x64)\
+ SSA_OP(Lsh64x8)\
+ SSA_OP(Lsh64x16)\
+ SSA_OP(Lsh64x32)\
+ SSA_OP(Lsh64x64)\
+ SSA_OP(Rsh8x8)\
+ SSA_OP(Rsh8x16)\
+ SSA_OP(Rsh8x32)\
+ SSA_OP(Rsh8x64)\
+ SSA_OP(Rsh16x8)\
+ SSA_OP(Rsh16x16)\
+ SSA_OP(Rsh16x32)\
+ SSA_OP(Rsh16x64)\
+ SSA_OP(Rsh32x8)\
+ SSA_OP(Rsh32x16)\
+ SSA_OP(Rsh32x32)\
+ SSA_OP(Rsh32x64)\
+ SSA_OP(Rsh64x8)\
+ SSA_OP(Rsh64x16)\
+ SSA_OP(Rsh64x32)\
+ SSA_OP(Rsh64x64)\
+ SSA_OP(Rsh8Ux8)\
+ SSA_OP(Rsh8Ux16)\
+ SSA_OP(Rsh8Ux32)\
+ SSA_OP(Rsh8Ux64)\
+ SSA_OP(Rsh16Ux8)\
+ SSA_OP(Rsh16Ux16)\
+ SSA_OP(Rsh16Ux32)\
+ SSA_OP(Rsh16Ux64)\
+ SSA_OP(Rsh32Ux8)\
+ SSA_OP(Rsh32Ux16)\
+ SSA_OP(Rsh32Ux32)\
+ SSA_OP(Rsh32Ux64)\
+ SSA_OP(Rsh64Ux8)\
+ SSA_OP(Rsh64Ux16)\
+ SSA_OP(Rsh64Ux32)\
+ SSA_OP(Rsh64Ux64)\
+\
+ SSA_OP(Eq8)\
+ SSA_OP(Eq16)\
+ SSA_OP(Eq32)\
+ SSA_OP(Eq64)\
+ SSA_OP(EqPtr)\
+ SSA_OP(Eq32F)\
+ SSA_OP(Eq64F)\
+ SSA_OP(Ne8)\
+ SSA_OP(Ne16)\
+ SSA_OP(Ne32)\
+ SSA_OP(Ne64)\
+ SSA_OP(NePtr)\
+ SSA_OP(Ne32F)\
+ SSA_OP(Ne64F)\
+ SSA_OP(Lt8)\
+ SSA_OP(Lt16)\
+ SSA_OP(Lt32)\
+ SSA_OP(Lt64)\
+ SSA_OP(LtPtr)\
+ SSA_OP(Lt32F)\
+ SSA_OP(Lt64F)\
+ SSA_OP(Gt8)\
+ SSA_OP(Gt16)\
+ SSA_OP(Gt32)\
+ SSA_OP(Gt64)\
+ SSA_OP(GtPtr)\
+ SSA_OP(Gt32F)\
+ SSA_OP(Gt64F)\
+ SSA_OP(Le8)\
+ SSA_OP(Le16)\
+ SSA_OP(Le32)\
+ SSA_OP(Le64)\
+ SSA_OP(LePtr)\
+ SSA_OP(Le32F)\
+ SSA_OP(Le64F)\
+ SSA_OP(Ge8)\
+ SSA_OP(Ge16)\
+ SSA_OP(Ge32)\
+ SSA_OP(Ge64)\
+ SSA_OP(GePtr)\
+ SSA_OP(Ge32F)\
+ SSA_OP(Ge64F)\
+\
+ SSA_OP(NotB)\
+ SSA_OP(EqB)\
+ SSA_OP(NeB)\
+\
+ SSA_OP(Neg8)\
+ SSA_OP(Neg16)\
+ SSA_OP(Neg32)\
+ SSA_OP(Neg64)\
+ SSA_OP(Neg32F)\
+ SSA_OP(Neg64F)\
+\
+ SSA_OP(Not8)\
+ SSA_OP(Not16)\
+ SSA_OP(Not32)\
+ SSA_OP(Not64)\
+\
+ SSA_OP(SignExt8to16)\
+ SSA_OP(SignExt8to32)\
+ SSA_OP(SignExt8to64)\
+ SSA_OP(SignExt16to32)\
+ SSA_OP(SignExt16to64)\
+ SSA_OP(SignExt32to64)\
+ SSA_OP(ZeroExt8to16)\
+ SSA_OP(ZeroExt8to32)\
+ SSA_OP(ZeroExt8to64)\
+ SSA_OP(ZeroExt16to32)\
+ SSA_OP(ZeroExt16to64)\
+ SSA_OP(ZeroExt32to64)\
+ SSA_OP(Trunc16to8)\
+ SSA_OP(Trunc32to8)\
+ SSA_OP(Trunc32to16)\
+ SSA_OP(Trunc64to8)\
+ SSA_OP(Trunc64to16)\
+ SSA_OP(Trunc64to32)\
+\
+ SSA_OP(Cvt32to32F)\
+ SSA_OP(Cvt32to64F)\
+ SSA_OP(Cvt64to32F)\
+ SSA_OP(Cvt64to64F)\
+ SSA_OP(Cvt32Fto32)\
+ SSA_OP(Cvt32Fto64)\
+ SSA_OP(Cvt64Fto32)\
+ SSA_OP(Cvt64Fto64)\
+ SSA_OP(Cvt32Fto64F)\
+ SSA_OP(Cvt64Fto32F)\
+ SSA_OP(Cvt32Uto32F)\
+ SSA_OP(Cvt32Uto64F)\
+ SSA_OP(Cvt32Fto32U)\
+ SSA_OP(Cvt64Fto32U)\
+ SSA_OP(Cvt64Uto32F)\
+ SSA_OP(Cvt64Uto64F)\
+ SSA_OP(Cvt32Fto64U)\
+ SSA_OP(Cvt64Fto64U)\
+
+
enum ssaOp {
- ssaOp_Invalid,
-
- ssaOp_Unknown,
-
- ssaOp_Comment, // Does nothing
-
- ssaOp_SP, // Stack Pointer
- ssaOp_SB, // Stack Base
- ssaOp_Addr, // Address of something - special rules for certain types when loading and storing (e.g. Maps)
-
- ssaOp_Local,
- ssaOp_Global,
- ssaOp_Proc,
-
- ssaOp_Load,
- ssaOp_Store,
- ssaOp_Move,
- ssaOp_Zero, // Zero initialize
-
- ssaOp_ArrayIndex, // Index for a fixed array
- ssaOp_PtrIndex, // Index for a struct/tuple/etc
- ssaOp_OffsetPtr,
- ssaOp_ValueIndex, // Extract for a value from a register
-
- ssaOp_Phi,
- ssaOp_Copy,
-
- // TODO(bill): calling conventions
- ssaOp_CallOdin,
- ssaOp_CallC,
- ssaOp_CallStd,
- ssaOp_CallFast,
-
- ssaOp_BoundsCheck,
- ssaOp_SliceBoundsCheck,
-
- // Built in operations/procedures
- ssaOp_Bswap16,
- ssaOp_Bswap32,
- ssaOp_Bswap64,
-
- ssaOp_Assume,
- ssaOp_DebugTrap,
- ssaOp_Trap,
- ssaOp_ReadCycleCounter,
-
-
- ssaOp_ConstBool,
- ssaOp_ConstString,
- ssaOp_ConstSlice,
- ssaOp_ConstNil,
- ssaOp_Const8,
- ssaOp_Const16,
- ssaOp_Const32,
- ssaOp_Const64,
- ssaOp_Const32F,
- ssaOp_Const64F,
-
- // These should be all the operations I could possibly need for the mean time
- ssaOp_Add8,
- ssaOp_Add16,
- ssaOp_Add32,
- ssaOp_Add64,
- ssaOp_AddPtr,
- ssaOp_Add32F,
- ssaOp_Add64F,
- ssaOp_Sub8,
- ssaOp_Sub16,
- ssaOp_Sub32,
- ssaOp_Sub64,
- ssaOp_SubPtr,
- ssaOp_Sub32F,
- ssaOp_Sub64F,
- ssaOp_Mul8,
- ssaOp_Mul16,
- ssaOp_Mul32,
- ssaOp_Mul64,
- ssaOp_Mul32F,
- ssaOp_Mul64F,
- ssaOp_Div8,
- ssaOp_Div8U,
- ssaOp_Div16,
- ssaOp_Div16U,
- ssaOp_Div32,
- ssaOp_Div32U,
- ssaOp_Div64,
- ssaOp_Div64U,
- ssaOp_Div32F,
- ssaOp_Div64F,
- ssaOp_Mod8,
- ssaOp_Mod8U,
- ssaOp_Mod16,
- ssaOp_Mod16U,
- ssaOp_Mod32,
- ssaOp_Mod32U,
- ssaOp_Mod64,
- ssaOp_Mod64U,
-
- ssaOp_And8,
- ssaOp_And16,
- ssaOp_And32,
- ssaOp_And64,
- ssaOp_Or8,
- ssaOp_Or16,
- ssaOp_Or32,
- ssaOp_Or64,
- ssaOp_Xor8,
- ssaOp_Xor16,
- ssaOp_Xor32,
- ssaOp_Xor64,
-
- ssaOp_Lsh8x8,
- ssaOp_Lsh8x16,
- ssaOp_Lsh8x32,
- ssaOp_Lsh8x64,
- ssaOp_Lsh16x8,
- ssaOp_Lsh16x16,
- ssaOp_Lsh16x32,
- ssaOp_Lsh16x64,
- ssaOp_Lsh32x8,
- ssaOp_Lsh32x16,
- ssaOp_Lsh32x32,
- ssaOp_Lsh32x64,
- ssaOp_Lsh64x8,
- ssaOp_Lsh64x16,
- ssaOp_Lsh64x32,
- ssaOp_Lsh64x64,
- ssaOp_Rsh8x8,
- ssaOp_Rsh8x16,
- ssaOp_Rsh8x32,
- ssaOp_Rsh8x64,
- ssaOp_Rsh16x8,
- ssaOp_Rsh16x16,
- ssaOp_Rsh16x32,
- ssaOp_Rsh16x64,
- ssaOp_Rsh32x8,
- ssaOp_Rsh32x16,
- ssaOp_Rsh32x32,
- ssaOp_Rsh32x64,
- ssaOp_Rsh64x8,
- ssaOp_Rsh64x16,
- ssaOp_Rsh64x32,
- ssaOp_Rsh64x64,
- ssaOp_Rsh8Ux8,
- ssaOp_Rsh8Ux16,
- ssaOp_Rsh8Ux32,
- ssaOp_Rsh8Ux64,
- ssaOp_Rsh16Ux8,
- ssaOp_Rsh16Ux16,
- ssaOp_Rsh16Ux32,
- ssaOp_Rsh16Ux64,
- ssaOp_Rsh32Ux8,
- ssaOp_Rsh32Ux16,
- ssaOp_Rsh32Ux32,
- ssaOp_Rsh32Ux64,
- ssaOp_Rsh64Ux8,
- ssaOp_Rsh64Ux16,
- ssaOp_Rsh64Ux32,
- ssaOp_Rsh64Ux64,
-
- ssaOp_Eq8,
- ssaOp_Eq16,
- ssaOp_Eq32,
- ssaOp_Eq64,
- ssaOp_EqPtr,
- ssaOp_Eq32F,
- ssaOp_Eq64F,
- ssaOp_Ne8,
- ssaOp_Ne16,
- ssaOp_Ne32,
- ssaOp_Ne64,
- ssaOp_NePtr,
- ssaOp_Ne32F,
- ssaOp_Ne64F,
- ssaOp_Lt8,
- ssaOp_Lt16,
- ssaOp_Lt32,
- ssaOp_Lt64,
- ssaOp_LtPtr,
- ssaOp_Lt32F,
- ssaOp_Lt64F,
- ssaOp_Gt8,
- ssaOp_Gt16,
- ssaOp_Gt32,
- ssaOp_Gt64,
- ssaOp_GtPtr,
- ssaOp_Gt32F,
- ssaOp_Gt64F,
- ssaOp_Le8,
- ssaOp_Le16,
- ssaOp_Le32,
- ssaOp_Le64,
- ssaOp_LePtr,
- ssaOp_Le32F,
- ssaOp_Le64F,
- ssaOp_Ge8,
- ssaOp_Ge16,
- ssaOp_Ge32,
- ssaOp_Ge64,
- ssaOp_GePtr,
- ssaOp_Ge32F,
- ssaOp_Ge64F,
-
- ssaOp_NotB,
- ssaOp_EqB,
- ssaOp_NeB,
-
- ssaOp_Neg8,
- ssaOp_Neg16,
- ssaOp_Neg32,
- ssaOp_Neg64,
- ssaOp_Neg32F,
- ssaOp_Neg64F,
-
- ssaOp_Not8,
- ssaOp_Not16,
- ssaOp_Not32,
- ssaOp_Not64,
-
- ssaOp_SignExt8to16,
- ssaOp_SignExt8to32,
- ssaOp_SignExt8to64,
- ssaOp_SignExt16to32,
- ssaOp_SignExt16to64,
- ssaOp_SignExt32to64,
- ssaOp_ZeroExt8to16,
- ssaOp_ZeroExt8to32,
- ssaOp_ZeroExt8to64,
- ssaOp_ZeroExt16to32,
- ssaOp_ZeroExt16to64,
- ssaOp_ZeroExt32to64,
- ssaOp_Trunc16to8,
- ssaOp_Trunc32to8,
- ssaOp_Trunc32to16,
- ssaOp_Trunc64to8,
- ssaOp_Trunc64to16,
- ssaOp_Trunc64to32,
-
- ssaOp_Cvt32to32F,
- ssaOp_Cvt32to64F,
- ssaOp_Cvt64to32F,
- ssaOp_Cvt64to64F,
- ssaOp_Cvt32Fto32,
- ssaOp_Cvt32Fto64,
- ssaOp_Cvt64Fto32,
- ssaOp_Cvt64Fto64,
- ssaOp_Cvt32Fto64F,
- ssaOp_Cvt64Fto32F,
- ssaOp_Cvt32Uto32F,
- ssaOp_Cvt32Uto64F,
- ssaOp_Cvt32Fto32U,
- ssaOp_Cvt64Fto32U,
- ssaOp_Cvt64Uto32F,
- ssaOp_Cvt64Uto64F,
- ssaOp_Cvt32Fto64U,
- ssaOp_Cvt64Fto64U,
-
- ssaOp_Count,
+#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
+ SSA_OPS
+#undef SSA_OP
+};
+
+String const ssa_op_strings[] = {
+#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
+ SSA_OPS
+#undef SSA_OP
};
#define SSA_MAX_ARGS 4
@@ -295,6 +311,8 @@ struct ssaValue {
ssaValueArray var_args; // Only used in procedure calls as the SSA_MAX_ARGS may be too small
ExactValue exact_value; // Used for constants
+
+ String comment_string;
};
enum ssaBlockKind {
@@ -333,15 +351,29 @@ struct ssaBlock {
i32 id; // Unique identifier but the pointer could be used too
ssaBlockKind kind;
ssaProc * proc; // Containing procedure
+ String name; // Optional
// Likely branch direction
ssaBranchPrediction likeliness;
+ // Determines how a block exits
+ // It depends on the type of block:
+ // - BlockIf will be a boolean value
+ // - BlockExit will be a memory control value
+ ssaValue *control;
+
ssaValueArray values;
ssaEdgeArray preds;
ssaEdgeArray succs;
};
+struct ssaTargetList {
+ ssaTargetList *prev;
+ ssaBlock * break_;
+ ssaBlock * continue_;
+ ssaBlock * fallthrough_;
+};
+
struct ssaProc {
ssaModule * module; // Parent module
String name; // Mangled name
@@ -350,8 +382,11 @@ struct ssaProc {
Array(ssaBlock *) blocks;
ssaBlock * entry; // Entry block
+ ssaBlock * exit; // Exit block
ssaBlock * curr_block;
+ ssaTargetList * target_list;
+
i32 block_id;
i32 value_id;
MapSsaValue values; // Key: Entity *
@@ -385,14 +420,28 @@ struct ssaModule {
};
+void ssa_push_target_list(ssaProc *p, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) {
+ ssaTargetList *tl = gb_alloc_item(p->module->allocator, ssaTargetList);
+ tl->prev = p->target_list;
+ tl->break_ = break_;
+ tl->continue_ = continue_;
+ tl->fallthrough_ = fallthrough_;
+ p->target_list = tl;
+}
+void ssa_pop_target_list(ssaProc *p) {
+ p->target_list = p->target_list->prev;
+}
-ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind) {
+ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
ssaBlock *b = gb_alloc_item(p->module->allocator, ssaBlock);
b->id = p->block_id++;
b->kind = kind;
b->proc = p;
+ if (name != NULL || name[0] != 0) {
+ b->name = make_string_c(name);
+ }
array_init(&b->values, heap_allocator());
array_init(&b->preds, heap_allocator());
@@ -425,7 +474,11 @@ ssaBlock *ssa_end_block(ssaProc *p) {
return b;
}
-void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) {
+void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
+ if (b == NULL) {
+ return;
+ }
+ GB_ASSERT(c != NULL);
isize i = b->succs.count;
isize j = b->preds.count;
ssaEdge s = {c, j};
@@ -434,6 +487,37 @@ void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) {
array_add(&c->preds, p);
}
+void ssa_set_control(ssaBlock *b, ssaValue *v) {
+ if (b->control != NULL) {
+ b->control->uses--;
+ }
+ b->control = v;
+ if (v != NULL) {
+ v->uses++;
+ }
+}
+
+void ssa_emit_jump(ssaProc *p, ssaBlock *edge) {
+ ssa_add_edge_to(ssa_end_block(p), edge);
+}
+
+
+bool ssa_op_uses_var_args(ssaOp op) {
+ switch (op) {
+ case ssaOp_CallOdin:
+ case ssaOp_CallC:
+ case ssaOp_CallStd:
+ case ssaOp_CallFast:
+ return true;
+
+ case ssaOp_Phi:
+ return true;
+ }
+ return false;
+}
+
+
+
ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) {
ssaValue *v = gb_alloc_item(p->module->allocator, ssaValue);
@@ -504,17 +588,44 @@ ssaValue *ssa_const_val(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) {
return ssa_new_value0v(p->curr_block, op, t, exact_value);
}
-ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); }
-ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); }
-ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); }
-ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); }
-ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); }
-ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); }
-ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); }
-ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); }
-ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); }
-ssaValue *ssa_const_slice (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstSlice, t, (ExactValue){0}); }
-ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); }
+ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); }
+ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); }
+ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); }
+ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); }
+ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); }
+ssaValue *ssa_const_slice (ssaProc *p, Type *t, ExactValue v) { return ssa_const_val(p, ssaOp_ConstSlice, t, v); }
+ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); }
+
+ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
+ switch (8*type_size_of(p->module->allocator, t)) {
+ case 8: return ssa_const_i8 (p, t, cast(i8)c);
+ case 16: return ssa_const_i16(p, t, cast(i16)c);
+ case 32: return ssa_const_i32(p, t, cast(i32)c);
+ case 64: return ssa_const_i64(p, t, cast(i64)c);
+ }
+ GB_PANIC("Unknown int size");
+ return NULL;
+}
+
+void ssa_reset_value_args(ssaValue *v) {
+ if (ssa_op_uses_var_args(v->op)) {
+ for_array(i, v->var_args) {
+ v->var_args.e[i]->uses--;
+ }
+ v->var_args.count = 0;
+ } else {
+ for (isize i = 0; i < v->arg_count; i++) {
+ v->args[i]->uses--;
+ }
+ v->arg_count = 0;
+ }
+}
+
+
bool ssa_is_blank_ident(AstNode *node) {
if (node->kind == AstNode_Ident) {
@@ -527,6 +638,7 @@ bool ssa_is_blank_ident(AstNode *node) {
typedef enum ssaAddrKind {
ssaAddr_Default,
+ ssaAddr_Map,
} ssaAddrKind;
typedef struct ssaAddr {
@@ -543,6 +655,21 @@ ssaAddr ssa_addr(ssaValue *v) {
return addr;
}
+Type *ssa_addr_type(ssaAddr addr) {
+ if (addr.addr == NULL) {
+ return NULL;
+ }
+
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("TODO: ssa_addr_type");
+ return NULL;
+ }
+
+ Type *t = addr.addr->type;
+ GB_ASSERT(is_type_pointer(t));
+ return type_deref(t);
+}
+
ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) {
@@ -559,27 +686,24 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_
}
ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) {
- ssaAddr result = {0};
-
Type *t = make_type_pointer(p->module->allocator, e->type);
ssaValue *local = ssa_new_value0(p->entry, ssaOp_Local, t);
map_ssa_value_set(&p->values, hash_pointer(e), local);
map_ssa_value_set(&p->module->values, hash_pointer(e), local);
+ local->comment_string = e->token.string;
ssaValue *addr = ssa_new_value1(p->curr_block, ssaOp_Addr, local->type, local);
ssa_new_value1(p->curr_block, ssaOp_Zero, t, addr);
- result.addr = addr;
- return result;
+ return ssa_addr(addr);
}
ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
- ssaAddr result = {0};
-
Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name));
if (found) {
Entity *e = *found;
return ssa_add_local(p, e, name);
}
- return result;
+
+ return ssa_addr(NULL);
}
ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
@@ -594,12 +718,9 @@ ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
}
void ssa_emit_comment(ssaProc *p, String s) {
- ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s));
+ // ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s));
}
-
-
-
void ssa_build_stmt(ssaProc *p, AstNode *node);
void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes);
@@ -607,12 +728,312 @@ void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
if (addr.addr == NULL) {
return;
}
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("TODO(bill): ssa_addr_store");
+ return;
+ }
+
+ ssa_new_value2(p->curr_block, ssaOp_Store, addr.addr->type, addr.addr, value);
+}
+
+ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) {
+ if (addr.addr == NULL) {
+ return NULL;
+ }
+
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("here\n");
+ return NULL;
+ }
+
+ Type *t = addr.addr->type;
+ Type *bt = base_type(t);
+ if (bt->kind == Type_Proc) {
+ return addr.addr;
+ }
+
+ return ssa_new_value1(p->curr_block, ssaOp_Load, type_deref(t), addr.addr);
+}
+
+ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
+ GB_PANIC("TODO(bill): ssa_get_using_variable");
+ return NULL;
+ // GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous);
+ // String name = e->token.string;
+ // Entity *parent = e->using_parent;
+ // Selection sel = lookup_field(proc->module->allocator, parent->type, name, false);
+ // GB_ASSERT(sel.entity != NULL);
+ // irValue **pv = map_ir_value_get(&proc->module->values, hash_pointer(parent));
+ // irValue *v = NULL;
+ // if (pv != NULL) {
+ // v = *pv;
+ // } else {
+ // v = ir_build_addr(proc, e->using_expr).addr;
+ // }
+ // GB_ASSERT(v != NULL);
+ // return ir_emit_deep_field_gep(proc, parent->type, v, sel);
}
-ssaAddr ssa_build_addr(ssaProc *p, AstNode *node) {
+ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
+ GB_ASSERT(e != NULL);
+
+ ssaValue *v = NULL;
+ ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e));
+ if (found) {
+ v = *found;
+ } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
+ // NOTE(bill): Calculate the using variable every time
+ v = ssa_get_using_variable(p, e);
+ }
+
+ if (v == NULL) {
+ GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
+ }
+
+ return ssa_addr(v);
+}
+
+ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
+ switch (expr->kind) {
+ case_ast_node(i, Ident, expr);
+ if (ssa_is_blank_ident(expr)) {
+ ssaAddr val = {0};
+ return val;
+ }
+ Entity *e = entity_of_ident(p->module->info, expr);
+ return ssa_build_addr_from_entity(p, e, expr);
+ case_end;
+
+ case_ast_node(pe, ParenExpr, expr);
+ return ssa_build_addr(p, unparen_expr(expr));
+ case_end;
+ }
+
+ GB_PANIC("Cannot get entity's address");
return ssa_addr(NULL);
}
+
+Type *ssa_proper_type(Type *t) {
+ t = default_type(base_type(base_enum_type(t)));
+
+ if (t->kind == Type_Basic) {
+ switch (t->Basic.kind) {
+ case Basic_int:
+ if (build_context.word_size == 8) {
+ return t_i64;
+ }
+ return t_i32;
+ case Basic_uint:
+ if (build_context.word_size == 8) {
+ return t_u64;
+ }
+ return t_u32;
+ }
+ }
+
+ return t;
+}
+
+ssaOp ssa_determine_op(TokenKind op, Type *t) {
+ t = ssa_proper_type(t);
+ if (t->kind == Type_Basic) {
+ switch (t->Basic.kind) {
+ case Basic_bool:
+ switch (op) {
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ }
+ break;
+ case Basic_i8:
+ switch (op) {
+ case Token_Add: return ssaOp_Add8;
+ case Token_Sub: return ssaOp_Sub8;
+ case Token_Mul: return ssaOp_Mul8;
+ case Token_Quo: return ssaOp_Div8;
+ case Token_Mod: return ssaOp_Mod8;
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ case Token_Lt: return ssaOp_Lt8;
+ case Token_LtEq: return ssaOp_Le8;
+ case Token_Gt: return ssaOp_Gt8;
+ case Token_GtEq: return ssaOp_Ge8;
+ case Token_CmpEq: return ssaOp_Eq8;
+ case Token_NotEq: return ssaOp_Ne8;
+ }
+ break;
+ case Basic_u8:
+ switch (op) {
+ case Token_Add: return ssaOp_Add8;
+ case Token_Sub: return ssaOp_Sub8;
+ case Token_Mul: return ssaOp_Mul8;
+ case Token_Quo: return ssaOp_Div8U;
+ case Token_Mod: return ssaOp_Mod8U;
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ case Token_Lt: return ssaOp_Lt8;
+ case Token_LtEq: return ssaOp_Le8;
+ case Token_Gt: return ssaOp_Gt8;
+ case Token_GtEq: return ssaOp_Ge8;
+ case Token_CmpEq: return ssaOp_Eq8;
+ case Token_NotEq: return ssaOp_Ne8;
+ }
+ break;
+ case Basic_i16:
+ switch (op) {
+ case Token_Add: return ssaOp_Add16;
+ case Token_Sub: return ssaOp_Sub16;
+ case Token_Mul: return ssaOp_Mul16;
+ case Token_Quo: return ssaOp_Div16;
+ case Token_Mod: return ssaOp_Mod16;
+ case Token_And: return ssaOp_And16;
+ case Token_Or: return ssaOp_Or16;
+ case Token_Xor: return ssaOp_Xor16;
+ case Token_AndNot: return ssaOp_AndNot16;
+ case Token_Lt: return ssaOp_Lt16;
+ case Token_LtEq: return ssaOp_Le16;
+ case Token_Gt: return ssaOp_Gt16;
+ case Token_GtEq: return ssaOp_Ge16;
+ case Token_CmpEq: return ssaOp_Eq16;
+ case Token_NotEq: return ssaOp_Ne16;
+ }
+ break;
+ case Basic_u16:
+ switch (op) {
+ case Token_Add: return ssaOp_Add16;
+ case Token_Sub: return ssaOp_Sub16;
+ case Token_Mul: return ssaOp_Mul16;
+ case Token_Quo: return ssaOp_Div16U;
+ case Token_Mod: return ssaOp_Mod16U;
+ case Token_And: return ssaOp_And16;
+ case Token_Or: return ssaOp_Or16;
+ case Token_Xor: return ssaOp_Xor16;
+ case Token_AndNot: return ssaOp_AndNot16;
+ case Token_Lt: return ssaOp_Lt16;
+ case Token_LtEq: return ssaOp_Le16;
+ case Token_Gt: return ssaOp_Gt16;
+ case Token_GtEq: return ssaOp_Ge16;
+ case Token_CmpEq: return ssaOp_Eq16;
+ case Token_NotEq: return ssaOp_Ne16;
+ }
+ break;
+ case Basic_i32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32;
+ case Token_Sub: return ssaOp_Sub32;
+ case Token_Mul: return ssaOp_Mul32;
+ case Token_Quo: return ssaOp_Div32;
+ case Token_Mod: return ssaOp_Mod32;
+ case Token_And: return ssaOp_And32;
+ case Token_Or: return ssaOp_Or32;
+ case Token_Xor: return ssaOp_Xor32;
+ case Token_AndNot: return ssaOp_AndNot32;
+ case Token_Lt: return ssaOp_Lt32;
+ case Token_LtEq: return ssaOp_Le32;
+ case Token_Gt: return ssaOp_Gt32;
+ case Token_GtEq: return ssaOp_Ge32;
+ case Token_CmpEq: return ssaOp_Eq32;
+ case Token_NotEq: return ssaOp_Ne32;
+ }
+ break;
+ case Basic_u32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32;
+ case Token_Sub: return ssaOp_Sub32;
+ case Token_Mul: return ssaOp_Mul32;
+ case Token_Quo: return ssaOp_Div32U;
+ case Token_Mod: return ssaOp_Mod32U;
+ case Token_And: return ssaOp_And32;
+ case Token_Or: return ssaOp_Or32;
+ case Token_Xor: return ssaOp_Xor32;
+ case Token_AndNot: return ssaOp_AndNot32;
+ case Token_Lt: return ssaOp_Lt32;
+ case Token_LtEq: return ssaOp_Le32;
+ case Token_Gt: return ssaOp_Gt32;
+ case Token_GtEq: return ssaOp_Ge32;
+ case Token_CmpEq: return ssaOp_Eq32;
+ case Token_NotEq: return ssaOp_Ne32;
+ }
+ break;
+ case Basic_i64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64;
+ case Token_Sub: return ssaOp_Sub64;
+ case Token_Mul: return ssaOp_Mul64;
+ case Token_Quo: return ssaOp_Div64;
+ case Token_Mod: return ssaOp_Mod64;
+ case Token_And: return ssaOp_And64;
+ case Token_Or: return ssaOp_Or64;
+ case Token_Xor: return ssaOp_Xor64;
+ case Token_AndNot: return ssaOp_AndNot64;
+ case Token_Lt: return ssaOp_Lt64;
+ case Token_LtEq: return ssaOp_Le64;
+ case Token_Gt: return ssaOp_Gt64;
+ case Token_GtEq: return ssaOp_Ge64;
+ case Token_CmpEq: return ssaOp_Eq64;
+ case Token_NotEq: return ssaOp_Ne64;
+ }
+ break;
+ case Basic_u64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64;
+ case Token_Sub: return ssaOp_Sub64;
+ case Token_Mul: return ssaOp_Mul64;
+ case Token_Quo: return ssaOp_Div64U;
+ case Token_Mod: return ssaOp_Mod64U;
+ case Token_And: return ssaOp_And64;
+ case Token_Or: return ssaOp_Or64;
+ case Token_Xor: return ssaOp_Xor64;
+ case Token_AndNot: return ssaOp_AndNot64;
+ case Token_Lt: return ssaOp_Lt64;
+ case Token_LtEq: return ssaOp_Le64;
+ case Token_Gt: return ssaOp_Gt64;
+ case Token_GtEq: return ssaOp_Ge64;
+ case Token_CmpEq: return ssaOp_Eq64;
+ case Token_NotEq: return ssaOp_Ne64;
+ }
+ break;
+ case Basic_f32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32F;
+ case Token_Sub: return ssaOp_Sub32F;
+ case Token_Mul: return ssaOp_Mul32F;
+ case Token_Quo: return ssaOp_Div32F;
+ case Token_Lt: return ssaOp_Lt32F;
+ case Token_LtEq: return ssaOp_Le32F;
+ case Token_Gt: return ssaOp_Gt32F;
+ case Token_GtEq: return ssaOp_Ge32F;
+ case Token_CmpEq: return ssaOp_Eq32F;
+ case Token_NotEq: return ssaOp_Ne32F;
+ }
+ break;
+ case Basic_f64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64F;
+ case Token_Sub: return ssaOp_Sub64F;
+ case Token_Mul: return ssaOp_Mul64F;
+ case Token_Quo: return ssaOp_Div64F;
+ case Token_Lt: return ssaOp_Lt64F;
+ case Token_LtEq: return ssaOp_Le64F;
+ case Token_Gt: return ssaOp_Gt64F;
+ case Token_GtEq: return ssaOp_Ge64F;
+ case Token_CmpEq: return ssaOp_Eq64F;
+ case Token_NotEq: return ssaOp_Ne64F;
+ }
+ break;
+ }
+ }
+
+ GB_PANIC("Invalid Op for type");
+ return ssaOp_Invalid;
+}
+
ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
expr = unparen_expr(expr);
@@ -620,15 +1041,53 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
GB_ASSERT_NOT_NULL(tv);
if (tv->value.kind != ExactValue_Invalid) {
- return NULL;
- // return llir_add_module_constant(p->module, tv->type, tv->value);
+ Type *t = base_type(base_enum_type(tv->type));
+ if (is_type_boolean(t)) {
+ return ssa_const_bool(p, tv->type, tv->value.value_bool);
+ } else if (is_type_string(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_String);
+ return ssa_const_string(p, tv->type, tv->value.value_string);
+ } else if(is_type_slice(t)) {
+ return ssa_const_slice(p, tv->type, tv->value);
+ } else if (is_type_integer(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_Integer);
+
+ i64 s = 8*type_size_of(p->module->allocator, t);
+ switch (s) {
+ case 8: return ssa_const_i8 (p, tv->type, tv->value.value_integer);
+ case 16: return ssa_const_i16(p, tv->type, tv->value.value_integer);
+ case 32: return ssa_const_i32(p, tv->type, tv->value.value_integer);
+ case 64: return ssa_const_i64(p, tv->type, tv->value.value_integer);
+ default: GB_PANIC("Unknown integer size");
+ }
+ } else if (is_type_float(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_Float);
+ i64 s = 8*type_size_of(p->module->allocator, t);
+ switch (s) {
+ case 32: return ssa_const_f32(p, tv->type, tv->value.value_float);
+ case 64: return ssa_const_f64(p, tv->type, tv->value.value_float);
+ default: GB_PANIC("Unknown float size");
+ }
+ }
+ // IMPORTANT TODO(bill): Do constant record/array literals correctly
+ return ssa_const_nil(p, tv->type);
+ }
+
+ if (tv->mode == Addressing_Variable) {
+ return ssa_addr_load(p, ssa_build_addr(p, expr));
}
+
switch (expr->kind) {
case_ast_node(bl, BasicLit, expr);
GB_PANIC("Non-constant basic literal");
case_end;
+ case_ast_node(bd, BasicDirective, expr);
+ TokenPos pos = bd->token.pos;
+ GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name));
+ case_end;
+
case_ast_node(i, Ident, expr);
Entity *e = *map_entity_get(&p->module->info->uses, hash_pointer(expr));
if (e->kind == Entity_Builtin) {
@@ -648,7 +1107,103 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
if (v->op == ssaOp_Proc) {
return v;
}
- return v;
+
+ ssaAddr addr = ssa_build_addr(p, expr);
+ return ssa_addr_load(p, addr);
+ }
+ case_end;
+
+ case_ast_node(ue, UnaryExpr, expr);
+ switch (ue->op.kind) {
+ case Token_Pointer: {
+ ssaValue *ptr = ssa_build_addr(p, ue->expr).addr;
+ return ssa_new_value1(p->curr_block, ssaOp_Copy, tv->type, ptr);
+ } break;
+
+ case Token_Add:
+ return ssa_build_expr(p, ue->expr);
+
+ case Token_Not: // Boolean not
+ return ssa_new_value1(p->curr_block, ssaOp_NotB, tv->type, ssa_build_expr(p, ue->expr));
+ case Token_Xor: { // Bitwise not
+ ssaValue *x = ssa_build_expr(p, ue->expr);
+ isize bits = 8*type_size_of(p->module->allocator, x->type);
+ switch (bits) {
+ case 8: return ssa_new_value1(p->curr_block, ssaOp_Not8, tv->type, x);
+ case 16: return ssa_new_value1(p->curr_block, ssaOp_Not16, tv->type, x);
+ case 32: return ssa_new_value1(p->curr_block, ssaOp_Not32, tv->type, x);
+ case 64: return ssa_new_value1(p->curr_block, ssaOp_Not64, tv->type, x);
+ }
+ GB_PANIC("unknown integer size");
+ } break;
+
+ case Token_Sub: { // 0-x
+ ssaValue *x = ssa_build_expr(p, ue->expr);
+ isize bits = 8*type_size_of(p->module->allocator, x->type);
+ if (is_type_integer(x->type)) {
+ switch (bits) {
+ case 8: return ssa_new_value1(p->curr_block, ssaOp_Neg8, tv->type, x);
+ case 16: return ssa_new_value1(p->curr_block, ssaOp_Neg16, tv->type, x);
+ case 32: return ssa_new_value1(p->curr_block, ssaOp_Neg32, tv->type, x);
+ case 64: return ssa_new_value1(p->curr_block, ssaOp_Neg64, tv->type, x);
+ }
+ } else if (is_type_float(x->type)) {
+ switch (bits) {
+ case 32: return ssa_new_value1(p->curr_block, ssaOp_Neg32F, tv->type, x);
+ case 64: return ssa_new_value1(p->curr_block, ssaOp_Neg64F, tv->type, x);
+ }
+ }
+ GB_PANIC("unknown type for -x");
+ } break;
+ }
+ case_end;
+
+ case_ast_node(be, BinaryExpr, expr);
+ Type *type = default_type(tv->type);
+
+ switch (be->op.kind) {
+ case Token_Add:
+ case Token_Sub:
+ case Token_Mul:
+ case Token_Quo:
+ case Token_Mod:
+ case Token_And:
+ case Token_Or:
+ case Token_Xor:
+ case Token_AndNot: {
+ ssaValue *x = ssa_build_expr(p, be->left);
+ ssaValue *y = ssa_build_expr(p, be->right);
+ GB_ASSERT(x != NULL && y != NULL);
+ return ssa_new_value2(p->curr_block, ssa_determine_op(be->op.kind, x->type), tv->type, x, y);
+ }
+
+ case Token_Shl:
+ case Token_Shr: {
+ GB_PANIC("TODO: shifts");
+ return NULL;
+ }
+
+ case Token_CmpEq:
+ case Token_NotEq:
+ case Token_Lt:
+ case Token_LtEq:
+ case Token_Gt:
+ case Token_GtEq: {
+ ssaValue *x = ssa_build_expr(p, be->left);
+ ssaValue *y = ssa_build_expr(p, be->right);
+ GB_ASSERT(x != NULL && y != NULL);
+ return ssa_new_value2(p->curr_block, ssa_determine_op(be->op.kind, x->type), tv->type, x, y);
+ } break;
+
+ case Token_CmpAnd:
+ case Token_CmpOr:
+ GB_PANIC("TODO: inline && and ||");
+ return NULL;
+ // return ir_emit_logical_binary_expr(proc, expr);
+
+ default:
+ GB_PANIC("Invalid binary expression");
+ break;
}
case_end;
}
@@ -673,9 +1228,82 @@ ssaValue *ssa_emit_struct_ep(ssaProc *p, ssaValue *ptr, i32 index) {
}
+ssaValue *ssa_build_cond(ssaProc *p, AstNode *cond, ssaBlock *yes, ssaBlock *no) {
+ switch (cond->kind) {
+ case_ast_node(pe, ParenExpr, cond);
+ return ssa_build_cond(p, pe->expr, yes, no);
+ case_end;
+
+ case_ast_node(ue, UnaryExpr, cond);
+ if (ue->op.kind == Token_Not) {
+ return ssa_build_cond(p, ue->expr, no, yes);
+ }
+ case_end;
+
+ case_ast_node(be, BinaryExpr, cond);
+ if (be->op.kind == Token_CmpAnd) {
+ ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmd.and");
+ ssa_build_cond(p, be->left, block, no);
+ ssa_start_block(p, block);
+ return ssa_build_cond(p, be->right, yes, no);
+ } else if (be->op.kind == Token_CmpOr) {
+ ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmp.or");
+ ssa_build_cond(p, be->left, yes, block);
+ ssa_start_block(p, block);
+ return ssa_build_cond(p, be->right, yes, no);
+ }
+ case_end;
+ }
+
+ ssaValue *c = ssa_build_expr(p, cond);
+ ssaBlock *b = ssa_end_block(p);
+ b->kind = ssaBlock_If;
+ ssa_set_control(b, c);
+ ssa_add_edge_to(b, yes);
+ ssa_add_edge_to(b, no);
+ return c;
+}
+
+void ssa_build_when_stmt(ssaProc *p, AstNodeWhenStmt *ws) {
+ ssaValue *cond = ssa_build_expr(p, ws->cond);
+ GB_ASSERT(is_type_boolean(cond->type));
+
+ GB_ASSERT(cond->exact_value.kind == ExactValue_Bool);
+ if (cond->exact_value.value_bool) {
+ ssa_build_stmt_list(p, ws->body->BlockStmt.stmts);
+ } else if (ws->else_stmt) {
+ switch (ws->else_stmt->kind) {
+ case AstNode_BlockStmt:
+ ssa_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts);
+ break;
+ case AstNode_WhenStmt:
+ ssa_build_when_stmt(p, &ws->else_stmt->WhenStmt);
+ break;
+ default:
+ GB_PANIC("Invalid `else` statement in `when` statement");
+ break;
+ }
+ }
+}
+
+void ssa_build_assign_op(ssaProc *p, ssaAddr lhs, ssaValue *value, TokenKind op) {
+ // ssaValue *old_value = ssa_addr_load(p, lhs);
+ // Type *type = old_value->type;
+
+ // ssaValue *change = value;
+ // if (is_type_pointer(type) && is_type_integer(value->type)) {
+ // change = ssa_emit_conv(p, value, default_type(value->type));
+ // } else {
+ // change = ssa_emit_conv(p, value, type);
+ // }
+ // ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type);
+ // ssa_addr_store(p, lhs, new_value);
+}
+
+
void ssa_build_stmt(ssaProc *p, AstNode *node) {
if (p->curr_block == NULL) {
- ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain);
+ ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, "");
ssa_start_block(p, dead_block);
}
@@ -694,6 +1322,20 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
}
case_end;
+ case_ast_node(ws, WhenStmt, node);
+ ssa_build_when_stmt(p, ws);
+ case_end;
+
+ case_ast_node(s, IncDecStmt, node);
+ TokenKind op = Token_Add;
+ if (s->op.kind == Token_Dec) {
+ op = Token_Sub;
+ }
+ ssaAddr addr = ssa_build_addr(p, s->expr);
+ Type *t = ssa_addr_type(addr);
+ ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op);
+ case_end;
+
case_ast_node(vd, ValueDecl, node);
if (vd->is_var) {
ssaModule *m = p->module;
@@ -829,9 +1471,336 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
// NOTE(bill): No need to use return value
ssa_build_expr(p, es->expr);
case_end;
+
+ case_ast_node(ds, DeferStmt, node);
+ GB_PANIC("TODO: DeferStmt");
+ case_end;
+
+ case_ast_node(rs, ReturnStmt, node);
+ GB_PANIC("TODO: ReturnStmt");
+ case_end;
+
+ case_ast_node(is, IfStmt, node);
+ ssa_emit_comment(p, str_lit("IfStmt"));
+ if (is->init != NULL) {
+ ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init");
+ ssa_emit_jump(p, init);
+ ssa_start_block(p, init);
+ ssa_build_stmt(p, is->init);
+ }
+ ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
+ ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done");
+ ssaBlock *else_ = done;
+ if (is->else_stmt != NULL) {
+ else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
+ }
+ ssaBlock *b = NULL;
+
+ ssa_build_cond(p, is->cond, then, else_);
+ ssa_start_block(p, then);
+
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, is->body);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+
+ ssa_emit_jump(p, done);
+
+ if (is->else_stmt != NULL) {
+ ssa_start_block(p, else_);
+
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, is->else_stmt);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+
+ ssa_emit_jump(p, done);
+ }
+
+ ssa_start_block(p, done);
+ case_end;
+
+
+ case_ast_node(fs, ForStmt, node);
+ ssa_emit_comment(p, str_lit("ForStmt"));
+ if (fs->init != NULL) {
+ ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init");
+ ssa_emit_jump(p, init);
+ ssa_start_block(p, init);
+ ssa_build_stmt(p, fs->init);
+ }
+
+ ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body");
+ ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done");
+ ssaBlock *loop = body;
+ if (fs->cond != NULL) {
+ loop = ssa_new_block(p, ssaBlock_Plain, "for.loop");
+ }
+ ssaBlock *post = loop;
+ if (fs->post != NULL) {
+ post = ssa_new_block(p, ssaBlock_Plain, "for.post");
+ }
+
+ ssa_emit_jump(p, loop);
+ ssa_start_block(p, loop);
+
+ if (loop != body) {
+ ssa_build_cond(p, fs->cond, body, done);
+ ssa_start_block(p, body);
+ }
+
+ ssa_push_target_list(p, done, post, NULL);
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, fs->body);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+ ssa_pop_target_list(p);
+
+ ssa_emit_jump(p, post);
+
+ if (fs->post != NULL) {
+ ssa_start_block(p, post);
+ ssa_build_stmt(p, fs->post);
+ ssa_emit_jump(p, post);
+ }
+
+ ssa_start_block(p, done);
+ case_end;
+
+ case_ast_node(rs, RangeStmt, node);
+ GB_PANIC("TODO: RangeStmt");
+ case_end;
+
+ case_ast_node(rs, MatchStmt, node);
+ GB_PANIC("TODO: MatchStmt");
+ case_end;
+
+ case_ast_node(rs, TypeMatchStmt, node);
+ GB_PANIC("TODO: TypeMatchStmt");
+ case_end;
+
+ case_ast_node(bs, BranchStmt, node);
+ ssaBlock *b = NULL;
+ switch (bs->token.kind) {
+ case Token_break:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->break_;
+ }
+ break;
+ case Token_continue:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->continue_;
+ }
+ break;
+ case Token_fallthrough:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->fallthrough_;
+ }
+ break;
+ }
+ if (b != NULL) {
+ // ssa_emit_defer_stmts(p, irDeferExit_Branch, b);
+ }
+ switch (bs->token.kind) {
+ case Token_break: ssa_emit_comment(p, str_lit("break")); break;
+ case Token_continue: ssa_emit_comment(p, str_lit("continue")); break;
+ case Token_fallthrough: ssa_emit_comment(p, str_lit("fallthrough")); break;
+ }
+ ssa_emit_jump(p, b);
+ case_end;
+
+ case_ast_node(pa, PushAllocator, node);
+ GB_PANIC("TODO: PushAllocator");
+ case_end;
+ case_ast_node(pc, PushContext, node);
+ GB_PANIC("TODO: PushContext");
+ case_end;
}
}
+void ssa_print_value(gbFile *f, ssaValue *v) {
+ if (v == NULL) {
+ gb_fprintf(f, "nil");
+ }
+ gb_fprintf(f, "v%d", v->id);
+}
+
+void ssa_print_exact_value(gbFile *f, ssaValue *v) {
+ Type *t = default_type(v->type);
+ ExactValue ev = v->exact_value;
+ switch (ev.kind) {
+ case ExactValue_Bool:
+ if (ev.value_bool == false) {
+ gb_fprintf(f, " [false]");
+ } else {
+ gb_fprintf(f, " [true]");
+ }
+ break;
+ case ExactValue_Integer:
+ if (is_type_unsigned(t)) {
+ gb_fprintf(f, " [%llu]", ev.value_integer);
+ } else {
+ gb_fprintf(f, " [%lld]", ev.value_integer);
+ }
+ break;
+ case ExactValue_Float:
+ if (is_type_f32(t)) {
+ f32 fp = cast(f32)ev.value_float;
+ u32 x = *cast(u32 *)&fp;
+ gb_fprintf(f, " [0x%x]", x);
+ } else if (is_type_f64(t)) {
+ f64 fp = cast(f64)ev.value_float;
+ u64 x = *cast(u64 *)&fp;
+ gb_fprintf(f, " [0x%llx]", x);
+ } else {
+ GB_PANIC("unhandled integer");
+ }
+ break;
+ case ExactValue_String:
+ gb_fprintf(f, " [%.*s]", LIT(ev.value_string));
+ break;
+ case ExactValue_Pointer:
+ gb_fprintf(f, " [0x%llx]", ev.value_pointer);
+ break;
+ }
+}
+
+
+void ssa_print_reg_value(gbFile *f, ssaValue *v) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op]));
+
+ if (v->type != NULL) {
+ gbString type_str = type_to_string(default_type(v->type));
+ gb_fprintf(f, " %s", type_str);
+ gb_string_free(type_str);
+ }
+
+ ssa_print_exact_value(f, v);
+
+ if (ssa_op_uses_var_args(v->op)) {
+ for_array(i, v->var_args) {
+ gb_fprintf(f, " ");
+ ssa_print_value(f, v->var_args.e[i]);
+ }
+ } else {
+ for (isize i = 0; i < v->arg_count; i++) {
+ gb_fprintf(f, " ");
+ ssa_print_value(f, v->args[i]);
+ }
+ }
+
+ if (v->comment_string.len > 0) {
+ gb_fprintf(f, " ; %.*s", LIT(v->comment_string));
+ }
+
+ gb_fprintf(f, "\n");
+
+}
+
+void ssa_print_proc(gbFile *f, ssaProc *p) {
+ gbString type_str = type_to_string(p->entity->type);
+ gb_fprintf(f, "%.*s %s\n", LIT(p->name), type_str);
+ gb_string_free(type_str);
+
+ bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1);
+
+ for_array(i, p->blocks) {
+ ssaBlock *b = p->blocks.e[i];
+ gb_fprintf(f, " b%d:", b->id);
+ if (b->preds.count > 0) {
+ gb_fprintf(f, " <-");
+ for_array(j, b->preds) {
+ ssaBlock *pred = b->preds.e[j].block;
+ gb_fprintf(f, " b%d", pred->id);
+ }
+ }
+ gb_fprintf(f, "\n");
+
+ isize n = 0;
+ for_array(j, b->values) {
+ ssaValue *v = b->values.e[j];
+ if (v->op != ssaOp_Phi) {
+ continue;
+ }
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+
+ while (n < b->values.count) {
+ isize m = 0;
+ for_array(j, b->values) {
+ ssaValue *v = b->values.e[j];
+ if (printed[v->id]) {
+ continue;
+ }
+ bool skip = false;
+ if (ssa_op_uses_var_args(v->op)) {
+ for_array(k, v->var_args) {
+ ssaValue *w = v->var_args.e[k];
+ if (w != NULL && w->block == b && !printed[w->id]) {
+ skip = true;
+ break;
+ }
+ }
+ } else {
+ for (isize k = 0; k < v->arg_count; k++) {
+ ssaValue *w = v->args[k];
+ if (w != NULL && w->block == b && !printed[w->id]) {
+ skip = true;
+ break;
+ }
+ }
+ }
+
+ if (skip) {
+ break;
+ }
+
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+ if (m == n) {
+ gb_fprintf(f, "!!!!DepCycle!!!!\n");
+ for_array(k, b->values) {
+ ssaValue *v = b->values.e[k];
+ if (printed[v->id]) {
+ continue;
+ }
+
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+ }
+ }
+
+ if (b->kind == ssaBlock_Plain) {
+ GB_ASSERT(b->succs.count == 1);
+ ssaBlock *next = b->succs.e[0].block;
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "jump b%d", next->id);
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_If) {
+ GB_ASSERT(b->succs.count == 2);
+ ssaBlock *yes = b->succs.e[0].block;
+ ssaBlock *no = b->succs.e[1].block;
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "branch v%d, b%d, b%d", b->control->id, yes->id, no->id);
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_Exit) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "exit");
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_Ret) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "ret");
+ gb_fprintf(f, "\n");
+ }
+ }
+
+ gb_free(heap_allocator(), printed);
+}
+
void ssa_build_proc(ssaModule *m, ssaProc *p) {
p->module = m;
@@ -846,13 +1815,19 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
if (pl->body == NULL) {
return;
}
- p->entry = ssa_new_block(p, ssaBlock_Entry);
- p->curr_block = ssa_new_block(p, ssaBlock_Plain);
+ p->entry = ssa_new_block(p, ssaBlock_Entry, "entry");
+ ssa_start_block(p, p->entry);
ssa_build_stmt(p, pl->body);
+
+ p->exit = ssa_new_block(p, ssaBlock_Exit, "exit");
+ ssa_emit_jump(p, p->exit);
+
+ ssa_print_proc(gb_file_get_standard(gbFileStandard_Error), p);
}
+
bool ssa_generate(Parser *parser, CheckerInfo *info) {
if (global_error_collector.count != 0) {
return false;
@@ -956,8 +1931,6 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
}
if (e == entry_point) {
- gb_printf("%.*s\n", LIT(name));
-
ssaProc *p = ssa_new_proc(&m, name, e, decl);
ssa_build_proc(&m, p);
}