|  | @@ -6,7 +6,7 @@ typedef struct ssaProc     ssaProc;
 | 
	
		
			
				|  |  |  typedef struct ssaEdge     ssaEdge;
 | 
	
		
			
				|  |  |  typedef struct ssaRegister ssaRegister;
 | 
	
		
			
				|  |  |  typedef enum ssaBlockKind  ssaBlockKind;
 | 
	
		
			
				|  |  | -typedef enum ssaBranchPredicition ssaBranchPredicition;
 | 
	
		
			
				|  |  | +typedef enum ssaBranchPrediction ssaBranchPrediction;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  String ssa_mangle_name(ssaModule *m, String path, Entity *e);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -22,6 +22,8 @@ enum ssaOp {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	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)
 | 
	
	
		
			
				|  | @@ -38,6 +40,7 @@ enum ssaOp {
 | 
	
		
			
				|  |  |  	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,
 | 
	
	
		
			
				|  | @@ -309,7 +312,7 @@ enum ssaBlockKind {
 | 
	
		
			
				|  |  |  	ssaBlock_Count,
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -enum ssaBranchPredicition {
 | 
	
		
			
				|  |  | +enum ssaBranchPrediction {
 | 
	
		
			
				|  |  |  	ssaBranch_Unknown  = 0,
 | 
	
		
			
				|  |  |  	ssaBranch_Likely   = +1,
 | 
	
		
			
				|  |  |  	ssaBranch_Unlikely = -1,
 | 
	
	
		
			
				|  | @@ -332,7 +335,7 @@ struct ssaBlock {
 | 
	
		
			
				|  |  |  	ssaProc *            proc; // Containing procedure
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// Likely branch direction
 | 
	
		
			
				|  |  | -	ssaBranchPredicition likeliness;
 | 
	
		
			
				|  |  | +	ssaBranchPrediction likeliness;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	ssaValueArray values;
 | 
	
		
			
				|  |  |  	ssaEdgeArray  preds;
 | 
	
	
		
			
				|  | @@ -428,7 +431,7 @@ void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) {
 | 
	
		
			
				|  |  |  	ssaEdge s = {c, j};
 | 
	
		
			
				|  |  |  	ssaEdge p = {b, i};
 | 
	
		
			
				|  |  |  	array_add(&b->succs, s);
 | 
	
		
			
				|  |  | -	array_add(&b->preds, p);
 | 
	
		
			
				|  |  | +	array_add(&c->preds, p);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -522,6 +525,24 @@ bool ssa_is_blank_ident(AstNode *node) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +typedef enum ssaAddrKind {
 | 
	
		
			
				|  |  | +	ssaAddr_Default,
 | 
	
		
			
				|  |  | +} ssaAddrKind;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef struct ssaAddr {
 | 
	
		
			
				|  |  | +	ssaValue *  addr;
 | 
	
		
			
				|  |  | +	ssaAddrKind kind;
 | 
	
		
			
				|  |  | +} ssaAddr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +ssaAddr ssa_addr(ssaValue *v) {
 | 
	
		
			
				|  |  | +	if (v != NULL) {
 | 
	
		
			
				|  |  | +		GB_ASSERT(is_type_pointer(v->type));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	ssaAddr addr = {0};
 | 
	
		
			
				|  |  | +	addr.addr = v;
 | 
	
		
			
				|  |  | +	return addr;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) {
 | 
	
	
		
			
				|  | @@ -537,7 +558,9 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_
 | 
	
		
			
				|  |  |  	return p;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ssaValue *ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) {
 | 
	
		
			
				|  |  | +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);
 | 
	
	
		
			
				|  | @@ -545,18 +568,21 @@ ssaValue *ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	ssaValue *addr = ssa_new_value1(p->curr_block, ssaOp_Addr, local->type, local);
 | 
	
		
			
				|  |  |  	ssa_new_value1(p->curr_block, ssaOp_Zero, t, addr);
 | 
	
		
			
				|  |  | -	return addr;
 | 
	
		
			
				|  |  | +	result.addr = addr;
 | 
	
		
			
				|  |  | +	return result;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -ssaValue *ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
 | 
	
		
			
				|  |  | +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 NULL;
 | 
	
		
			
				|  |  | +	return result;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ssaValue *ssa_add_local_generated(ssaProc *p, Type *t) {
 | 
	
		
			
				|  |  | +ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
 | 
	
		
			
				|  |  |  	GB_ASSERT(t != NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	Scope *scope = NULL;
 | 
	
	
		
			
				|  | @@ -567,8 +593,9 @@ ssaValue *ssa_add_local_generated(ssaProc *p, Type *t) {
 | 
	
		
			
				|  |  |  	return ssa_add_local(p, e, NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +void ssa_emit_comment(ssaProc *p, String s) {
 | 
	
		
			
				|  |  | +	ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -576,9 +603,14 @@ ssaValue *ssa_add_local_generated(ssaProc *p, Type *t) {
 | 
	
		
			
				|  |  |  void ssa_build_stmt(ssaProc *p, AstNode *node);
 | 
	
		
			
				|  |  |  void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
 | 
	
		
			
				|  |  | +	if (addr.addr == NULL) {
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ssaValue *ssa_build_addr(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  | -	return NULL;
 | 
	
		
			
				|  |  | +ssaAddr ssa_build_addr(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  | +	return ssa_addr(NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
 | 
	
	
		
			
				|  | @@ -633,10 +665,6 @@ void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) {
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void ssa_addr_store(ssaProc *p, ssaValue *addr, ssaValue *value) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  ssaValue *ssa_emit_struct_ep(ssaProc *p, ssaValue *ptr, i32 index) {
 | 
	
		
			
				|  |  |  	GB_ASSERT(ptr->type != NULL);
 | 
	
	
		
			
				|  | @@ -659,6 +687,13 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  |  		ssa_build_stmt_list(p, bs->stmts);
 | 
	
		
			
				|  |  |  	case_end;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	case_ast_node(us, UsingStmt, node);
 | 
	
		
			
				|  |  | +		AstNode *decl = unparen_expr(us->node);
 | 
	
		
			
				|  |  | +		if (decl->kind == AstNode_ValueDecl) {
 | 
	
		
			
				|  |  | +			ssa_build_stmt(p, decl);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	case_end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	case_ast_node(vd, ValueDecl, node);
 | 
	
		
			
				|  |  |  		if (vd->is_var) {
 | 
	
		
			
				|  |  |  			ssaModule *m = p->module;
 | 
	
	
		
			
				|  | @@ -671,14 +706,14 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  |  					}
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  			} else {
 | 
	
		
			
				|  |  | -				ssaValueArray lvals = {0};
 | 
	
		
			
				|  |  | -				ssaValueArray inits = {0};
 | 
	
		
			
				|  |  | +				Array(ssaAddr) lvals = {0};
 | 
	
		
			
				|  |  | +				ssaValueArray  inits = {0};
 | 
	
		
			
				|  |  |  				array_init_reserve(&lvals, m->tmp_allocator, vd->names.count);
 | 
	
		
			
				|  |  |  				array_init_reserve(&inits, m->tmp_allocator, vd->names.count);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				for_array(i, vd->names) {
 | 
	
		
			
				|  |  |  					AstNode *name = vd->names.e[i];
 | 
	
		
			
				|  |  | -					ssaValue *lval = NULL;
 | 
	
		
			
				|  |  | +					ssaAddr lval = ssa_addr(NULL);
 | 
	
		
			
				|  |  |  					if (!ssa_is_blank_ident(name)) {
 | 
	
		
			
				|  |  |  						lval = ssa_add_local_for_ident(p, name);
 | 
	
		
			
				|  |  |  					}
 | 
	
	
		
			
				|  | @@ -688,11 +723,10 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				for_array(i, vd->values) {
 | 
	
		
			
				|  |  |  					ssaValue *init = ssa_build_expr(p, vd->values.e[i]);
 | 
	
		
			
				|  |  | -					if (init == NULL || init->type == NULL) {
 | 
	
		
			
				|  |  | -						// TODO(bill): remove this
 | 
	
		
			
				|  |  | +					if (init == NULL) { // TODO(bill): remove this
 | 
	
		
			
				|  |  |  						continue;
 | 
	
		
			
				|  |  |  					}
 | 
	
		
			
				|  |  | -					Type *t = base_type(init->type);
 | 
	
		
			
				|  |  | +					Type *t = type_deref(init->type);
 | 
	
		
			
				|  |  |  					if (init->op == ssaOp_Addr && t->kind == Type_Tuple) {
 | 
	
		
			
				|  |  |  						for (isize i = 0; i < t->Tuple.variable_count; i++) {
 | 
	
		
			
				|  |  |  							Entity *e = t->Tuple.variables[i];
 | 
	
	
		
			
				|  | @@ -704,11 +738,7 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  |  					}
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  				for_array(i, inits) {
 | 
	
		
			
				|  |  | -					if (lvals.e[i] == NULL) {
 | 
	
		
			
				|  |  | -						continue;
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  |  					ssa_addr_store(p, lvals.e[i], inits.e[i]);
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  			}
 | 
	
	
		
			
				|  | @@ -716,6 +746,89 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
 | 
	
		
			
				|  |  |  			gb_temp_arena_memory_end(tmp);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	case_end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case_ast_node(as, AssignStmt, node);
 | 
	
		
			
				|  |  | +		ssa_emit_comment(p, str_lit("AssignStmt"));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		ssaModule *m = p->module;
 | 
	
		
			
				|  |  | +		gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		switch (as->op.kind) {
 | 
	
		
			
				|  |  | +		case Token_Eq: {
 | 
	
		
			
				|  |  | +			Array(ssaAddr) lvals = {0};
 | 
	
		
			
				|  |  | +			array_init(&lvals, m->tmp_allocator);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			for_array(i, as->lhs) {
 | 
	
		
			
				|  |  | +				AstNode *lhs = as->lhs.e[i];
 | 
	
		
			
				|  |  | +				ssaAddr lval = {0};
 | 
	
		
			
				|  |  | +				if (!ssa_is_blank_ident(lhs)) {
 | 
	
		
			
				|  |  | +					lval = ssa_build_addr(p, lhs);
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				array_add(&lvals, lval);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			if (as->lhs.count == as->rhs.count) {
 | 
	
		
			
				|  |  | +				if (as->lhs.count == 1) {
 | 
	
		
			
				|  |  | +					AstNode *rhs = as->rhs.e[0];
 | 
	
		
			
				|  |  | +					ssaValue *init = ssa_build_expr(p, rhs);
 | 
	
		
			
				|  |  | +					ssa_addr_store(p, lvals.e[0], init);
 | 
	
		
			
				|  |  | +				} else {
 | 
	
		
			
				|  |  | +					ssaValueArray inits;
 | 
	
		
			
				|  |  | +					array_init_reserve(&inits, m->tmp_allocator, lvals.count);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					for_array(i, as->rhs) {
 | 
	
		
			
				|  |  | +						ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
 | 
	
		
			
				|  |  | +						array_add(&inits, init);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					for_array(i, inits) {
 | 
	
		
			
				|  |  | +						ssa_addr_store(p, lvals.e[i], inits.e[i]);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				ssaValueArray inits;
 | 
	
		
			
				|  |  | +				array_init_reserve(&inits, m->tmp_allocator, lvals.count);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				for_array(i, as->rhs) {
 | 
	
		
			
				|  |  | +					ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
 | 
	
		
			
				|  |  | +					Type *t = type_deref(init->type);
 | 
	
		
			
				|  |  | +					// TODO(bill): refactor for code reuse as this is repeated a bit
 | 
	
		
			
				|  |  | +					if (init->op == ssaOp_Addr && t->kind == Type_Tuple) {
 | 
	
		
			
				|  |  | +						for (isize i = 0; i < t->Tuple.variable_count; i++) {
 | 
	
		
			
				|  |  | +							Entity *e = t->Tuple.variables[i];
 | 
	
		
			
				|  |  | +							ssaValue *v = ssa_emit_struct_ep(p, init, i);
 | 
	
		
			
				|  |  | +							array_add(&inits, v);
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					} else {
 | 
	
		
			
				|  |  | +						array_add(&inits, init);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				for_array(i, inits) {
 | 
	
		
			
				|  |  | +					ssa_addr_store(p, lvals.e[i], inits.e[i]);
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		} break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		default: {
 | 
	
		
			
				|  |  | +			GB_PANIC("TODO(bill): assign operations");
 | 
	
		
			
				|  |  | +			// NOTE(bill): Only 1 += 1 is allowed, no tuples
 | 
	
		
			
				|  |  | +			// +=, -=, etc
 | 
	
		
			
				|  |  | +			// i32 op = cast(i32)as->op.kind;
 | 
	
		
			
				|  |  | +			// op += Token_Add - Token_AddEq; // Convert += to +
 | 
	
		
			
				|  |  | +			// ssaAddr lhs = ssa_build_addr(p, as->lhs.e[0]);
 | 
	
		
			
				|  |  | +			// ssaValue *value = ssa_build_expr(p, as->rhs.e[0]);
 | 
	
		
			
				|  |  | +			// ssa_build_assign_op(p, lhs, value, cast(TokenKind)op);
 | 
	
		
			
				|  |  | +		} break;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		gb_temp_arena_memory_end(tmp);
 | 
	
		
			
				|  |  | +	case_end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case_ast_node(es, ExprStmt, node);
 | 
	
		
			
				|  |  | +		// NOTE(bill): No need to use return value
 | 
	
		
			
				|  |  | +		ssa_build_expr(p, es->expr);
 | 
	
		
			
				|  |  | +	case_end;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |