Browse Source

Add checks for pre-existing type declarations.

gingerBill 5 years ago
parent
commit
10cde925ca
2 changed files with 606 additions and 164 deletions
  1. 604 164
      src/llvm_backend.cpp
  2. 2 0
      src/map.cpp

+ 604 - 164
src/llvm_backend.cpp

@@ -375,6 +375,8 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
 }
 }
 
 
 LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
+	Type *original_type = type;
+
 	LLVMContextRef ctx = m->ctx;
 	LLVMContextRef ctx = m->ctx;
 	i64 size = type_size_of(type); // Check size
 	i64 size = type_size_of(type); // Check size
 
 
@@ -410,7 +412,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		// Basic_complex32,
 		// Basic_complex32,
 		case Basic_complex64:
 		case Basic_complex64:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..complex64");
+				char const *name = "..complex64";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[2] = {
 				LLVMTypeRef fields[2] = {
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
@@ -420,7 +427,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			}
 			}
 		case Basic_complex128:
 		case Basic_complex128:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..complex128");
+				char const *name = "..complex128";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[2] = {
 				LLVMTypeRef fields[2] = {
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
@@ -431,7 +443,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 
 
 		case Basic_quaternion128:
 		case Basic_quaternion128:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..quaternion128");
+				char const *name = "..quaternion128";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[4] = {
 				LLVMTypeRef fields[4] = {
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
 					lb_type(m, t_f32),
@@ -443,7 +460,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			}
 			}
 		case Basic_quaternion256:
 		case Basic_quaternion256:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..quaternion256");
+				char const *name = "..quaternion256";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[4] = {
 				LLVMTypeRef fields[4] = {
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
 					lb_type(m, t_f64),
@@ -462,7 +484,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		case Basic_rawptr: return LLVMPointerType(LLVMInt8Type(), 0);
 		case Basic_rawptr: return LLVMPointerType(LLVMInt8Type(), 0);
 		case Basic_string:
 		case Basic_string:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..string");
+				char const *name = "..string";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[2] = {
 				LLVMTypeRef fields[2] = {
 					LLVMPointerType(lb_type(m, t_u8), 0),
 					LLVMPointerType(lb_type(m, t_u8), 0),
 					lb_type(m, t_int),
 					lb_type(m, t_int),
@@ -473,7 +500,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		case Basic_cstring: return LLVMPointerType(LLVMInt8Type(), 0);
 		case Basic_cstring: return LLVMPointerType(LLVMInt8Type(), 0);
 		case Basic_any:
 		case Basic_any:
 			{
 			{
-				LLVMTypeRef type = LLVMStructCreateNamed(ctx, "..any");
+				char const *name = "..any";
+				LLVMTypeRef type = LLVMGetTypeByName(m->mod, name);
+				if (type != nullptr) {
+					return type;
+				}
+				type = LLVMStructCreateNamed(ctx, name);
 				LLVMTypeRef fields[2] = {
 				LLVMTypeRef fields[2] = {
 					lb_type(m, t_rawptr),
 					lb_type(m, t_rawptr),
 					lb_type(m, t_typeid),
 					lb_type(m, t_typeid),
@@ -1333,6 +1365,14 @@ void lb_end_procedure_body(lbProcedure *p) {
 	    	lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
 	    	lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
 			LLVMBuildRetVoid(p->builder);
 			LLVMBuildRetVoid(p->builder);
 		}
 		}
+	} else {
+		if (p->curr_block->preds.count == 0) {
+		    LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
+		    if (instr == nullptr) {
+		    	// NOTE(bill): Remove dead trailing block
+		    	LLVMDeleteBasicBlock(p->curr_block->block);
+		    }
+		}
 	}
 	}
 
 
 	p->curr_block = nullptr;
 	p->curr_block = nullptr;
@@ -1425,7 +1465,7 @@ lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *f
 	// v = lb_emit_conv(p, v, t_bool);
 	// v = lb_emit_conv(p, v, t_bool);
 	v = lb_emit_conv(p, v, t_llvm_bool);
 	v = lb_emit_conv(p, v, t_llvm_bool);
 
 
-	LLVMBuildCondBr(p->builder, v.value, true_block->block, false_block->block);
+	lb_emit_if(p, v, true_block, false_block);
 
 
 	return v;
 	return v;
 }
 }
@@ -2367,6 +2407,304 @@ void lb_build_inline_range_stmt(lbProcedure *p, AstInlineRangeStmt *rs) {
 }
 }
 
 
 
 
+void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss) {
+	if (ss->init != nullptr) {
+		lb_build_stmt(p, ss->init);
+	}
+	lbValue tag = lb_const_bool(p->module, t_llvm_bool, true);
+	if (ss->tag != nullptr) {
+		tag = lb_build_expr(p, ss->tag);
+	}
+	lbBlock *done = lb_create_block(p, "switch.done"); // NOTE(bill): Append later
+
+	ast_node(body, BlockStmt, ss->body);
+
+	Array<Ast *> default_stmts = {};
+	lbBlock *default_fall = nullptr;
+	lbBlock *default_block = nullptr;
+
+	lbBlock *fall = nullptr;
+	bool append_fall = false;
+
+	isize case_count = body->stmts.count;
+	for_array(i, body->stmts) {
+		Ast *clause = body->stmts[i];
+		lbBlock *body = fall;
+
+		ast_node(cc, CaseClause, clause);
+
+		if (body == nullptr) {
+			if (cc->list.count == 0) {
+				body = lb_create_block(p, "switch.dflt.body");
+			} else {
+				body = lb_create_block(p, "switch.case.body");
+			}
+		}
+		if (append_fall && body == fall) {
+			append_fall = false;
+		}
+
+		fall = done;
+		if (i+1 < case_count) {
+			append_fall = true;
+			fall = lb_create_block(p, "switch.fall.body");
+		}
+
+		if (cc->list.count == 0) {
+			// default case
+			default_stmts = cc->stmts;
+			default_fall  = fall;
+			default_block = body;
+			continue;
+		}
+
+		lbBlock *next_cond = nullptr;
+		for_array(j, cc->list) {
+			Ast *expr = unparen_expr(cc->list[j]);
+			next_cond = lb_create_block(p, "switch.case.next");
+			lbValue cond = lb_const_bool(p->module, t_llvm_bool, false);
+			if (is_ast_range(expr)) {
+				ast_node(ie, BinaryExpr, expr);
+				TokenKind op = Token_Invalid;
+				switch (ie->op.kind) {
+				case Token_Ellipsis:  op = Token_LtEq; break;
+				case Token_RangeHalf: op = Token_Lt;   break;
+				default: GB_PANIC("Invalid interval operator"); break;
+				}
+				lbValue lhs = lb_build_expr(p, ie->left);
+				lbValue rhs = lb_build_expr(p, ie->right);
+				// TODO(bill): do short circuit here
+				lbValue cond_lhs = lb_emit_comp(p, Token_LtEq, lhs, tag);
+				lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs);
+				cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool);
+			} else {
+				if (expr->tav.mode == Addressing_Type) {
+					GB_ASSERT(is_type_typeid(tag.type));
+					lbValue e = lb_typeid(p->module, expr->tav.type);
+					e = lb_emit_conv(p, e, tag.type);
+					cond = lb_emit_comp(p, Token_CmpEq, tag, e);
+				} else {
+					cond = lb_emit_comp(p, Token_CmpEq, tag, lb_build_expr(p, expr));
+				}
+			}
+			lb_emit_if(p, cond, body, next_cond);
+			lb_start_block(p, next_cond);
+		}
+		lb_start_block(p, body);
+
+		lb_push_target_list(p, ss->label, done, nullptr, fall);
+		lb_open_scope(p);
+		lb_build_stmt_list(p, cc->stmts);
+		lb_close_scope(p, lbDeferExit_Default, body);
+		lb_pop_target_list(p);
+
+		lb_emit_jump(p, done);
+		lb_start_block(p, next_cond);
+	}
+
+	if (default_block != nullptr) {
+		lb_emit_jump(p, default_block);
+		lb_start_block(p, default_block);
+
+		lb_push_target_list(p, ss->label, done, nullptr, default_fall);
+		lb_open_scope(p);
+		lb_build_stmt_list(p, default_stmts);
+		lb_close_scope(p, lbDeferExit_Default, default_block);
+		lb_pop_target_list(p);
+	}
+
+	lb_emit_jump(p, done);
+	lb_start_block(p, done);
+}
+
+void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
+	Entity *e = implicit_entity_of_node(clause);
+	GB_ASSERT(e != nullptr);
+	lbAddr x = lb_add_local(p, e->type, e, false);
+	lb_addr_store(p, x, value);
+}
+
+void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
+	ast_node(cc, CaseClause, clause);
+
+	lb_push_target_list(p, label, done, nullptr, nullptr);
+	lb_open_scope(p);
+	lb_build_stmt_list(p, cc->stmts);
+	lb_close_scope(p, lbDeferExit_Default, body);
+	lb_pop_target_list(p);
+
+	lb_emit_jump(p, done);
+}
+
+
+
+void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
+	lbModule *m = p->module;
+
+	ast_node(as, AssignStmt, ss->tag);
+	GB_ASSERT(as->lhs.count == 1);
+	GB_ASSERT(as->rhs.count == 1);
+
+	lbValue parent = lb_build_expr(p, as->rhs[0]);
+	bool is_parent_ptr = is_type_pointer(parent.type);
+
+	TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type);
+	GB_ASSERT(switch_kind != TypeSwitch_Invalid);
+
+	lbValue parent_value = parent;
+
+	lbValue parent_ptr = parent;
+	if (!is_parent_ptr) {
+		parent_ptr = lb_address_from_load_or_generate_local(p, parent_ptr);
+	}
+
+	lbValue tag_index = {};
+	lbValue union_data = {};
+	if (switch_kind == TypeSwitch_Union) {
+		tag_index = lb_emit_load(p, lb_emit_union_tag_ptr(p, parent_ptr));
+		union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
+	}
+
+	lbBlock *start_block = lb_create_block(p, "typeswitch.case.first");
+	lb_emit_jump(p, start_block);
+	lb_start_block(p, start_block);
+
+	// NOTE(bill): Append this later
+	lbBlock *done = lb_create_block(p, "typeswitch.done");
+	Ast *default_ = nullptr;
+
+	ast_node(body, BlockStmt, ss->body);
+
+	gb_local_persist i32 weird_count = 0;
+
+	for_array(i, body->stmts) {
+		Ast *clause = body->stmts[i];
+		ast_node(cc, CaseClause, clause);
+		if (cc->list.count == 0) {
+			default_ = clause;
+			continue;
+		}
+
+		lbBlock *body = lb_create_block(p, "typeswitch.body");
+		lbBlock *next = nullptr;
+		Type *case_type = nullptr;
+		for_array(type_index, cc->list) {
+			next = lb_create_block(p, "typeswitch.next");
+			case_type = type_of_expr(cc->list[type_index]);
+			lbValue cond = {};
+			if (switch_kind == TypeSwitch_Union) {
+				Type *ut = base_type(type_deref(parent.type));
+				lbValue variant_tag = lb_const_union_tag(m, ut, case_type);
+				cond = lb_emit_comp(p, Token_CmpEq, tag_index, variant_tag);
+			} else if (switch_kind == TypeSwitch_Any) {
+				lbValue any_typeid  = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 1));
+				lbValue case_typeid = lb_typeid(m, case_type);
+				cond = lb_emit_comp(p, Token_CmpEq, any_typeid, case_typeid);
+			}
+			GB_ASSERT(cond.value != nullptr);
+
+			lb_emit_if(p, cond, body, next);
+			lb_start_block(p, next);
+		}
+
+		Entity *case_entity = implicit_entity_of_node(clause);
+
+		lbValue value = parent_value;
+
+		lb_start_block(p, body);
+
+		// bool any_or_not_ptr = is_type_any(type_deref(parent.type)) || !is_parent_ptr;
+		bool any_or_not_ptr = !is_parent_ptr;
+		if (cc->list.count == 1) {
+
+			Type *ct = case_entity->type;
+			if (any_or_not_ptr) {
+				ct = alloc_type_pointer(ct);
+			}
+			GB_ASSERT_MSG(is_type_pointer(ct), "%s", type_to_string(ct));
+			lbValue data = {};
+			if (switch_kind == TypeSwitch_Union) {
+				data = union_data;
+			} else if (switch_kind == TypeSwitch_Any) {
+				lbValue any_data = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 0));
+				data = any_data;
+			}
+			value = lb_emit_conv(p, data, ct);
+			if (any_or_not_ptr) {
+				value = lb_emit_load(p, value);
+			}
+		}
+
+		lb_store_type_case_implicit(p, clause, value);
+		lb_type_case_body(p, ss->label, clause, body, done);
+		lb_start_block(p, next);
+	}
+
+	if (default_ != nullptr) {
+		lb_store_type_case_implicit(p, default_, parent_value);
+		lb_type_case_body(p, ss->label, default_, p->curr_block, done);
+	} else {
+		lb_emit_jump(p, done);
+	}
+	lb_start_block(p, done);
+}
+
+
+lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
+	lbModule *m = p->module;
+
+	lbBlock *rhs  = lb_create_block(p, "logical.cmp.rhs");
+	lbBlock *done = lb_create_block(p, "logical.cmp.done");
+
+	type = default_type(type);
+
+	lbValue short_circuit = {};
+	if (op == Token_CmpAnd) {
+		lb_build_cond(p, left, rhs, done);
+		short_circuit = lb_const_bool(m, type, false);
+	} else if (op == Token_CmpOr) {
+		lb_build_cond(p, left, done, rhs);
+		short_circuit = lb_const_bool(m, type, true);
+	}
+
+	if (rhs->preds.count == 0) {
+		lb_start_block(p, done);
+		return short_circuit;
+	}
+
+	if (done->preds.count == 0) {
+		lb_start_block(p, rhs);
+		return lb_build_expr(p, right);
+	}
+
+	Array<LLVMValueRef> incoming_values = {};
+	Array<LLVMBasicBlockRef> incoming_blocks = {};
+	array_init(&incoming_values, heap_allocator(), done->preds.count+1);
+	array_init(&incoming_blocks, heap_allocator(), done->preds.count+1);
+
+	for_array(i, done->preds) {
+		incoming_values[i] = short_circuit.value;
+		incoming_blocks[i] = done->preds[i]->block;
+	}
+
+	lb_start_block(p, rhs);
+	lbValue edge = lb_build_expr(p, right);
+	incoming_values[done->preds.count] = edge.value;
+	incoming_blocks[done->preds.count] = rhs->block;
+
+	lb_emit_jump(p, done);
+	lb_start_block(p, done);
+
+	lbValue res = {};
+	res.type = type;
+	res.value = LLVMBuildPhi(p->builder, lb_type(m, type), "");
+
+	LLVMAddIncoming(res.value, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
+
+	return res;
+}
+
+
 void lb_build_stmt(lbProcedure *p, Ast *node) {
 void lb_build_stmt(lbProcedure *p, Ast *node) {
 	switch (node->kind) {
 	switch (node->kind) {
 	case_ast_node(bs, EmptyStmt, node);
 	case_ast_node(bs, EmptyStmt, node);
@@ -2587,11 +2925,11 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
 			op += Token_Add - Token_AddEq; // Convert += to +
 			op += Token_Add - Token_AddEq; // Convert += to +
 			if (op == Token_CmpAnd || op == Token_CmpOr) {
 			if (op == Token_CmpAnd || op == Token_CmpOr) {
 				// TODO(bill): assign op
 				// TODO(bill): assign op
-				// Type *type = as->lhs[0]->tav.type;
-				// lbValue new_value = lb_emit_logical_binary_expr(p, cast(TokenKind)op, as->lhs[0], as->rhs[0], type);
+				Type *type = as->lhs[0]->tav.type;
+				lbValue new_value = lb_emit_logical_binary_expr(p, cast(TokenKind)op, as->lhs[0], as->rhs[0], type);
 
 
-				// lbAddr lhs = lb_build_addr(p, as->lhs[0]);
-				// lb_addr_store(p, lhs, new_value);
+				lbAddr lhs = lb_build_addr(p, as->lhs[0]);
+				lb_addr_store(p, lhs, new_value);
 			} else {
 			} else {
 				// TODO(bill): Assign op
 				// TODO(bill): Assign op
 				lbAddr lhs = lb_build_addr(p, as->lhs[0]);
 				lbAddr lhs = lb_build_addr(p, as->lhs[0]);
@@ -2803,117 +3141,11 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(ss, SwitchStmt, node);
 	case_ast_node(ss, SwitchStmt, node);
-		if (ss->init != nullptr) {
-			lb_build_stmt(p, ss->init);
-		}
-		lbValue tag = lb_const_bool(p->module, t_llvm_bool, true);
-		if (ss->tag != nullptr) {
-			tag = lb_build_expr(p, ss->tag);
-		}
-		lbBlock *done = lb_create_block(p, "switch.done"); // NOTE(bill): Append later
-
-		ast_node(body, BlockStmt, ss->body);
-
-		Array<Ast *> default_stmts = {};
-		lbBlock *default_fall = nullptr;
-		lbBlock *default_block = nullptr;
-
-		lbBlock *fall = nullptr;
-		bool append_fall = false;
-
-		isize case_count = body->stmts.count;
-		for_array(i, body->stmts) {
-			Ast *clause = body->stmts[i];
-			lbBlock *body = fall;
-
-			ast_node(cc, CaseClause, clause);
-
-			if (body == nullptr) {
-				if (cc->list.count == 0) {
-					body = lb_create_block(p, "switch.dflt.body");
-				} else {
-					body = lb_create_block(p, "switch.case.body");
-				}
-			}
-			if (append_fall && body == fall) {
-				append_fall = false;
-			}
-
-			fall = done;
-			if (i+1 < case_count) {
-				append_fall = true;
-				fall = lb_create_block(p, "switch.fall.body");
-			}
-
-			if (cc->list.count == 0) {
-				// default case
-				default_stmts = cc->stmts;
-				default_fall  = fall;
-				default_block = body;
-				continue;
-			}
-
-			lbBlock *next_cond = nullptr;
-			for_array(j, cc->list) {
-				Ast *expr = unparen_expr(cc->list[j]);
-				next_cond = lb_create_block(p, "switch.case.next");
-				lbValue cond = lb_const_bool(p->module, t_llvm_bool, false);
-				if (is_ast_range(expr)) {
-					ast_node(ie, BinaryExpr, expr);
-					TokenKind op = Token_Invalid;
-					switch (ie->op.kind) {
-					case Token_Ellipsis:  op = Token_LtEq; break;
-					case Token_RangeHalf: op = Token_Lt;   break;
-					default: GB_PANIC("Invalid interval operator"); break;
-					}
-					lbValue lhs = lb_build_expr(p, ie->left);
-					lbValue rhs = lb_build_expr(p, ie->right);
-					// TODO(bill): do short circuit here
-					lbValue cond_lhs = lb_emit_comp(p, Token_LtEq, lhs, tag);
-					lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs);
-					cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool);
-				} else {
-					if (expr->tav.mode == Addressing_Type) {
-						GB_ASSERT(is_type_typeid(tag.type));
-						lbValue e = lb_typeid(p->module, expr->tav.type);
-						e = lb_emit_conv(p, e, tag.type);
-						cond = lb_emit_comp(p, Token_CmpEq, tag, e);
-					} else {
-						cond = lb_emit_comp(p, Token_CmpEq, tag, lb_build_expr(p, expr));
-					}
-				}
-				lb_emit_if(p, cond, body, next_cond);
-				lb_start_block(p, next_cond);
-			}
-			lb_start_block(p, body);
-
-			lb_push_target_list(p, ss->label, done, nullptr, fall);
-			lb_open_scope(p);
-			lb_build_stmt_list(p, cc->stmts);
-			lb_close_scope(p, lbDeferExit_Default, body);
-			lb_pop_target_list(p);
-
-			lb_emit_jump(p, done);
-			lb_start_block(p, next_cond);
-		}
-
-		if (default_block != nullptr) {
-			lb_emit_jump(p, default_block);
-			lb_start_block(p, default_block);
-
-			lb_push_target_list(p, ss->label, done, nullptr, default_fall);
-			lb_open_scope(p);
-			lb_build_stmt_list(p, default_stmts);
-			lb_close_scope(p, lbDeferExit_Default, default_block);
-			lb_pop_target_list(p);
-		}
-
-		lb_emit_jump(p, done);
-		lb_start_block(p, done);
+		lb_build_switch_stmt(p, ss);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ss, TypeSwitchStmt, node);
 	case_ast_node(ss, TypeSwitchStmt, node);
-		// TODO(bill): TypeSwitchStmt
+		lb_build_type_switch_stmt(p, ss);
 	case_end;
 	case_end;
 
 
 	case_ast_node(bs, BranchStmt, node);
 	case_ast_node(bs, BranchStmt, node);
@@ -3183,6 +3415,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
 		return lb_typeid(m, value.value_typeid, original_type);
 		return lb_typeid(m, value.value_typeid, original_type);
 	}
 	}
 
 
+	if (value.kind == ExactValue_Invalid) {
+		return lb_const_nil(m, type);
+	}
+
 	// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
 	// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
 
 
 	if (is_type_slice(type)) {
 	if (is_type_slice(type)) {
@@ -3960,11 +4196,64 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
 
 
 	case Token_CmpAnd:
 	case Token_CmpAnd:
 	case Token_CmpOr:
 	case Token_CmpOr:
-		GB_PANIC("TODO(bill): && ||");
+		return lb_emit_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type);
 		break;
 		break;
+
 	case Token_in:
 	case Token_in:
 	case Token_not_in:
 	case Token_not_in:
-		GB_PANIC("TODO(bill): in/not_in");
+		{
+			lbValue left = lb_build_expr(p, be->left);
+			Type *type = default_type(tv.type);
+			lbValue right = lb_build_expr(p, be->right);
+			Type *rt = base_type(right.type);
+			switch (rt->kind) {
+			case Type_Map:
+				{
+					GB_PANIC("map in/not_in");
+					// lbValue addr = lb_address_from_load_or_generate_local(p, right);
+					// lbValue h = lb_gen_map_header(p, addr, rt);
+					// lbValue key = ir_gen_map_key(p, left, rt->Map.key);
+
+					// auto args = array_make<lbValue>(heap_allocator(), 2);
+					// args[0] = h;
+					// args[1] = key;
+
+					// lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
+					// if (be->op.kind == Token_in) {
+					// 	return ir_emit_conv(p, ir_emit_comp(p, Token_NotEq, ptr, v_raw_nil), t_bool);
+					// } else {
+					// 	return ir_emit_conv(p, ir_emit_comp(p, Token_CmpEq, ptr, v_raw_nil), t_bool);
+					// }
+				}
+				break;
+			case Type_BitSet:
+				{
+					Type *key_type = rt->BitSet.elem;
+					GB_ASSERT(are_types_identical(left.type, key_type));
+
+					Type *it = bit_set_to_int(rt);
+					left = lb_emit_conv(p, left, it);
+
+					lbValue lower = lb_const_value(p->module, it, exact_value_i64(rt->BitSet.lower));
+					lbValue key = lb_emit_arith(p, Token_Sub, left, lower, it);
+					lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, it, 1), key, it);
+					bit = lb_emit_conv(p, bit, it);
+
+					lbValue old_value = lb_emit_transmute(p, right, it);
+					lbValue new_value = lb_emit_arith(p, Token_And, old_value, bit, it);
+
+					if (be->op.kind == Token_in) {
+						return lb_emit_conv(p, lb_emit_comp(p, Token_NotEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool);
+					} else {
+						return lb_emit_conv(p, lb_emit_comp(p, Token_CmpEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool);
+					}
+				}
+				break;
+			default:
+				GB_PANIC("Invalid 'in' type");
+			}
+			break;
+		}
 		break;
 		break;
 	default:
 	default:
 		GB_PANIC("Invalid binary expression");
 		GB_PANIC("Invalid binary expression");
@@ -4121,11 +4410,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 			// NOTE(bill): Copy the value just for type correctness
 			// NOTE(bill): Copy the value just for type correctness
 			op = LLVMBitCast;
 			op = LLVMBitCast;
 		} else if (dz > sz) {
 		} else if (dz > sz) {
-			if (is_type_unsigned(src)) {
-				op = LLVMZExt; // zero extent
-			} else {
-				op = LLVMSExt; // sign extent
-			}
+			op = is_type_unsigned(src) ? LLVMZExt : LLVMSExt; // zero extent
 		}
 		}
 
 
 		if (dz > 1 && is_type_different_to_arch_endianness(dst)) {
 		if (dz > 1 && is_type_different_to_arch_endianness(dst)) {
@@ -4147,7 +4432,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 	if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
 	if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
 		LLVMValueRef b = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), "");
 		LLVMValueRef b = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), "");
 		lbValue res = {};
 		lbValue res = {};
-		res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, t), "");
+		res.value = LLVMBuildIntCast2(p->builder, value.value, lb_type(m, t), false, "");
 		res.type = t;
 		res.type = t;
 		return res;
 		return res;
 	}
 	}
@@ -6514,71 +6799,71 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
 			right = lb_emit_conv(p, right, t_string);
 			right = lb_emit_conv(p, right, t_string);
 		}
 		}
 
 
-		char const *runtime_proc = nullptr;
+		char const *runtime_procedure = nullptr;
 		switch (op_kind) {
 		switch (op_kind) {
-		case Token_CmpEq: runtime_proc = "string_eq"; break;
-		case Token_NotEq: runtime_proc = "string_ne"; break;
-		case Token_Lt:    runtime_proc = "string_lt"; break;
-		case Token_Gt:    runtime_proc = "string_gt"; break;
-		case Token_LtEq:  runtime_proc = "string_le"; break;
-		case Token_GtEq:  runtime_proc = "string_gt"; break;
+		case Token_CmpEq: runtime_procedure = "string_eq"; break;
+		case Token_NotEq: runtime_procedure = "string_ne"; break;
+		case Token_Lt:    runtime_procedure = "string_lt"; break;
+		case Token_Gt:    runtime_procedure = "string_gt"; break;
+		case Token_LtEq:  runtime_procedure = "string_le"; break;
+		case Token_GtEq:  runtime_procedure = "string_gt"; break;
 		}
 		}
-		GB_ASSERT(runtime_proc != nullptr);
+		GB_ASSERT(runtime_procedure != nullptr);
 
 
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		args[0] = left;
 		args[0] = left;
 		args[1] = right;
 		args[1] = right;
-		return lb_emit_runtime_call(p, runtime_proc, args);
+		return lb_emit_runtime_call(p, runtime_procedure, args);
 	}
 	}
 
 
 	if (is_type_complex(a)) {
 	if (is_type_complex(a)) {
-		char const *runtime_proc = "";
+		char const *runtime_procedure = "";
 		i64 sz = 8*type_size_of(a);
 		i64 sz = 8*type_size_of(a);
 		switch (sz) {
 		switch (sz) {
 		case 64:
 		case 64:
 			switch (op_kind) {
 			switch (op_kind) {
-			case Token_CmpEq: runtime_proc = "complex64_eq"; break;
-			case Token_NotEq: runtime_proc = "complex64_ne"; break;
+			case Token_CmpEq: runtime_procedure = "complex64_eq"; break;
+			case Token_NotEq: runtime_procedure = "complex64_ne"; break;
 			}
 			}
 			break;
 			break;
 		case 128:
 		case 128:
 			switch (op_kind) {
 			switch (op_kind) {
-			case Token_CmpEq: runtime_proc = "complex128_eq"; break;
-			case Token_NotEq: runtime_proc = "complex128_ne"; break;
+			case Token_CmpEq: runtime_procedure = "complex128_eq"; break;
+			case Token_NotEq: runtime_procedure = "complex128_ne"; break;
 			}
 			}
 			break;
 			break;
 		}
 		}
-		GB_ASSERT(runtime_proc != nullptr);
+		GB_ASSERT(runtime_procedure != nullptr);
 
 
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		args[0] = left;
 		args[0] = left;
 		args[1] = right;
 		args[1] = right;
-		return lb_emit_runtime_call(p, runtime_proc, args);
+		return lb_emit_runtime_call(p, runtime_procedure, args);
 	}
 	}
 
 
 	if (is_type_quaternion(a)) {
 	if (is_type_quaternion(a)) {
-		char const *runtime_proc = "";
+		char const *runtime_procedure = "";
 		i64 sz = 8*type_size_of(a);
 		i64 sz = 8*type_size_of(a);
 		switch (sz) {
 		switch (sz) {
 		case 128:
 		case 128:
 			switch (op_kind) {
 			switch (op_kind) {
-			case Token_CmpEq: runtime_proc = "quaternion128_eq"; break;
-			case Token_NotEq: runtime_proc = "quaternion128_ne"; break;
+			case Token_CmpEq: runtime_procedure = "quaternion128_eq"; break;
+			case Token_NotEq: runtime_procedure = "quaternion128_ne"; break;
 			}
 			}
 			break;
 			break;
 		case 256:
 		case 256:
 			switch (op_kind) {
 			switch (op_kind) {
-			case Token_CmpEq: runtime_proc = "quaternion256_eq"; break;
-			case Token_NotEq: runtime_proc = "quaternion256_ne"; break;
+			case Token_CmpEq: runtime_procedure = "quaternion256_eq"; break;
+			case Token_NotEq: runtime_procedure = "quaternion256_ne"; break;
 			}
 			}
 			break;
 			break;
 		}
 		}
-		GB_ASSERT(runtime_proc != nullptr);
+		GB_ASSERT(runtime_procedure != nullptr);
 
 
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		auto args = array_make<lbValue>(heap_allocator(), 2);
 		args[0] = left;
 		args[0] = left;
 		args[1] = right;
 		args[1] = right;
-		return lb_emit_runtime_call(p, runtime_proc, args);
+		return lb_emit_runtime_call(p, runtime_procedure, args);
 	}
 	}
 
 
 	if (is_type_bit_set(a)) {
 	if (is_type_bit_set(a)) {
@@ -6664,6 +6949,17 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
 		case Token_NotEq: pred = LLVMRealONE; break;
 		case Token_NotEq: pred = LLVMRealONE; break;
 		}
 		}
 		res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, "");
 		res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, "");
+	} else if (is_type_typeid(left.type)) {
+		LLVMIntPredicate pred = {};
+		switch (op_kind) {
+		case Token_Gt:   pred = LLVMIntUGT; break;
+		case Token_GtEq: pred = LLVMIntUGE; break;
+		case Token_Lt:   pred = LLVMIntULT; break;
+		case Token_LtEq: pred = LLVMIntULE; break;
+		case Token_CmpEq: pred = LLVMIntEQ;  break;
+		case Token_NotEq: pred = LLVMIntNE;  break;
+		}
+		res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, "");
 	} else {
 	} else {
 		GB_PANIC("Unhandled comparison kind %s %.*s %s", type_to_string(left.type), LIT(token_strings[op_kind]), type_to_string(right.type));
 		GB_PANIC("Unhandled comparison kind %s %.*s %s", type_to_string(left.type), LIT(token_strings[op_kind]), type_to_string(right.type));
 	}
 	}
@@ -6712,6 +7008,156 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
 	return value;
 	return value;
 }
 }
 
 
+lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos, bool do_conversion_check=true) {
+	lbModule *m = p->module;
+
+	Type *src_type = value.type;
+	bool is_ptr = is_type_pointer(src_type);
+
+	bool is_tuple = true;
+	Type *tuple = type;
+	if (type->kind != Type_Tuple) {
+		is_tuple = false;
+		tuple = make_optional_ok_type(type);
+	}
+
+	lbAddr v = lb_add_local_generated(p, tuple, true);
+
+	if (is_ptr) {
+		value = lb_emit_load(p, value);
+	}
+	Type *src = base_type(type_deref(src_type));
+	GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type));
+	Type *dst = tuple->Tuple.variables[0]->type;
+
+	lbValue value_  = lb_address_from_load_or_generate_local(p, value);
+
+	lbValue tag = {};
+	lbValue dst_tag = {};
+	lbValue cond = {};
+	lbValue data = {};
+
+	lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0);
+	lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1);
+
+	if (is_type_union_maybe_pointer(src)) {
+		data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type));
+	} else {
+		tag     = lb_emit_load(p, lb_emit_union_tag_ptr(p, value_));
+		dst_tag = lb_const_union_tag(m, src, dst);
+	}
+
+	lbBlock *ok_block = lb_create_block(p, "union_cast.ok");
+	lbBlock *end_block = lb_create_block(p, "union_cast.end");
+
+	if (data.value != nullptr) {
+		GB_ASSERT(is_type_union_maybe_pointer(src));
+		cond = lb_emit_comp_against_nil(p, Token_NotEq, data);
+	} else {
+		cond = lb_emit_comp(p, Token_CmpEq, tag, dst_tag);
+	}
+
+	lb_emit_if(p, cond, ok_block, end_block);
+	lb_start_block(p, ok_block);
+
+
+
+	if (data.value == nullptr) {
+		data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type));
+	}
+	lb_emit_store(p, gep0, data);
+	lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true));
+
+	lb_emit_jump(p, end_block);
+	lb_start_block(p, end_block);
+
+	if (!is_tuple) {
+		if (do_conversion_check) {
+			// NOTE(bill): Panic on invalid conversion
+			Type *dst_type = tuple->Tuple.variables[0]->type;
+
+			lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
+			auto args = array_make<lbValue>(heap_allocator(), 6);
+			args[0] = ok;
+
+			args[1] = lb_const_string(m, pos.file);
+			args[2] = lb_const_int(m, t_int, pos.line);
+			args[3] = lb_const_int(m, t_int, pos.column);
+
+			args[4] = lb_typeid(m, src_type);
+			args[5] = lb_typeid(m, dst_type);
+			lb_emit_runtime_call(p, "type_assertion_check", args);
+		}
+
+		return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
+	}
+	return lb_addr_load(p, v);
+}
+
+lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
+	lbModule *m = p->module;
+
+	Type *src_type = value.type;
+
+	if (is_type_pointer(src_type)) {
+		value = lb_emit_load(p, value);
+	}
+
+	bool is_tuple = true;
+	Type *tuple = type;
+	if (type->kind != Type_Tuple) {
+		is_tuple = false;
+		tuple = make_optional_ok_type(type);
+	}
+	Type *dst_type = tuple->Tuple.variables[0]->type;
+
+	lbAddr v = lb_add_local_generated(p, tuple, true);
+
+	lbValue dst_typeid = lb_typeid(m, dst_type);
+	lbValue any_typeid = lb_emit_struct_ev(p, value, 1);
+
+
+	lbBlock *ok_block = lb_create_block(p, "any_cast.ok");
+	lbBlock *end_block = lb_create_block(p, "any_cast.end");
+	lbValue cond = lb_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid);
+	lb_emit_if(p, cond, ok_block, end_block);
+	lb_start_block(p, ok_block);
+
+	lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0);
+	lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1);
+
+	lbValue any_data = lb_emit_struct_ev(p, value, 0);
+	lbValue ptr = lb_emit_conv(p, any_data, alloc_type_pointer(dst_type));
+	lb_emit_store(p, gep0, lb_emit_load(p, ptr));
+	lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true));
+
+	lb_emit_jump(p, end_block);
+	lb_start_block(p, end_block);
+
+	if (!is_tuple) {
+		// NOTE(bill): Panic on invalid conversion
+
+		lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
+		auto args = array_make<lbValue>(heap_allocator(), 6);
+		args[0] = ok;
+
+		args[1] = lb_const_string(m, pos.file);
+		args[2] = lb_const_int(m, t_int, pos.line);
+		args[3] = lb_const_int(m, t_int, pos.column);
+
+		args[4] = any_typeid;
+		args[5] = dst_typeid;
+		lb_emit_runtime_call(p, "type_assertion_check", args);
+
+		return lb_addr(lb_emit_struct_ep(p, v.addr, 0));
+	}
+	return v;
+}
+lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
+	return lb_addr_load(p, lb_emit_any_cast_addr(p, value, type, pos));
+}
+
+
 lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 	lbModule *m = p->module;
 	lbModule *m = p->module;
 
 
@@ -6852,11 +7298,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		lbValue e = lb_build_expr(p, ta->expr);
 		lbValue e = lb_build_expr(p, ta->expr);
 		Type *t = type_deref(e.type);
 		Type *t = type_deref(e.type);
 		if (is_type_union(t)) {
 		if (is_type_union(t)) {
-			GB_PANIC("cast - union_cast");
-			// return lb_emit_union_cast(p, e, type, pos);
+			return lb_emit_union_cast(p, e, type, pos);
 		} else if (is_type_any(t)) {
 		} else if (is_type_any(t)) {
-			GB_PANIC("cast - any_cast");
-			// return lb_emit_any_cast(p, e, type, pos);
+			return lb_emit_any_cast(p, e, type, pos);
 		} else {
 		} else {
 			GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type));
 			GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type));
 		}
 		}
@@ -7172,28 +7616,24 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 		}
 		}
 	case_end;
 	case_end;
 
 
-#if 0
 	case_ast_node(ta, TypeAssertion, expr);
 	case_ast_node(ta, TypeAssertion, expr);
 		gbAllocator a = heap_allocator();
 		gbAllocator a = heap_allocator();
 		TokenPos pos = ast_token(expr).pos;
 		TokenPos pos = ast_token(expr).pos;
 		lbValue e = lb_build_expr(p, ta->expr);
 		lbValue e = lb_build_expr(p, ta->expr);
-		Type *t = type_deref(ir_type(e));
+		Type *t = type_deref(e.type);
 		if (is_type_union(t)) {
 		if (is_type_union(t)) {
 			Type *type = type_of_expr(expr);
 			Type *type = type_of_expr(expr);
-			lbValue v = lb_add_local_generated(p, type, false);
-			ir_emit_comment(p, str_lit("cast - union_cast"));
-			lb_emit_store(p, v, ir_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos));
-			return ir_addr(v);
+			lbAddr v = lb_add_local_generated(p, type, false);
+			lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos));
+			return v;
 		} else if (is_type_any(t)) {
 		} else if (is_type_any(t)) {
-			ir_emit_comment(p, str_lit("cast - any_cast"));
 			Type *type = type_of_expr(expr);
 			Type *type = type_of_expr(expr);
-			return ir_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos);
+			return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos);
 		} else {
 		} else {
-			GB_PANIC("TODO(bill): type assertion %s", type_to_string(ir_type(e)));
+			GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type));
 		}
 		}
 	case_end;
 	case_end;
 
 
-#endif
 	case_ast_node(ue, UnaryExpr, expr);
 	case_ast_node(ue, UnaryExpr, expr);
 		switch (ue->op.kind) {
 		switch (ue->op.kind) {
 		case Token_And: {
 		case Token_And: {

+ 2 - 0
src/map.cpp

@@ -55,12 +55,14 @@ gb_inline HashKey hash_string(String s) {
 gb_inline HashKey hash_pointer(void *ptr) {
 gb_inline HashKey hash_pointer(void *ptr) {
 	HashKey h = {HashKey_Ptr};
 	HashKey h = {HashKey_Ptr};
 	h.key = cast(u64)cast(uintptr)ptr;
 	h.key = cast(u64)cast(uintptr)ptr;
+	// h.key = gb_fnv64a(&ptr, gb_size_of(void *));
 	h.ptr = ptr;
 	h.ptr = ptr;
 	return h;
 	return h;
 }
 }
 gb_inline HashKey hash_ptr_and_id(void *ptr, u64 id) {
 gb_inline HashKey hash_ptr_and_id(void *ptr, u64 id) {
 	HashKey h = {HashKey_PtrAndId};
 	HashKey h = {HashKey_PtrAndId};
 	h.key = cast(u64)cast(uintptr)ptr;
 	h.key = cast(u64)cast(uintptr)ptr;
+	// h.key = gb_fnv64a(&ptr, gb_size_of(void *));
 	h.ptr_and_id.ptr = ptr;
 	h.ptr_and_id.ptr = ptr;
 	h.ptr_and_id.id  = id;
 	h.ptr_and_id.id  = id;
 	return h;
 	return h;