From 9b61adb97dd78e1cf04ad410e72166f684f97925 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 12:03:40 +0100 Subject: Build as C++ --- src/ir.cpp | 7952 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 7952 insertions(+) create mode 100644 src/ir.cpp (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp new file mode 100644 index 000000000..5c665bfa8 --- /dev/null +++ b/src/ir.cpp @@ -0,0 +1,7952 @@ +typedef struct irProcedure irProcedure; +typedef struct irBlock irBlock; +typedef struct irValue irValue; +typedef struct irDebugInfo irDebugInfo; + +typedef Array(irValue *) irValueArray; + +#define MAP_TYPE irValue * +#define MAP_PROC map_ir_value_ +#define MAP_NAME MapIrValue +#include "map.cpp" + +#define MAP_TYPE irDebugInfo * +#define MAP_PROC map_ir_debug_info_ +#define MAP_NAME MapIrDebugInfo +#include "map.cpp" + + +typedef struct irModule { + CheckerInfo * info; + gbArena arena; + gbArena tmp_arena; + gbAllocator allocator; + gbAllocator tmp_allocator; + // bool generate_debug_info; + + u32 stmt_state_flags; + + // String source_filename; + String layout; + // String triple; + + MapEntity min_dep_map; // Key: Entity * + MapIrValue values; // Key: Entity * + MapIrValue members; // Key: String + MapString entity_names; // Key: Entity * of the typename + MapIrDebugInfo debug_info; // Key: Unique pointer + i32 global_string_index; + i32 global_array_index; // For ConstantSlice + i32 global_generated_index; + + Entity * entry_point_entity; + + Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies + irValueArray procs_to_generate; // NOTE(bill): Procedures to generate + + Array(String) foreign_library_paths; // Only the ones that were used +} irModule; + +// NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory) +typedef struct irDomNode { + irBlock * idom; // Parent (Immediate Dominator) + Array(irBlock *) children; + i32 pre, post; // Ordering in tree +} irDomNode; + + +typedef struct irBlock { + i32 index; + String label; + irProcedure *parent; + AstNode * node; // Can be NULL + Scope * scope; + isize scope_index; + irDomNode dom; + i32 gaps; + + irValueArray instrs; + irValueArray locals; + + Array(irBlock *) preds; + Array(irBlock *) succs; +} irBlock; + +typedef struct irTargetList irTargetList; +struct irTargetList { + irTargetList *prev; + irBlock * break_; + irBlock * continue_; + irBlock * fallthrough_; +}; + +typedef enum irDeferExitKind { + irDeferExit_Default, + irDeferExit_Return, + irDeferExit_Branch, +} irDeferExitKind; +typedef enum irDeferKind { + irDefer_Node, + irDefer_Instr, +} irDeferKind; + +typedef struct irDefer { + irDeferKind kind; + isize scope_index; + irBlock * block; + union { + AstNode *stmt; + // NOTE(bill): `instr` will be copied every time to create a new one + irValue *instr; + }; +} irDefer; + + +typedef struct irBranchBlocks { + AstNode *label; + irBlock *break_; + irBlock *continue_; +} irBranchBlocks; + + +struct irProcedure { + irProcedure * parent; + Array(irProcedure *) children; + + Entity * entity; + irModule * module; + String name; + Type * type; + AstNode * type_expr; + AstNode * body; + u64 tags; + + irValue * return_ptr; + irValueArray params; + Array(irDefer) defer_stmts; + Array(irBlock *) blocks; + i32 scope_index; + irBlock * decl_block; + irBlock * entry_block; + irBlock * curr_block; + irTargetList * target_list; + irValueArray referrers; + + Array(irBranchBlocks) branch_blocks; + + i32 local_count; + i32 instr_count; + i32 block_count; +}; + +#define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" +#define IR_TYPE_INFO_DATA_NAME "__$type_info_data" +#define IR_TYPE_INFO_TYPES_NAME "__$type_info_types_data" +#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data" +#define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" +#define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" + + +#define IR_INSTR_KINDS \ + IR_INSTR_KIND(Comment, struct { String text; }) \ + IR_INSTR_KIND(Local, struct { \ + Entity * entity; \ + Type * type; \ + bool zero_initialized; \ + irValueArray referrers; \ + i64 alignment; \ + }) \ + IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \ + IR_INSTR_KIND(Store, struct { \ + irValue *address, *value; bool atomic; \ + }) \ + IR_INSTR_KIND(Load, struct { Type *type; irValue *address; }) \ + IR_INSTR_KIND(PtrOffset, struct { \ + irValue *address; \ + irValue *offset; \ + }) \ + IR_INSTR_KIND(ArrayElementPtr, struct { \ + irValue *address; \ + Type * result_type; \ + irValue *elem_index; \ + }) \ + IR_INSTR_KIND(StructElementPtr, struct { \ + irValue *address; \ + Type * result_type; \ + i32 elem_index; \ + }) \ + IR_INSTR_KIND(StructExtractValue, struct { \ + irValue *address; \ + Type * result_type; \ + i32 index; \ + }) \ + IR_INSTR_KIND(UnionTagPtr, struct { \ + irValue *address; \ + Type *type; /* ^int */ \ + }) \ + IR_INSTR_KIND(UnionTagValue, struct { \ + irValue *address; \ + Type *type; /* int */ \ + }) \ + IR_INSTR_KIND(Conv, struct { \ + irConvKind kind; \ + irValue *value; \ + Type *from, *to; \ + }) \ + IR_INSTR_KIND(Jump, struct { irBlock *block; }) \ + IR_INSTR_KIND(If, struct { \ + irValue *cond; \ + irBlock *true_block; \ + irBlock *false_block; \ + }) \ + IR_INSTR_KIND(Return, struct { irValue *value; }) \ + IR_INSTR_KIND(Select, struct { \ + irValue *cond; \ + irValue *true_value; \ + irValue *false_value; \ + }) \ + IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \ + IR_INSTR_KIND(Unreachable, i32) \ + IR_INSTR_KIND(UnaryOp, struct { \ + Type * type; \ + TokenKind op; \ + irValue * expr; \ + }) \ + IR_INSTR_KIND(BinaryOp, struct { \ + Type * type; \ + TokenKind op; \ + irValue * left, *right; \ + }) \ + IR_INSTR_KIND(Call, struct { \ + Type * type; /* return type */ \ + irValue * value; \ + irValue * return_ptr; \ + irValue **args; \ + isize arg_count; \ + }) \ + IR_INSTR_KIND(StartupRuntime, i32) \ + IR_INSTR_KIND(BoundsCheck, struct { \ + TokenPos pos; \ + irValue *index; \ + irValue *len; \ + }) \ + IR_INSTR_KIND(SliceBoundsCheck, struct { \ + TokenPos pos; \ + irValue *low; \ + irValue *high; \ + irValue *max; \ + bool is_substring; \ + }) \ + IR_INSTR_KIND(DebugDeclare, struct { \ + irDebugInfo *debug_info; \ + AstNode * expr; \ + Entity * entity; \ + bool is_addr; \ + irValue * value; \ + }) \ + + + +#define IR_CONV_KINDS \ + IR_CONV_KIND(trunc) \ + IR_CONV_KIND(zext) \ + IR_CONV_KIND(sext) \ + IR_CONV_KIND(fptrunc) \ + IR_CONV_KIND(fpext) \ + IR_CONV_KIND(fptoui) \ + IR_CONV_KIND(fptosi) \ + IR_CONV_KIND(uitofp) \ + IR_CONV_KIND(sitofp) \ + IR_CONV_KIND(ptrtoint) \ + IR_CONV_KIND(inttoptr) \ + IR_CONV_KIND(bitcast) + +typedef enum irInstrKind { + irInstr_Invalid, +#define IR_INSTR_KIND(x, ...) GB_JOIN2(irInstr_, x), + IR_INSTR_KINDS +#undef IR_INSTR_KIND +} irInstrKind; + +String const ir_instr_strings[] = { + {cast(u8 *)"Invalid", gb_size_of("Invalid")-1}, +#define IR_INSTR_KIND(x, ...) {cast(u8 *)#x, gb_size_of(#x)-1}, + IR_INSTR_KINDS +#undef IR_INSTR_KIND +}; + +typedef enum irConvKind { + irConv_Invalid, +#define IR_CONV_KIND(x) GB_JOIN2(irConv_, x), + IR_CONV_KINDS +#undef IR_CONV_KIND +} irConvKind; + +String const ir_conv_strings[] = { + {cast(u8 *)"Invalid", gb_size_of("Invalid")-1}, +#define IR_CONV_KIND(x) {cast(u8 *)#x, gb_size_of(#x)-1}, + IR_CONV_KINDS +#undef IR_CONV_KIND +}; + +#define IR_INSTR_KIND(k, ...) typedef __VA_ARGS__ GB_JOIN2(irInstr, k); + IR_INSTR_KINDS +#undef IR_INSTR_KIND + +typedef struct irInstr irInstr; +struct irInstr { + irInstrKind kind; + + irBlock *parent; + Type *type; + + union { +#define IR_INSTR_KIND(k, ...) GB_JOIN2(irInstr, k) k; + IR_INSTR_KINDS +#undef IR_INSTR_KIND + }; +}; + + +typedef enum irValueKind { + irValue_Invalid, + + irValue_Constant, + irValue_ConstantSlice, + irValue_Nil, + irValue_TypeName, + irValue_Global, + irValue_Param, + + irValue_Proc, + irValue_Block, + irValue_Instr, + + irValue_Count, +} irValueKind; + +typedef struct irValueConstant { + Type * type; + ExactValue value; +} irValueConstant; + +typedef struct irValueConstantSlice { + Type * type; + irValue *backing_array; + i64 count; +} irValueConstantSlice; + +typedef struct irValueNil { + Type *type; +} irValueNil; + +typedef struct irValueTypeName { + Type * type; + String name; +} irValueTypeName; + +typedef struct irValueGlobal { + String name; + Entity * entity; + Type * type; + irValue * value; + irValueArray referrers; + bool is_constant; + bool is_private; + bool is_thread_local; + bool is_foreign; + bool is_unnamed_addr; +} irValueGlobal; + + +typedef enum irParamPasskind { + irParamPass_Value, // Pass by value + irParamPass_Pointer, // Pass as a pointer rather than by value + irParamPass_Integer, // Pass as an integer of the same size +} irParamPasskind; + +typedef struct irValueParam { + irParamPasskind kind; + irProcedure * parent; + Entity * entity; + Type * type; + Type * original_type; + irValueArray referrers; +} irValueParam; + +typedef struct irValue { + irValueKind kind; + i32 index; + bool index_set; + union { + irValueConstant Constant; + irValueConstantSlice ConstantSlice; + irValueNil Nil; + irValueTypeName TypeName; + irValueGlobal Global; + irValueParam Param; + irProcedure Proc; + irBlock Block; + irInstr Instr; + }; +} irValue; + +gb_global irValue *v_zero = NULL; +gb_global irValue *v_one = NULL; +gb_global irValue *v_zero32 = NULL; +gb_global irValue *v_one32 = NULL; +gb_global irValue *v_two32 = NULL; +gb_global irValue *v_false = NULL; +gb_global irValue *v_true = NULL; +gb_global irValue *v_raw_nil = NULL; + +typedef enum irAddrKind { + irAddr_Default, + // irAddr_Vector, + irAddr_Map, + irAddr_BitField, +} irAddrKind; + +typedef struct irAddr { + irAddrKind kind; + irValue * addr; + union { + struct { + irValue *map_key; + Type * map_type; + Type * map_result; + }; + struct { + i32 bit_field_value_index; + }; + }; + // union { + // struct { irValue *index; } Vector; + // }; +} irAddr; + +irAddr ir_addr(irValue *addr) { + irAddr v = {irAddr_Default, addr}; + return v; +} + +irAddr ir_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) { + irAddr v = {irAddr_Map, addr}; + v.map_key = map_key; + v.map_type = map_type; + v.map_result = map_result; + return v; +} + +irAddr ir_addr_bit_field(irValue *addr, isize bit_field_value_index) { + irAddr v = {irAddr_BitField, addr}; + v.bit_field_value_index = bit_field_value_index; + return v; +} + +typedef enum irDebugEncoding { + irDebugBasicEncoding_Invalid = 0, + + irDebugBasicEncoding_address = 1, + irDebugBasicEncoding_boolean = 2, + irDebugBasicEncoding_float = 3, + irDebugBasicEncoding_signed = 4, + irDebugBasicEncoding_signed_char = 5, + irDebugBasicEncoding_unsigned = 6, + irDebugBasicEncoding_unsigned_char = 7, + + irDebugBasicEncoding_member = 13, + irDebugBasicEncoding_pointer_type = 15, + irDebugBasicEncoding_typedef = 22, + + irDebugBasicEncoding_array_type = 1, + irDebugBasicEncoding_enumeration_type = 4, + irDebugBasicEncoding_structure_type = 19, + irDebugBasicEncoding_union_type = 23, + +} irDebugEncoding; + +typedef enum irDebugInfoKind { + irDebugInfo_Invalid, + + irDebugInfo_CompileUnit, + irDebugInfo_File, + irDebugInfo_Scope, + irDebugInfo_Proc, + irDebugInfo_AllProcs, + + irDebugInfo_BasicType, // basic types + irDebugInfo_ProcType, + irDebugInfo_DerivedType, // pointer, typedef + irDebugInfo_CompositeType, // array, struct, enum, (raw_)union + irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum + irDebugInfo_GlobalVariable, + irDebugInfo_LocalVariable, + + + irDebugInfo_Count, +} irDebugInfoKind; + +typedef struct irDebugInfo irDebugInfo; +struct irDebugInfo { + irDebugInfoKind kind; + i32 id; + + union { + struct { + AstFile * file; + String producer; + irDebugInfo *all_procs; + } CompileUnit; + struct { + AstFile *file; + String filename; + String directory; + } File; + struct { + irDebugInfo *parent; + irDebugInfo *file; + TokenPos pos; + Scope * scope; // Actual scope + } Scope; + struct { + Entity * entity; + String name; + irDebugInfo *file; + TokenPos pos; + } Proc; + struct { + Array(irDebugInfo *) procs; + } AllProcs; + + + struct { + String name; + i32 size; + i32 align; + irDebugEncoding encoding; + } BasicType; + struct { + irDebugInfo * return_type; + Array(irDebugInfo *) param_types; + } ProcType; + struct { + irDebugInfo * base_type; + irDebugEncoding encoding; + } DerivedType; + struct { + irDebugEncoding encoding; + String name; + String identifier; + irDebugInfo * file; + TokenPos pos; + i32 size; + i32 align; + Array(irDebugInfo *) elements; + } CompositeType; + struct { + String name; + i64 value; + } Enumerator; + struct { + String name; + String linkage_name; + irDebugInfo *scope; + irDebugInfo *file; + TokenPos pos; + irValue *variable; + irDebugInfo *declaration; + } GlobalVariable; + struct { + String name; + irDebugInfo *scope; + irDebugInfo *file; + TokenPos pos; + i32 arg; // Non-zero if proc parameter + irDebugInfo *type; + } LocalVariable; + }; +}; + + + +typedef struct irGen { + irModule module; + gbFile output_file; + bool opt_called; + String output_base; + String output_name; +} irGen; + + + + + + +Type *ir_type(irValue *value); +Type *ir_instr_type(irInstr *instr) { + switch (instr->kind) { + case irInstr_Local: + return instr->Local.type; + case irInstr_Load: + return instr->Load.type; + case irInstr_StructElementPtr: + return instr->StructElementPtr.result_type; + case irInstr_ArrayElementPtr: + return instr->ArrayElementPtr.result_type; + case irInstr_PtrOffset: + return ir_type(instr->PtrOffset.address); + case irInstr_Phi: + return instr->Phi.type; + case irInstr_StructExtractValue: + return instr->StructExtractValue.result_type; + case irInstr_UnionTagPtr: + return instr->UnionTagPtr.type; + case irInstr_UnionTagValue: + return instr->UnionTagValue.type; + case irInstr_UnaryOp: + return instr->UnaryOp.type; + case irInstr_BinaryOp: + return instr->BinaryOp.type; + case irInstr_Conv: + return instr->Conv.to; + case irInstr_Select: + return ir_type(instr->Select.true_value); + case irInstr_Call: { + Type *pt = base_type(instr->Call.type); + if (pt != NULL) { + if (pt->kind == Type_Tuple && pt->Tuple.variable_count == 1) { + return pt->Tuple.variables[0]->type; + } + return pt; + } + return NULL; + } break; + } + return NULL; +} + +Type *ir_type(irValue *value) { + switch (value->kind) { + case irValue_Constant: + return value->Constant.type; + case irValue_ConstantSlice: + return value->ConstantSlice.type; + case irValue_Nil: + return value->Nil.type; + case irValue_TypeName: + return value->TypeName.type; + case irValue_Global: + return value->Global.type; + case irValue_Param: + return value->Param.type; + case irValue_Proc: + return value->Proc.type; + case irValue_Instr: + return ir_instr_type(&value->Instr); + } + return NULL; +} + + +bool ir_is_blank_ident(AstNode *node) { + if (node->kind == AstNode_Ident) { + ast_node(i, Ident, node); + return is_blank_ident(i->string); + } + return false; +} + + +irInstr *ir_get_last_instr(irBlock *block) { + if (block != NULL) { + isize len = block->instrs.count; + if (len > 0) { + irValue *v = block->instrs.e[len-1]; + GB_ASSERT(v->kind == irValue_Instr); + return &v->Instr; + } + } + return NULL; + +} + +bool ir_is_instr_terminating(irInstr *i) { + if (i != NULL) { + switch (i->kind) { + case irInstr_Return: + case irInstr_Unreachable: + return true; + } + } + + return false; +} + + +void ir_add_edge(irBlock *from, irBlock *to) { + GB_ASSERT(from->instrs.count > 0); + if (!ir_is_instr_terminating(ir_get_last_instr(from))) { + array_add(&from->succs, to); + array_add(&to->preds, from); + } +} + +void ir_set_instr_parent(irValue *instr, irBlock *parent) { + if (instr->kind == irValue_Instr) { + instr->Instr.parent = parent; + } +} + +irValueArray *ir_value_referrers(irValue *v) { + switch (v->kind) { + case irValue_Global: + return &v->Global.referrers; + case irValue_Param: + return &v->Param.referrers; + case irValue_Proc: { + if (v->Proc.parent != NULL) { + return &v->Proc.referrers; + } + return NULL; + } + case irValue_Instr: { + irInstr *i = &v->Instr; + switch (i->kind) { + case irInstr_Local: + return &i->Local.referrers; + } + } break; + } + + return NULL; +} + + + +//////////////////////////////////////////////////////////////// +// +// @Make +// +//////////////////////////////////////////////////////////////// + +void ir_module_add_value (irModule *m, Entity *e, irValue *v); +irValue *ir_emit_zero_init (irProcedure *p, irValue *address); +irValue *ir_emit_comment (irProcedure *p, String text); +irValue *ir_emit_store (irProcedure *p, irValue *address, irValue *value); +irValue *ir_emit_load (irProcedure *p, irValue *address); +void ir_emit_jump (irProcedure *proc, irBlock *block); +irValue *ir_emit_conv (irProcedure *proc, irValue *value, Type *t); +irValue *ir_type_info (irProcedure *proc, Type *type); +irValue *ir_build_expr (irProcedure *proc, AstNode *expr); +void ir_build_stmt (irProcedure *proc, AstNode *node); +irValue *ir_build_cond (irProcedure *proc, AstNode *cond, irBlock *true_block, irBlock *false_block); +void ir_build_defer_stmt (irProcedure *proc, irDefer d); +irAddr ir_build_addr (irProcedure *proc, AstNode *expr); +void ir_build_proc (irValue *value, irProcedure *parent); +void ir_gen_global_type_name(irModule *m, Entity *e, String name); + + + + +irValue *ir_alloc_value(gbAllocator a, irValueKind kind) { + irValue *v = gb_alloc_item(a, irValue); + v->kind = kind; + return v; +} +irValue *ir_alloc_instr(irProcedure *proc, irInstrKind kind) { + irValue *v = ir_alloc_value(proc->module->allocator, irValue_Instr); + v->Instr.kind = kind; + proc->instr_count++; + return v; +} +irDebugInfo *ir_alloc_debug_info(gbAllocator a, irDebugInfoKind kind) { + irDebugInfo *di = gb_alloc_item(a, irDebugInfo); + di->kind = kind; + return di; +} + + + + +irValue *ir_value_type_name(gbAllocator a, String name, Type *type) { + irValue *v = ir_alloc_value(a, irValue_TypeName); + v->TypeName.name = name; + v->TypeName.type = type; + return v; +} + +irValue *ir_value_global(gbAllocator a, Entity *e, irValue *value) { + irValue *v = ir_alloc_value(a, irValue_Global); + v->Global.entity = e; + v->Global.type = make_type_pointer(a, e->type); + v->Global.value = value; + array_init(&v->Global.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here + return v; +} +irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e, Type *abi_type) { + irValue *v = ir_alloc_value(a, irValue_Param); + v->Param.kind = irParamPass_Value; + v->Param.parent = parent; + v->Param.entity = e; + v->Param.original_type = e->type; + v->Param.type = abi_type; + + if (abi_type != e->type) { + if (is_type_pointer(abi_type)) { + v->Param.kind = irParamPass_Pointer; + } else if (is_type_integer(abi_type)) { + v->Param.kind = irParamPass_Integer; + } else { + GB_PANIC("Invalid abi type pass kind"); + } + } + array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here + return v; +} +irValue *ir_value_nil(gbAllocator a, Type *type) { + irValue *v = ir_alloc_value(a, irValue_Nil); + v->Nil.type = type; + return v; +} + +String ir_get_global_name(irModule *m, irValue *v) { + if (v->kind != irValue_Global) { + return str_lit(""); + } + irValueGlobal *g = &v->Global; + Entity *e = g->entity; + String name = e->token.string; + String *found = map_string_get(&m->entity_names, hash_pointer(e)); + if (found != NULL) { + name = *found; + } + return name; +} + + + +irValue *ir_instr_local(irProcedure *p, Entity *e, bool zero_initialized) { + irValue *v = ir_alloc_instr(p, irInstr_Local); + irInstr *i = &v->Instr; + i->Local.entity = e; + i->Local.type = make_type_pointer(p->module->allocator, e->type); + i->Local.zero_initialized = zero_initialized; + i->Local.alignment = type_align_of(p->module->allocator, e->type); + array_init(&i->Local.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here + ir_module_add_value(p->module, e, v); + return v; +} + + +irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value, bool atomic) { + irValue *v = ir_alloc_instr(p, irInstr_Store); + irInstr *i = &v->Instr; + i->Store.address = address; + i->Store.value = value; + i->Store.atomic = atomic; + return v; +} + +irValue *ir_instr_zero_init(irProcedure *p, irValue *address) { + irValue *v = ir_alloc_instr(p, irInstr_ZeroInit); + irInstr *i = &v->Instr; + i->ZeroInit.address = address; + return v; +} + +irValue *ir_instr_load(irProcedure *p, irValue *address) { + irValue *v = ir_alloc_instr(p, irInstr_Load); + irInstr *i = &v->Instr; + i->Load.address = address; + i->Load.type = type_deref(ir_type(address)); + return v; +} + +irValue *ir_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *elem_index) { + irValue *v = ir_alloc_instr(p, irInstr_ArrayElementPtr); + irInstr *i = &v->Instr; + Type *t = ir_type(address); + GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); + t = base_type(type_deref(t)); + GB_ASSERT(is_type_array(t) || is_type_vector(t)); + + Type *result_type = make_type_pointer(p->module->allocator, t->Array.elem); + + i->ArrayElementPtr.address = address; + i->ArrayElementPtr.elem_index = elem_index; + i->ArrayElementPtr.result_type = result_type; + + GB_ASSERT_MSG(is_type_pointer(ir_type(address)), + "%s", type_to_string(ir_type(address))); + return v; +} +irValue *ir_instr_struct_element_ptr(irProcedure *p, irValue *address, i32 elem_index, Type *result_type) { + irValue *v = ir_alloc_instr(p, irInstr_StructElementPtr); + irInstr *i = &v->Instr; + i->StructElementPtr.address = address; + i->StructElementPtr.elem_index = elem_index; + i->StructElementPtr.result_type = result_type; + + GB_ASSERT_MSG(is_type_pointer(ir_type(address)), + "%s", type_to_string(ir_type(address))); + return v; +} +irValue *ir_instr_ptr_offset(irProcedure *p, irValue *address, irValue *offset) { + irValue *v = ir_alloc_instr(p, irInstr_PtrOffset); + irInstr *i = &v->Instr; + i->PtrOffset.address = address; + i->PtrOffset.offset = offset; + + GB_ASSERT_MSG(is_type_pointer(ir_type(address)), + "%s", type_to_string(ir_type(address))); + GB_ASSERT_MSG(is_type_integer(ir_type(offset)), + "%s", type_to_string(ir_type(address))); + + return v; +} + + + +irValue *ir_instr_struct_extract_value(irProcedure *p, irValue *address, i32 index, Type *result_type) { + irValue *v = ir_alloc_instr(p, irInstr_StructExtractValue); + irInstr *i = &v->Instr; + i->StructExtractValue.address = address; + i->StructExtractValue.index = index; + i->StructExtractValue.result_type = result_type; + return v; +} + +irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) { + irValue *v = ir_alloc_instr(p, irInstr_UnionTagPtr); + irInstr *i = &v->Instr; + i->UnionTagPtr.address = address; + i->UnionTagPtr.type = t_int_ptr; + return v; +} + +irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) { + irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue); + irInstr *i = &v->Instr; + i->UnionTagValue.address = address; + i->UnionTagValue.type = t_int; + return v; +} + +irValue *ir_instr_unary_op(irProcedure *p, TokenKind op, irValue *expr, Type *type) { + irValue *v = ir_alloc_instr(p, irInstr_UnaryOp); + irInstr *i = &v->Instr; + i->UnaryOp.op = op; + i->UnaryOp.expr = expr; + i->UnaryOp.type = type; + return v; +} + + +irValue *ir_instr_binary_op(irProcedure *p, TokenKind op, irValue *left, irValue *right, Type *type) { + irValue *v = ir_alloc_instr(p, irInstr_BinaryOp); + irInstr *i = &v->Instr; + i->BinaryOp.op = op; + i->BinaryOp.left = left; + i->BinaryOp.right = right; + i->BinaryOp.type = type; + return v; +} + +irValue *ir_instr_jump(irProcedure *p, irBlock *block) { + irValue *v = ir_alloc_instr(p, irInstr_Jump); + irInstr *i = &v->Instr; + i->Jump.block = block; + return v; +} +irValue *ir_instr_if(irProcedure *p, irValue *cond, irBlock *true_block, irBlock *false_block) { + irValue *v = ir_alloc_instr(p, irInstr_If); + irInstr *i = &v->Instr; + i->If.cond = cond; + i->If.true_block = true_block; + i->If.false_block = false_block; + return v; +} + + +irValue *ir_instr_phi(irProcedure *p, irValueArray edges, Type *type) { + irValue *v = ir_alloc_instr(p, irInstr_Phi); + irInstr *i = &v->Instr; + i->Phi.edges = edges; + i->Phi.type = type; + return v; +} + +irValue *ir_instr_unreachable(irProcedure *p) { + irValue *v = ir_alloc_instr(p, irInstr_Unreachable); + return v; +} + +irValue *ir_instr_return(irProcedure *p, irValue *value) { + irValue *v = ir_alloc_instr(p, irInstr_Return); + v->Instr.Return.value = value; + return v; +} + +irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { + irValue *v = ir_alloc_instr(p, irInstr_Select); + v->Instr.Select.cond = cond; + v->Instr.Select.true_value = t; + v->Instr.Select.false_value = f; + return v; +} + +irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irValue **args, isize arg_count, Type *result_type) { + irValue *v = ir_alloc_instr(p, irInstr_Call); + v->Instr.Call.value = value; + v->Instr.Call.return_ptr = return_ptr; + v->Instr.Call.args = args; + v->Instr.Call.arg_count = arg_count; + v->Instr.Call.type = result_type; + return v; +} + +irValue *ir_instr_conv(irProcedure *p, irConvKind kind, irValue *value, Type *from, Type *to) { + irValue *v = ir_alloc_instr(p, irInstr_Conv); + v->Instr.Conv.kind = kind; + v->Instr.Conv.value = value; + v->Instr.Conv.from = from; + v->Instr.Conv.to = to; + return v; +} + +irValue *ir_instr_comment(irProcedure *p, String text) { + irValue *v = ir_alloc_instr(p, irInstr_Comment); + v->Instr.Comment.text = text; + return v; +} + +irValue *ir_instr_bounds_check(irProcedure *p, TokenPos pos, irValue *index, irValue *len) { + irValue *v = ir_alloc_instr(p, irInstr_BoundsCheck); + v->Instr.BoundsCheck.pos = pos; + v->Instr.BoundsCheck.index = index; + v->Instr.BoundsCheck.len = len; + return v; +} +irValue *ir_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue *low, irValue *high, irValue *max, bool is_substring) { + irValue *v = ir_alloc_instr(p, irInstr_SliceBoundsCheck); + v->Instr.SliceBoundsCheck.pos = pos; + v->Instr.SliceBoundsCheck.low = low; + v->Instr.SliceBoundsCheck.high = high; + v->Instr.SliceBoundsCheck.max = max; + v->Instr.SliceBoundsCheck.is_substring = is_substring; + return v; +} +irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) { + irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare); + v->Instr.DebugDeclare.debug_info = debug_info; + v->Instr.DebugDeclare.expr = expr; + v->Instr.DebugDeclare.entity = entity; + v->Instr.DebugDeclare.is_addr = is_addr; + v->Instr.DebugDeclare.value = value; + return v; + +} + + + +irValue *ir_value_constant(gbAllocator a, Type *type, ExactValue value) { + irValue *v = ir_alloc_value(a, irValue_Constant); + v->Constant.type = type; + v->Constant.value = value; + return v; +} + + +irValue *ir_value_constant_slice(gbAllocator a, Type *type, irValue *backing_array, i64 count) { + irValue *v = ir_alloc_value(a, irValue_ConstantSlice); + v->ConstantSlice.type = type; + v->ConstantSlice.backing_array = backing_array; + v->ConstantSlice.count = count; + return v; +} + + + +irValue *ir_emit(irProcedure *proc, irValue *instr) { + GB_ASSERT(instr->kind == irValue_Instr); + irBlock *b = proc->curr_block; + instr->Instr.parent = b; + if (b != NULL) { + irInstr *i = ir_get_last_instr(b); + if (!ir_is_instr_terminating(i)) { + array_add(&b->instrs, instr); + } + } else if (instr->Instr.kind != irInstr_Unreachable) { + GB_PANIC("ir_emit: Instruction missing parent block"); + } + return instr; +} + + + +irValue *ir_const_int(gbAllocator a, i64 i) { + return ir_value_constant(a, t_int, exact_value_i64(i)); +} +irValue *ir_const_i32(gbAllocator a, i32 i) { + return ir_value_constant(a, t_i32, exact_value_i64(i)); +} +irValue *ir_const_u32(gbAllocator a, u32 i) { + return ir_value_constant(a, t_u32, exact_value_i64(i)); +} +irValue *ir_const_i64(gbAllocator a, i64 i) { + return ir_value_constant(a, t_i64, exact_value_i64(i)); +} +irValue *ir_const_u64(gbAllocator a, u64 i) { + return ir_value_constant(a, t_u64, exact_value_i64(i)); +} +irValue *ir_const_f32(gbAllocator a, f32 f) { + return ir_value_constant(a, t_f32, exact_value_float(f)); +} +irValue *ir_const_f64(gbAllocator a, f64 f) { + return ir_value_constant(a, t_f64, exact_value_float(f)); +} +irValue *ir_const_bool(gbAllocator a, bool b) { + return ir_value_constant(a, t_bool, exact_value_bool(b != 0)); +} +irValue *ir_const_string(gbAllocator a, String s) { + return ir_value_constant(a, t_string, exact_value_string(s)); +} + +irValue *ir_value_procedure(gbAllocator a, irModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) { + irValue *v = ir_alloc_value(a, irValue_Proc); + v->Proc.module = m; + v->Proc.entity = entity; + v->Proc.type = type; + v->Proc.type_expr = type_expr; + v->Proc.body = body; + v->Proc.name = name; + array_init(&v->Proc.referrers, heap_allocator()); // TODO(bill): replace heap allocator + + Type *t = base_type(type); + GB_ASSERT(is_type_proc(t)); + array_init_reserve(&v->Proc.params, heap_allocator(), t->Proc.param_count); + + return v; +} + + +irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefix, i64 id) { + gbAllocator a = m->allocator; + Token token = {Token_Ident}; + isize name_len = prefix.len + 10; + token.string.text = gb_alloc_array(a, u8, name_len); + token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, + "%.*s-%llx", LIT(prefix), cast(unsigned long long)id)-1; + Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, elem_type, count), false); + irValue *value = ir_value_global(a, e, NULL); + value->Global.is_private = true; + ir_module_add_value(m, e, value); + map_ir_value_set(&m->members, hash_string(token.string), value); + return value; +} + +irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) { + Scope *scope = NULL; + if (node != NULL) { + Scope **found = map_scope_get(&proc->module->info->scopes, hash_pointer(node)); + if (found) { + scope = *found; + } else { + GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind])); + } + } + + irValue *v = ir_alloc_value(proc->module->allocator, irValue_Block); + v->Block.label = make_string_c(label); + v->Block.node = node; + v->Block.scope = scope; + v->Block.parent = proc; + // TODO(bill): Is this correct or even needed? + v->Block.scope_index = proc->scope_index; + + array_init(&v->Block.instrs, heap_allocator()); + array_init(&v->Block.locals, heap_allocator()); + + array_init(&v->Block.preds, heap_allocator()); + array_init(&v->Block.succs, heap_allocator()); + + irBlock *block = &v->Block; + return block; +} + +void ir_add_block_to_proc(irProcedure *proc, irBlock *b) { + for_array(i, proc->blocks) { + if (proc->blocks.e[i] == b) { + return; + } + } + array_add(&proc->blocks, b); + b->index = proc->block_count++; +} + +void ir_start_block(irProcedure *proc, irBlock *block) { + proc->curr_block = block; + if (block != NULL) { + ir_add_block_to_proc(proc, block); + } +} + + + + + + + +irDefer ir_add_defer_node(irProcedure *proc, isize scope_index, AstNode *stmt) { + irDefer d = {irDefer_Node}; + d.scope_index = scope_index; + d.block = proc->curr_block; + d.stmt = stmt; + array_add(&proc->defer_stmts, d); + return d; +} + + +irDefer ir_add_defer_instr(irProcedure *proc, isize scope_index, irValue *instr) { + irDefer d = {irDefer_Instr}; + d.scope_index = proc->scope_index; + d.block = proc->curr_block; + d.instr = instr; // NOTE(bill): It will make a copy everytime it is called + array_add(&proc->defer_stmts, d); + return d; +} + + + +irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { + gbAllocator a = m->allocator; + // gbAllocator a = gb_heap_allocator(); + + if (is_type_slice(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + isize count = cl->elems.count; + if (count == 0) { + return ir_value_nil(a, type); + } + Type *elem = base_type(type)->Slice.elem; + Type *t = make_type_array(a, elem, count); + irValue *backing_array = ir_add_module_constant(m, t, value); + + + isize max_len = 7+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index); + m->global_array_index++; + + String name = make_string(str, len-1); + + Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value); + irValue *g = ir_value_global(a, e, backing_array); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + + return ir_value_constant_slice(a, type, g, count); + } + + return ir_value_constant(a, type, value); +} + +irValue *ir_add_global_string_array(irModule *m, String string) { + // TODO(bill): Should this use the arena allocator or the heap allocator? + // Strings could be huge! + gbAllocator a = m->allocator; + // gbAllocator a = gb_heap_allocator(); + + isize max_len = 6+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index); + m->global_string_index++; + + String name = make_string(str, len-1); + Token token = {Token_String}; + token.string = name; + Type *type = make_type_array(a, t_u8, string.len); + ExactValue ev = exact_value_string(string); + Entity *entity = make_entity_constant(a, NULL, token, type, ev); + irValue *g = ir_value_global(a, entity, ir_add_module_constant(m, type, ev)); + g->Global.is_private = true; + // g->Global.is_unnamed_addr = true; + // g->Global.is_constant = true; + + ir_module_add_value(m, entity, g); + map_ir_value_set(&m->members, hash_string(name), g); + + return g; +} + + + + +irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) { + irBlock *b = proc->decl_block; // all variables must be in the first block + irValue *instr = ir_instr_local(proc, e, true); + instr->Instr.parent = b; + array_add(&b->instrs, instr); + array_add(&b->locals, instr); + proc->local_count++; + + // if (zero_initialized) { + ir_emit_zero_init(proc, instr); + // } + + if (expr != NULL && proc->entity != NULL) { + irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); + ir_emit(proc, ir_instr_debug_declare(proc, di, expr, e, true, instr)); + } + + return instr; +} + +irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero_initialized) { + Entity **found = map_entity_get(&proc->module->info->definitions, hash_pointer(name)); + if (found) { + Entity *e = *found; + ir_emit_comment(proc, e->token.string); + return ir_add_local(proc, e, name); + } + return NULL; +} + +irValue *ir_add_local_generated(irProcedure *proc, Type *type) { + GB_ASSERT(type != NULL); + + Scope *scope = NULL; + if (proc->curr_block) { + scope = proc->curr_block->scope; + } + Entity *e = make_entity_variable(proc->module->allocator, + scope, + empty_token, + type, false); + return ir_add_local(proc, e, NULL); +} + + +irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) { + GB_ASSERT(type != NULL); + gbAllocator a = m->allocator; + + isize max_len = 7+8+1; + u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "__ggv$%x", m->global_generated_index); + m->global_generated_index++; + String name = make_string(str, len-1); + + Scope *scope = NULL; + Entity *e = make_entity_variable(a, + scope, + make_token_ident(name), + type, false); + + irValue *g = ir_value_global(a, e, value); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + return g; +} + + +irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr, Type *abi_type) { + irValue *v = ir_value_param(proc->module->allocator, proc, e, abi_type); + irValueParam *p = &v->Param; + + switch (p->kind) { + case irParamPass_Value: { + irValue *l = ir_add_local(proc, e, expr); + ir_emit_store(proc, l, v); + return v; + } + case irParamPass_Pointer: { + ir_module_add_value(proc->module, e, v); + return ir_emit_load(proc, v); + } + case irParamPass_Integer: { + irValue *l = ir_add_local(proc, e, expr); + irValue *iptr = ir_emit_conv(proc, l, make_type_pointer(proc->module->allocator, p->type)); + ir_emit_store(proc, iptr, v); + return ir_emit_load(proc, l); + } + } + + GB_PANIC("Unreachable"); + return NULL; +} + + + +//////////////////////////////////////////////////////////////// +// +// @Debug +// +//////////////////////////////////////////////////////////////// + +irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { + // if (!proc->module->generate_debug_info) { + // return NULL; + // } + + GB_ASSERT(file != NULL); + irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_File); + di->File.file = file; + + String filename = file->tokenizer.fullpath; + String directory = filename; + isize slash_index = 0; + for (isize i = filename.len-1; i >= 0; i--) { + if (filename.text[i] == '\\' || + filename.text[i] == '/') { + break; + } + slash_index = i; + } + directory.len = slash_index-1; + filename.text = filename.text + slash_index; + filename.len -= slash_index; + + + di->File.filename = filename; + di->File.directory = directory; + + map_ir_debug_info_set(&proc->module->debug_info, hash_pointer(file), di); + return di; +} + + +irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) { + // if (!proc->module->generate_debug_info) { + // return NULL; + // } + + GB_ASSERT(entity != NULL); + irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_Proc); + di->Proc.entity = entity; + di->Proc.name = name; + di->Proc.file = file; + di->Proc.pos = entity->token.pos; + + map_ir_debug_info_set(&proc->module->debug_info, hash_pointer(entity), di); + return di; +} + +//////////////////////////////////////////////////////////////// +// +// @Emit +// +//////////////////////////////////////////////////////////////// + + + +irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) { +#if 1 + // NOTE(bill): Sanity check + Type *a = type_deref(ir_type(address)); + Type *b = ir_type(value); + if (!is_type_untyped(b)) { + GB_ASSERT_MSG(are_types_identical(core_type(a), core_type(b)), "%s %s", type_to_string(a), type_to_string(b)); + } +#endif + return ir_emit(p, ir_instr_store(p, address, value, is_type_atomic(a))); +} +irValue *ir_emit_load(irProcedure *p, irValue *address) { + GB_ASSERT(address != NULL); + return ir_emit(p, ir_instr_load(p, address)); +} +irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { + return ir_emit(p, ir_instr_select(p, cond, t, f)); +} + +irValue *ir_emit_zero_init(irProcedure *p, irValue *address) { + return ir_emit(p, ir_instr_zero_init(p, address)); +} + +irValue *ir_emit_comment(irProcedure *p, String text) { + return ir_emit(p, ir_instr_comment(p, text)); +} + +irValue *ir_copy_value_to_ptr(irProcedure *proc, irValue *val, Type *new_type, i64 alignment) { + i64 type_alignment = type_align_of(proc->module->allocator, new_type); + if (alignment < type_alignment) { + alignment = type_alignment; + } + irValue *ptr = ir_add_local_generated(proc, new_type); + ptr->Instr.Local.alignment = alignment; + ir_emit_store(proc, ptr, val); + return ptr; +} + +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { + return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); +} + +irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t); + +irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_count) { + Type *pt = base_type(ir_type(value)); + GB_ASSERT(pt->kind == Type_Proc); + Type *results = pt->Proc.results; + + isize param_count = pt->Proc.param_count; + GB_ASSERT(param_count == arg_count); + for (isize i = 0; i < param_count; i++) { + Type *original_type = pt->Proc.params->Tuple.variables[i]->type; + Type *new_type = pt->Proc.abi_compat_params[i]; + if (original_type != new_type) { + if (is_type_pointer(new_type)) { + args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); + } else if (is_type_integer(new_type)) { + args[i] = ir_emit_transmute(p, args[i], new_type); + } + } + } + + Type *abi_rt = pt->Proc.abi_compat_result_type; + Type *rt = reduce_tuple_to_single_type(results); + if (pt->Proc.return_by_pointer) { + irValue *return_ptr = ir_add_local_generated(p, rt); + GB_ASSERT(is_type_pointer(ir_type(return_ptr))); + ir_emit(p, ir_instr_call(p, value, return_ptr, args, arg_count, NULL)); + return ir_emit_load(p, return_ptr); + } + + irValue *result = ir_emit(p, ir_instr_call(p, value, NULL, args, arg_count, abi_rt)); + if (abi_rt != results) { + result = ir_emit_transmute(p, result, rt); + } + return result; +} + +irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count) { + String name = make_string_c(name_); + irValue **found = map_ir_value_get(&proc->module->members, hash_string(name)); + GB_ASSERT_MSG(found != NULL, "%.*s", LIT(name)); + irValue *gp = *found; + return ir_emit_call(proc, gp, args, arg_count); +} + + + +void ir_emit_defer_stmts(irProcedure *proc, irDeferExitKind kind, irBlock *block) { + isize count = proc->defer_stmts.count; + isize i = count; + while (i --> 0) { + irDefer d = proc->defer_stmts.e[i]; + if (kind == irDeferExit_Default) { + if (proc->scope_index == d.scope_index && + d.scope_index > 1) { + ir_build_defer_stmt(proc, d); + array_pop(&proc->defer_stmts); + continue; + } else { + break; + } + } else if (kind == irDeferExit_Return) { + ir_build_defer_stmt(proc, d); + } else if (kind == irDeferExit_Branch) { + GB_ASSERT(block != NULL); + isize lower_limit = block->scope_index+1; + if (lower_limit < d.scope_index) { + ir_build_defer_stmt(proc, d); + } + } + } +} + + +void ir_open_scope(irProcedure *proc) { + proc->scope_index++; +} + +void ir_close_scope(irProcedure *proc, irDeferExitKind kind, irBlock *block) { + ir_emit_defer_stmts(proc, kind, block); + GB_ASSERT(proc->scope_index > 0); + proc->scope_index--; +} + + + +void ir_emit_unreachable(irProcedure *proc) { + ir_emit(proc, ir_instr_unreachable(proc)); +} + +void ir_emit_return(irProcedure *proc, irValue *v) { + ir_emit_defer_stmts(proc, irDeferExit_Return, NULL); + + if (proc->type->Proc.return_by_pointer) { + ir_emit_store(proc, proc->return_ptr, v); + ir_emit(proc, ir_instr_return(proc, NULL)); + } else { + Type *abi_rt = proc->type->Proc.abi_compat_result_type; + if (abi_rt != proc->type->Proc.results) { + v = ir_emit_transmute(proc, v, abi_rt); + } + + ir_emit(proc, ir_instr_return(proc, v)); + } +} + +void ir_emit_jump(irProcedure *proc, irBlock *target_block) { + irBlock *b = proc->curr_block; + if (b == NULL) { + return; + } + ir_emit(proc, ir_instr_jump(proc, target_block)); + ir_add_edge(b, target_block); + ir_start_block(proc, NULL); +} + +void ir_emit_if(irProcedure *proc, irValue *cond, irBlock *true_block, irBlock *false_block) { + irBlock *b = proc->curr_block; + if (b == NULL) { + return; + } + ir_emit(proc, ir_instr_if(proc, cond, true_block, false_block)); + ir_add_edge(b, true_block); + ir_add_edge(b, false_block); + ir_start_block(proc, NULL); +} + +void ir_emit_startup_runtime(irProcedure *proc) { + GB_ASSERT(proc->parent == NULL && str_eq(proc->name, str_lit("main"))); + ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); +} + + + + +irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); +irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); + +irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) { + GB_ASSERT_MSG(is_type_pointer(ir_type(map_val)), "%s", type_to_string(ir_type(map_val))); + gbAllocator a = proc->module->allocator; + irValue *h = ir_add_local_generated(proc, t_map_header); + map_type = base_type(map_type); + + Type *key_type = map_type->Map.key; + Type *val_type = map_type->Map.value; + + // NOTE(bill): Removes unnecessary allocation if split gep + irValue *gep0 = ir_emit_struct_ep(proc, h, 0); + irValue *m = ir_emit_conv(proc, map_val, type_deref(ir_type(gep0))); + ir_emit_store(proc, gep0, m); + + if (is_type_string(key_type)) { + // GB_PANIC("TODO(bill): string map keys"); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), v_true); + } + + i64 entry_size = type_size_of(a, map_type->Map.entry_type); + i64 entry_align = type_align_of(a, map_type->Map.entry_type); + i64 value_offset = type_offset_of(a, map_type->Map.entry_type, 2); + i64 value_size = type_size_of(a, map_type->Map.value); + + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(a, entry_size)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(a, entry_align)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_int(a, value_offset)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 5), ir_const_int(a, value_size)); + + + return ir_emit_load(proc, h); +} + +irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { + Type *hash_type = t_u128; + irValue *v = ir_add_local_generated(proc, t_map_key); + Type *t = base_type(ir_type(key)); + key = ir_emit_conv(proc, key, key_type); + if (is_type_integer(t)) { + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); + } else if (is_type_pointer(t)) { + irValue *p = ir_emit_conv(proc, key, t_uint); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, hash_type)); + } else if (is_type_float(t)) { + irValue *bits = NULL; + i64 size = type_size_of(proc->module->allocator, t); + switch (8*size) { + case 32: bits = ir_emit_transmute(proc, key, t_u32); break; + case 64: bits = ir_emit_transmute(proc, key, t_u64); break; + default: GB_PANIC("Unhandled float size: %lld bits", size); break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, hash_type)); + } else if (is_type_string(t)) { + irValue *str = ir_emit_conv(proc, key, t_string); + irValue *hashed_str = NULL; + + if (str->kind == irValue_Constant) { + ExactValue ev = str->Constant.value; + GB_ASSERT(ev.kind == ExactValue_String); + u128 hs = fnv128a(ev.value_string.text, ev.value_string.len); + hashed_str = ir_value_constant(proc->module->allocator, t_u128, exact_value_u128(hs)); + } else { + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + args[0] = str; + hashed_str = ir_emit_global_call(proc, "__default_hash_string", args, 1); + } + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); + } else { + GB_PANIC("Unhandled map key type"); + } + + return ir_emit_load(proc, v); +} + +// NOTE(bill): Returns NULL if not possible +irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) { + if (val->kind == irValue_Instr) { + if (val->Instr.kind == irInstr_Load) { + return val->Instr.Load.address; + } + } + Type *type = ir_type(val); + irValue *local = ir_add_local_generated(proc, type); + ir_emit_store(proc, local, val); + return local; +} + + +Type *ir_addr_type(irAddr addr) { + if (addr.addr == NULL) { + return NULL; + } + + if (addr.kind == irAddr_Map) { + Type *t = base_type(addr.map_type); + GB_ASSERT(is_type_map(t)); + return t->Map.value; + } + + Type *t = ir_type(addr.addr); + GB_ASSERT(is_type_pointer(t)); + return type_deref(t); +} + +irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, + irValue *map_key, irValue *map_value) { + map_type = base_type(map_type); + + irValue *h = ir_gen_map_header(proc, addr, map_type); + irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key); + irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value); + + irValue *ptr = ir_add_local_generated(proc, ir_type(v)); + ir_emit_store(proc, ptr, v); + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); + args[0] = h; + args[1] = key; + args[2] = ir_emit_conv(proc, ptr, t_rawptr); + + return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); +} + + +irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset); +irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type); + +irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { + if (addr.addr == NULL) { + return NULL; + } + if (addr.kind == irAddr_Map) { + return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); + } else if (addr.kind == irAddr_BitField) { + gbAllocator a = proc->module->allocator; + + Type *bft = base_type(type_deref(ir_type(addr.addr))); + GB_ASSERT(is_type_bit_field(bft)); + i32 value_index = addr.bit_field_value_index; + i32 offset = bft->BitField.offsets[value_index]; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + + i32 byte_index = offset / 8; + i32 bit_inset = offset % 8; + + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + if (size_in_bytes == 0) { + GB_ASSERT(size_in_bits == 0); + return NULL; + } + + Type *int_type = NULL; + switch (size_in_bytes) { + case 1: int_type = t_u8; break; + case 2: int_type = t_u16; break; + case 4: int_type = t_u32; break; + case 8: int_type = t_u64; break; + case 16: int_type = t_u128; break; + } + GB_ASSERT(int_type != NULL); + + value = ir_emit_conv(proc, value, int_type); + + irValue *bytes = ir_emit_conv(proc, addr.addr, t_u8_ptr); + bytes = ir_emit_ptr_offset(proc, bytes, ir_const_int(a, byte_index)); + + + if (bit_inset == 0) { + irValue *v = value; + i32 sa = 8*size_in_bytes - size_in_bits; + if (sa > 0) { + irValue *shift_amount = ir_const_int(a, sa); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Shr, v, shift_amount, int_type); + } + irValue *ptr = ir_emit_conv(proc, bytes, make_type_pointer(a, int_type)); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, ptr), v, int_type); + return ir_emit_store(proc, ptr, v); + } + + + // First byte + { + i32 sa = 8 - bit_inset; + irValue *shift_amount = ir_const_int(a, sa); + irValue *v = ir_emit_conv(proc, value, t_u8); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, bytes), v, int_type); + ir_emit_store(proc, bytes, v); + + } + + // Remaining bytes + { + irValue *shift_amount = ir_const_int(a, bit_inset); + irValue *ptr = ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), make_type_pointer(a, int_type)); + irValue *v = ir_emit_arith(proc, Token_Shr, value, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Or, ir_emit_load(proc, ptr), v, int_type); + return ir_emit_store(proc, ptr, v); + } + } + + irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); + return ir_emit_store(proc, addr.addr, v); +} + +irValue *ir_addr_load(irProcedure *proc, irAddr addr) { + if (addr.addr == NULL) { + GB_PANIC("Illegal addr load"); + return NULL; + } + + if (addr.kind == irAddr_Map) { + // TODO(bill): map lookup + Type *map_type = base_type(addr.map_type); + irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type); + irValue *h = ir_gen_map_header(proc, addr.addr, map_type); + irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2); + args[0] = h; + args[1] = key; + + irValue *ptr = ir_emit_global_call(proc, "__dynamic_map_get", args, 2); + irValue *ok = ir_emit_comp(proc, Token_NotEq, ptr, v_raw_nil); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), ok); + + irBlock *then = ir_new_block(proc, NULL, "map.get.then"); + irBlock *done = ir_new_block(proc, NULL, "map.get.done"); + ir_emit_if(proc, ok, then, done); + ir_start_block(proc, then); + { + // TODO(bill): mem copy it instead? + irValue *gep0 = ir_emit_struct_ep(proc, v, 0); + irValue *value = ir_emit_conv(proc, ptr, ir_type(gep0)); + ir_emit_store(proc, gep0, ir_emit_load(proc, value)); + } + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + + if (is_type_tuple(addr.map_result)) { + return ir_emit_load(proc, v); + } else { + irValue *single = ir_emit_struct_ep(proc, v, 0); + return ir_emit_load(proc, single); + } + } else if (addr.kind == irAddr_BitField) { + gbAllocator a = proc->module->allocator; + + + Type *bft = base_type(type_deref(ir_type(addr.addr))); + GB_ASSERT(is_type_bit_field(bft)); + i32 value_index = addr.bit_field_value_index; + i32 offset = bft->BitField.offsets[value_index]; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + + i32 byte_index = offset / 8; + i32 bit_inset = offset % 8; + + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + if (size_in_bytes == 0) { + GB_ASSERT(size_in_bits == 0); + return ir_const_i32(a, 0); + } + + Type *int_type = NULL; + switch (size_in_bytes) { + case 1: int_type = t_u8; break; + case 2: int_type = t_u16; break; + case 4: int_type = t_u32; break; + case 8: int_type = t_u64; break; + case 16: int_type = t_u128; break; + } + GB_ASSERT(int_type != NULL); + + + irValue *bytes = ir_emit_conv(proc, addr.addr, t_u8_ptr); + bytes = ir_emit_ptr_offset(proc, bytes, ir_const_int(a, byte_index)); + + Type *int_ptr = make_type_pointer(a, int_type); + + if (bit_inset == 0) { + irValue *v = ir_emit_load(proc, ir_emit_conv(proc, bytes, int_ptr)); + i32 sa = 8*size_in_bytes - size_in_bits; + if (sa > 0) { + irValue *shift_amount = ir_const_int(a, sa); + v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type); + v = ir_emit_arith(proc, Token_Shr, v, shift_amount, int_type); + } + return v; + } + + + irValue *first_byte = ir_emit_load(proc, bytes); + irValue *res = ir_emit_arith(proc, Token_Shr, first_byte, ir_const_int(a, 8 - bit_inset), int_type); + + irValue *remaining_bytes = ir_emit_load(proc, ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), int_ptr)); + remaining_bytes = ir_emit_arith(proc, Token_Shl, remaining_bytes, ir_const_int(a, bit_inset), int_type); + return ir_emit_arith(proc, Token_Or, res, remaining_bytes, int_type); + + } + + Type *t = base_type(ir_type(addr.addr)); + if (t->kind == Type_Proc) { + // NOTE(bill): Imported procedures don't require a load as they are pointers + return addr.addr; + } + return ir_emit_load(proc, addr.addr); +} + +irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index); +irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index); + +irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset) { + offset = ir_emit_conv(proc, offset, t_int); + return ir_emit(proc, ir_instr_ptr_offset(proc, ptr, offset)); +} + +irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type *type) { + switch (op) { + case Token_Add: + return x; + case Token_Not: // Boolean not + case Token_Xor: // Bitwise not + case Token_Sub: // Bitwise Not + break; + case Token_Pointer: + GB_PANIC("This should be handled elsewhere"); + break; + } + if (is_type_vector(ir_type(x))) { + ir_emit_comment(proc, str_lit("vector.arith.begin")); + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + Type *tl = base_type(ir_type(x)); + irValue *val = ir_address_from_load_or_generate_local(proc, x); + GB_ASSERT(is_type_vector(type)); + Type *elem_type = base_type(type)->Vector.elem; + + irValue *res = ir_add_local_generated(proc, type); + for (i32 i = 0; i < tl->Vector.count; i++) { + irValue *e = ir_emit_load(proc, ir_emit_array_epi(proc, val, i)); + irValue *z = ir_emit_unary_arith(proc, op, e, elem_type); + ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); + } + ir_emit_comment(proc, str_lit("vector.arith.end")); + return ir_emit_load(proc, res); + + } + return ir_emit(proc, ir_instr_unary_op(proc, op, x, type)); +} + + + +irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type) { + Type *t_left = ir_type(left); + Type *t_right = ir_type(right); + + if (is_type_vector(t_left) || is_type_vector(t_right)) { + ir_emit_comment(proc, str_lit("vector.arith.begin")); + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + left = ir_emit_conv(proc, left, type); + right = ir_emit_conv(proc, right, type); + irValue *lhs = ir_address_from_load_or_generate_local(proc, left); + irValue *rhs = ir_address_from_load_or_generate_local(proc, right); + GB_ASSERT(is_type_vector(type)); + Type *elem_type = base_type(type)->Vector.elem; + + irValue *res = ir_add_local_generated(proc, type); + i64 count = base_type(type)->Vector.count; + for (i32 i = 0; i < count; i++) { + irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); + irValue *z = ir_emit_arith(proc, op, x, y, elem_type); + ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); + } + ir_emit_comment(proc, str_lit("vector.arith.end")); + return ir_emit_load(proc, res); + } + + if (is_type_complex(t_left)) { + ir_emit_comment(proc, str_lit("complex.arith.begin")); + Type *ft = base_complex_elem_type(t_left); + + irValue *res = ir_add_local_generated(proc, type); + irValue *a = ir_emit_struct_ev(proc, left, 0); + irValue *b = ir_emit_struct_ev(proc, left, 1); + irValue *c = ir_emit_struct_ev(proc, right, 0); + irValue *d = ir_emit_struct_ev(proc, right, 1); + + irValue *real = NULL; + irValue *imag = NULL; + + switch (op) { + case Token_Add: + real = ir_emit_arith(proc, Token_Add, a, c, ft); + imag = ir_emit_arith(proc, Token_Add, b, d, ft); + break; + case Token_Sub: + real = ir_emit_arith(proc, Token_Sub, a, c, ft); + imag = ir_emit_arith(proc, Token_Sub, b, d, ft); + break; + case Token_Mul: { + irValue *x = ir_emit_arith(proc, Token_Mul, a, c, ft); + irValue *y = ir_emit_arith(proc, Token_Mul, b, d, ft); + real = ir_emit_arith(proc, Token_Sub, x, y, ft); + irValue *z = ir_emit_arith(proc, Token_Mul, b, c, ft); + irValue *w = ir_emit_arith(proc, Token_Mul, a, d, ft); + imag = ir_emit_arith(proc, Token_Add, z, w, ft); + } break; + case Token_Quo: { + irValue *s1 = ir_emit_arith(proc, Token_Mul, c, c, ft); + irValue *s2 = ir_emit_arith(proc, Token_Mul, d, d, ft); + irValue *s = ir_emit_arith(proc, Token_Add, s1, s2, ft); + + irValue *x = ir_emit_arith(proc, Token_Mul, a, c, ft); + irValue *y = ir_emit_arith(proc, Token_Mul, b, d, ft); + real = ir_emit_arith(proc, Token_Add, x, y, ft); + real = ir_emit_arith(proc, Token_Quo, real, s, ft); + + irValue *z = ir_emit_arith(proc, Token_Mul, b, c, ft); + irValue *w = ir_emit_arith(proc, Token_Mul, a, d, ft); + imag = ir_emit_arith(proc, Token_Sub, z, w, ft); + imag = ir_emit_arith(proc, Token_Quo, imag, s, ft); + } break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + + ir_emit_comment(proc, str_lit("complex.end.begin")); + return ir_emit_load(proc, res); + } + + + if (op == Token_Add) { + if (is_type_pointer(t_left)) { + irValue *ptr = ir_emit_conv(proc, left, type); + irValue *offset = right; + return ir_emit_ptr_offset(proc, ptr, offset); + } else if (is_type_pointer(ir_type(right))) { + irValue *ptr = ir_emit_conv(proc, right, type); + irValue *offset = left; + return ir_emit_ptr_offset(proc, ptr, offset); + } + } else if (op == Token_Sub) { + if (is_type_pointer(t_left) && is_type_integer(t_right)) { + // ptr - int + irValue *ptr = ir_emit_conv(proc, left, type); + irValue *offset = ir_emit_unary_arith(proc, Token_Sub, right, t_int); + return ir_emit_ptr_offset(proc, ptr, offset); + } else if (is_type_pointer(t_left) && is_type_pointer(t_right)) { + GB_ASSERT(is_type_integer(type)); + irModule *m = proc->module; + Type *ptr_type = base_type(t_left); + GB_ASSERT(!is_type_rawptr(ptr_type)); + irValue *elem_size = ir_const_int(m->allocator, type_size_of(m->allocator, ptr_type->Pointer.elem)); + irValue *x = ir_emit_conv(proc, left, type); + irValue *y = ir_emit_conv(proc, right, type); + irValue *diff = ir_emit_arith(proc, op, x, y, type); + return ir_emit_arith(proc, Token_Quo, diff, elem_size, type); + } + } + + + switch (op) { + case Token_Shl: + case Token_Shr: + left = ir_emit_conv(proc, left, type); + // if (!is_type_unsigned(ir_type(right))) { + // Type *t = t_u64; + // if (build_context.word_size == 32) { + // t = t_u32; + // } + // right = ir_emit_conv(proc, right, t); + // } + right = ir_emit_conv(proc, right, type); + + break; + + case Token_AndNot: { + // NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1) + // NOTE(bill): "not" `x` == `x` "xor" `-1` + irValue *neg = ir_add_module_constant(proc->module, type, exact_value_i64(-1)); + op = Token_Xor; + right = ir_emit_arith(proc, op, right, neg, type); + GB_ASSERT(right->Instr.kind == irInstr_BinaryOp); + right->Instr.BinaryOp.type = type; + op = Token_And; + } /* fallthrough */ + case Token_Add: + case Token_Sub: + case Token_Mul: + case Token_Quo: + case Token_Mod: + case Token_ModMod: + case Token_And: + case Token_Or: + case Token_Xor: + left = ir_emit_conv(proc, left, type); + right = ir_emit_conv(proc, right, type); + break; + } + + if (op == Token_ModMod) { + irValue *n = left; + irValue *m = right; + irValue *a = ir_emit_arith(proc, Token_Mod, n, m, type); + irValue *b = ir_emit_arith(proc, Token_Add, a, m, type); + return ir_emit_arith(proc, Token_Mod, b, m, type); + } + + if (is_type_i128_or_u128(type)) { + // IMPORTANT NOTE(bill): LLVM is goddamn buggy! + bool is_unsigned = is_type_unsigned(type); + char *name = NULL; + if (op == Token_Quo) { + name = is_unsigned ? "__udivti3" : "__divti3"; + } else if (op == Token_Mod) { + name = is_unsigned ? "__umodti3" : "__modti3"; + } + if (name != NULL) { + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2); + args[0] = left; + args[1] = right; + return ir_emit_global_call(proc, name, args, 2); + } + } + + return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type)); +} + +irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) { + Type *t = ir_type(u); + GB_ASSERT_MSG(is_type_pointer(t) && + is_type_union(type_deref(t)), "%s", type_to_string(t)); + irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u)); + Type *tpt = ir_type(tag_ptr); + GB_ASSERT(is_type_pointer(tpt)); + tpt = base_type(type_deref(tpt)); + GB_ASSERT(tpt == t_int); + return tag_ptr; +} + +irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) { + Type *t = ir_type(u); + GB_ASSERT(is_type_union(t)); + GB_ASSERT(are_types_identical(t, ir_type(u))); + return ir_emit(proc, ir_instr_union_tag_value(proc, u)); +} + +irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); + +irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) { + Type *t = ir_type(x); + if (is_type_any(t)) { + irValue *data = ir_emit_struct_ev(proc, x, 0); + irValue *ti = ir_emit_struct_ev(proc, x, 1); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, ti, v_raw_nil); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, ti, v_raw_nil); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_slice(t)) { + irValue *data = ir_emit_struct_ev(proc, x, 0); + irValue *cap = ir_emit_struct_ev(proc, x, 2); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_dynamic_array(t)) { + irValue *data = ir_emit_struct_ev(proc, x, 0); + irValue *cap = ir_emit_struct_ev(proc, x, 2); + if (op_kind == Token_CmpEq) { + irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); + irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_map(t)) { + irValue *hashes = ir_emit_struct_ev(proc, x, 0); + irValue *entries = ir_emit_struct_ev(proc, x, 1); + irValue *a = ir_emit_comp_against_nil(proc, op_kind, hashes); + irValue *b = ir_emit_comp_against_nil(proc, op_kind, entries); + if (op_kind == Token_CmpEq) { + return ir_emit_arith(proc, Token_Or, a, b, t_bool); + } else if (op_kind == Token_NotEq) { + return ir_emit_arith(proc, Token_And, a, b, t_bool); + } + } else if (is_type_union(t)) { + irValue *tag = ir_emit_union_tag_value(proc, x); + return ir_emit_comp(proc, op_kind, tag, v_zero); + } + return NULL; +} + +irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) { + Type *a = base_type(ir_type(left)); + Type *b = base_type(ir_type(right)); + + GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); + + irValue *nil_check = NULL; + if (left->kind == irValue_Nil) { + nil_check = ir_emit_comp_against_nil(proc, op_kind, right); + } else if (right->kind == irValue_Nil) { + nil_check = ir_emit_comp_against_nil(proc, op_kind, left); + } + if (nil_check != NULL) { + return nil_check; + } + + if (are_types_identical(a, b)) { + // NOTE(bill): No need for a conversion + } else if (left->kind == irValue_Constant || left->kind == irValue_Nil) { + left = ir_emit_conv(proc, left, ir_type(right)); + } else if (right->kind == irValue_Constant || right->kind == irValue_Nil) { + right = ir_emit_conv(proc, right, ir_type(left)); + } + + Type *result = t_bool; + if (is_type_vector(a)) { + result = make_type_vector(proc->module->allocator, t_bool, a->Vector.count); + } + + if (is_type_vector(a)) { + ir_emit_comment(proc, str_lit("vector.comp.begin")); + Type *tl = base_type(a); + irValue *lhs = ir_address_from_load_or_generate_local(proc, left); + irValue *rhs = ir_address_from_load_or_generate_local(proc, right); + + GB_ASSERT(is_type_vector(result)); + Type *elem_type = base_type(result)->Vector.elem; + + irValue *res = ir_add_local_generated(proc, result); + for (i32 i = 0; i < tl->Vector.count; i++) { + irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); + irValue *z = ir_emit_comp(proc, op_kind, x, y); + ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); + } + + ir_emit_comment(proc, str_lit("vector.comp.end")); + return ir_emit_load(proc, res); + } + + + return ir_emit(proc, ir_instr_binary_op(proc, op_kind, left, right, result)); +} + +irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index) { + GB_ASSERT(index != NULL); + Type *t = ir_type(s); + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_vector(st), "%s", type_to_string(st)); + + // NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32 + index = ir_emit_conv(proc, index, t_i32); + return ir_emit(proc, ir_instr_array_element_ptr(proc, s, index)); +} + +irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index) { + return ir_emit_array_ep(proc, s, ir_const_i32(proc->module->allocator, index)); +} + + + +irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { + gbAllocator a = proc->module->allocator; + Type *t = base_type(type_deref(ir_type(s))); + Type *result_type = NULL; + + if (is_type_struct(t)) { + GB_ASSERT(t->Record.field_count > 0); + GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); + result_type = make_type_pointer(a, t->Record.fields[index]->type); + } else if (is_type_union(t)) { + type_set_offsets(a, t); + GB_ASSERT(t->Record.field_count > 0); + if (index == -1) { + index = t->Record.field_count+1; + result_type = t_int_ptr; + } else { + GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); + result_type = make_type_pointer(a, t->Record.fields[index]->type); + } + } else if (is_type_tuple(t)) { + GB_ASSERT(t->Tuple.variable_count > 0); + GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); + result_type = make_type_pointer(a, t->Tuple.variables[index]->type); + } else if (is_type_complex(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = make_type_pointer(a, ft); break; + case 1: result_type = make_type_pointer(a, ft); break; + } + } else if (is_type_slice(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->Slice.elem)); break; + case 1: result_type = make_type_pointer(a, t_int); break; + case 2: result_type = make_type_pointer(a, t_int); break; + } + } else if (is_type_string(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, t_u8_ptr); break; + case 1: result_type = make_type_pointer(a, t_int); break; + } + } else if (is_type_any(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, t_rawptr); break; + case 1: result_type = make_type_pointer(a, t_type_info_ptr); break; + } + } else if (is_type_dynamic_array(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break; + case 1: result_type = t_int_ptr; break; + case 2: result_type = t_int_ptr; break; + case 3: result_type = t_allocator_ptr; break; + } + } else if (is_type_dynamic_map(t)) { + Type *gst = t->Map.generated_struct_type; + switch (index) { + case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->type); break; + case 1: result_type = make_type_pointer(a, gst->Record.fields[1]->type); break; + } + }else { + GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index); + } + + GB_ASSERT(result_type != NULL); + + return ir_emit(proc, ir_instr_struct_element_ptr(proc, s, index, result_type)); +} + + +irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { + // NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32 + + gbAllocator a = proc->module->allocator; + Type *t = base_type(ir_type(s)); + Type *result_type = NULL; + + if (is_type_struct(t)) { + GB_ASSERT(t->Record.field_count > 0); + GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); + result_type = t->Record.fields[index]->type; + } else if (is_type_union(t)) { + type_set_offsets(a, t); + if (index == -1) { + index = t->Record.field_count+1; + result_type = t_int_ptr; + } else { + GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); + } + result_type = t->Record.fields[index]->type; + } else if (is_type_tuple(t)) { + GB_ASSERT(t->Tuple.variable_count > 0); + GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); + result_type = t->Tuple.variables[index]->type; + } else if (is_type_complex(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + } + } else if (is_type_slice(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, t->Slice.elem); break; + case 1: result_type = t_int; break; + case 2: result_type = t_int; break; + } + } else if (is_type_string(t)) { + switch (index) { + case 0: result_type = t_u8_ptr; break; + case 1: result_type = t_int; break; + } + } else if (is_type_any(t)) { + switch (index) { + case 0: result_type = t_rawptr; break; + case 1: result_type = t_type_info_ptr; break; + } + } else if (is_type_dynamic_array(t)) { + switch (index) { + case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break; + case 1: result_type = t_int; break; + case 2: result_type = t_int; break; + case 3: result_type = t_allocator; break; + } + } else if (is_type_dynamic_map(t)) { + Type *gst = t->Map.generated_struct_type; + switch (index) { + case 0: result_type = gst->Record.fields[0]->type; break; + case 1: result_type = gst->Record.fields[1]->type; break; + } + } else { + GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index); + } + + GB_ASSERT(result_type != NULL); + + return ir_emit(proc, ir_instr_struct_extract_value(proc, s, index, result_type)); +} + + +irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { + GB_ASSERT(sel.index.count > 0); + Type *type = type_deref(ir_type(e)); + + for_array(i, sel.index) { + i32 index = cast(i32)sel.index.e[i]; + if (is_type_pointer(type)) { + type = type_deref(type); + e = ir_emit_load(proc, e); + e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? + } + type = core_type(type); + + + if (is_type_raw_union(type)) { + type = type->Record.fields[index]->type; + e = ir_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type)); + } else if (type->kind == Type_Record) { + if (index == -1) { + type = t_int; + } else { + type = type->Record.fields[index]->type; + } + e = ir_emit_struct_ep(proc, e, index); + } else if (type->kind == Type_Tuple) { + type = type->Tuple.variables[index]->type; + e = ir_emit_struct_ep(proc, e, index); + }else if (type->kind == Type_Basic) { + switch (type->Basic.kind) { + case Basic_any: { + if (index == 0) { + type = t_rawptr; + } else if (index == 1) { + type = t_type_info_ptr; + } + e = ir_emit_struct_ep(proc, e, index); + } break; + + case Basic_string: + e = ir_emit_struct_ep(proc, e, index); + break; + + default: + GB_PANIC("un-gep-able type"); + break; + } + } else if (type->kind == Type_Slice) { + e = ir_emit_struct_ep(proc, e, index); + } else if (type->kind == Type_DynamicArray) { + e = ir_emit_struct_ep(proc, e, index); + } else if (type->kind == Type_Vector) { + e = ir_emit_array_epi(proc, e, index); + } else if (type->kind == Type_Array) { + e = ir_emit_array_epi(proc, e, index); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ep(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ep(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ep(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator + } + } else { + GB_PANIC("un-gep-able type %s", type_to_string(type)); + } + } + + return e; +} + + +irValue *ir_emit_deep_field_ev(irProcedure *proc, irValue *e, Selection sel) { + GB_ASSERT(sel.index.count > 0); + Type *type = ir_type(e); + + for_array(i, sel.index) { + i32 index = cast(i32)sel.index.e[i]; + if (is_type_pointer(type)) { + type = type_deref(type); + e = ir_emit_load(proc, e); + e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? + } + type = base_type(type); + + + if (is_type_raw_union(type)) { + GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); + type = type->Record.fields[index]->type; + e = ir_emit_conv(proc, e, type); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ev(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ev(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ev(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ev(proc, e, 3); break; // allocator + } + } else { + e = ir_emit_struct_ev(proc, e, index); + } + } + + return e; +} + + + + + +irValue *ir_array_elem(irProcedure *proc, irValue *array) { + return ir_emit_array_ep(proc, array, v_zero32); +} +irValue *ir_array_len(irProcedure *proc, irValue *array) { + Type *t = base_type(ir_type(array)); + GB_ASSERT(t->kind == Type_Array); + return ir_const_int(proc->module->allocator, t->Array.count); +} + +irValue *ir_vector_elem(irProcedure *proc, irValue *vector) { + return ir_emit_array_ep(proc, vector, v_one32); +} + + +irValue *ir_slice_elem(irProcedure *proc, irValue *slice) { + Type *t = base_type(ir_type(slice)); + GB_ASSERT(t->kind == Type_Slice); + return ir_emit_struct_ev(proc, slice, 0); +} +irValue *ir_slice_count(irProcedure *proc, irValue *slice) { + Type *t = base_type(ir_type(slice)); + GB_ASSERT(t->kind == Type_Slice); + return ir_emit_struct_ev(proc, slice, 1); +} +irValue *ir_slice_capacity(irProcedure *proc, irValue *slice) { + Type *t = base_type(ir_type(slice)); + GB_ASSERT(t->kind == Type_Slice); + return ir_emit_struct_ev(proc, slice, 2); +} + +irValue *ir_dynamic_array_elem(irProcedure *proc, irValue *da) { + Type *t = ir_type(da); + GB_ASSERT(t->kind == Type_DynamicArray); + return ir_emit_struct_ev(proc, da, 0); +} +irValue *ir_dynamic_array_count(irProcedure *proc, irValue *da) { + Type *t = base_type(ir_type(da)); + GB_ASSERT_MSG(t->kind == Type_DynamicArray, "%s", type_to_string(t)); + return ir_emit_struct_ev(proc, da, 1); +} +irValue *ir_dynamic_array_capacity(irProcedure *proc, irValue *da) { + Type *t = base_type(ir_type(da)); + GB_ASSERT(t->kind == Type_DynamicArray); + return ir_emit_struct_ev(proc, da, 2); +} +irValue *ir_dynamic_array_allocator(irProcedure *proc, irValue *da) { + Type *t = base_type(ir_type(da)); + GB_ASSERT(t->kind == Type_DynamicArray); + return ir_emit_struct_ev(proc, da, 3); +} + + + +irValue *ir_string_elem(irProcedure *proc, irValue *string) { + Type *t = base_type(ir_type(string)); + GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string); + return ir_emit_struct_ev(proc, string, 0); +} +irValue *ir_string_len(irProcedure *proc, irValue *string) { + Type *t = base_type(ir_type(string)); + GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t)); + return ir_emit_struct_ev(proc, string, 1); +} + + +void ir_fill_slice(irProcedure *proc, irValue *slice_ptr, irValue *data, irValue *len, irValue *cap) { + Type *t = ir_type(slice_ptr); + GB_ASSERT(is_type_pointer(t)); + t = type_deref(t); + GB_ASSERT(is_type_slice(t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 0), data); + ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 1), len); + ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 2), cap); +} +void ir_fill_string(irProcedure *proc, irValue *string_ptr, irValue *data, irValue *len) { + Type *t = ir_type(string_ptr); + GB_ASSERT(is_type_pointer(t)); + t = type_deref(t); + GB_ASSERT(is_type_string(t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, string_ptr, 0), data); + ir_emit_store(proc, ir_emit_struct_ep(proc, string_ptr, 1), len); +} + +irValue *ir_emit_string(irProcedure *proc, irValue *elem, irValue *len) { + irValue *str = ir_add_local_generated(proc, t_string); + ir_fill_string(proc, str, elem, len); + return ir_emit_load(proc, str); +} + + + + +irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base, irValue *low, irValue *high, irValue *max) { + // TODO(bill): array bounds checking for slice creation + // TODO(bill): check that low < high <= max + gbAllocator a = proc->module->allocator; + Type *bt = base_type(ir_type(base)); + + if (low == NULL) { + low = v_zero; + } + if (high == NULL) { + switch (bt->kind) { + case Type_Array: high = ir_array_len(proc, base); break; + case Type_Slice: high = ir_slice_count(proc, base); break; + case Type_Pointer: high = v_one; break; + } + } + if (max == NULL) { + switch (bt->kind) { + case Type_Array: high = ir_array_len(proc, base); break; + case Type_Slice: high = ir_slice_capacity(proc, base); break; + case Type_Pointer: high = v_one; break; + } + } + + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); + irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int); + + irValue *elem = NULL; + switch (bt->kind) { + case Type_Array: elem = ir_array_elem(proc, base); break; + case Type_Slice: elem = ir_slice_elem(proc, base); break; + case Type_Pointer: elem = ir_emit_load(proc, base); break; + } + + elem = ir_emit_ptr_offset(proc, elem, low); + + irValue *slice = ir_add_local_generated(proc, slice_type); + ir_fill_slice(proc, slice, elem, len, cap); + return slice; +} + + + +String ir_lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { + Type *prev_src = src; + // Type *prev_dst = dst; + src = base_type(type_deref(src)); + // dst = base_type(type_deref(dst)); + bool src_is_ptr = src != prev_src; + // bool dst_is_ptr = dst != prev_dst; + + GB_ASSERT(is_type_struct(src) || is_type_union(src)); + for (isize i = 0; i < src->Record.field_count; i++) { + Entity *f = src->Record.fields[i]; + if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) { + if (are_types_identical(dst, f->type)) { + return f->token.string; + } + if (src_is_ptr && is_type_pointer(dst)) { + if (are_types_identical(type_deref(dst), f->type)) { + return f->token.string; + } + } + if (is_type_struct(f->type)) { + String name = ir_lookup_polymorphic_field(info, dst, f->type); + if (name.len > 0) { + return name; + } + } + } + } + return str_lit(""); +} + + + +irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { + Type *src_type = ir_type(value); + if (are_types_identical(t, src_type)) { + return value; + } + + Type *src = core_type(src_type); + Type *dst = core_type(t); + + + // if (is_type_untyped_nil(src) && type_has_nil(dst)) { + if (is_type_untyped_nil(src)) { + return ir_value_nil(proc->module->allocator, t); + } + + if (value->kind == irValue_Constant) { + if (is_type_any(dst)) { + irValue *default_value = ir_add_local_generated(proc, default_type(src_type)); + ir_emit_store(proc, default_value, value); + return ir_emit_conv(proc, ir_emit_load(proc, default_value), t_any); + } else if (dst->kind == Type_Basic) { + ExactValue ev = value->Constant.value; + if (is_type_float(dst)) { + ev = exact_value_to_float(ev); + } else if (is_type_complex(dst)) { + ev = exact_value_to_complex(ev); + } else if (is_type_string(dst)) { + // Handled elsewhere + GB_ASSERT(ev.kind == ExactValue_String); + } else if (is_type_integer(dst)) { + ev = exact_value_to_integer(ev); + } else if (is_type_pointer(dst)) { + // IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect `null` + irValue *i = ir_add_module_constant(proc->module, t_uint, ev); + return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, i, t_uint, dst)); + } + return ir_add_module_constant(proc->module, t, ev); + } + } + + if (are_types_identical(src, dst)) { + return value; + } + + // integer -> integer + if (is_type_integer(src) && is_type_integer(dst)) { + GB_ASSERT(src->kind == Type_Basic && + dst->kind == Type_Basic); + i64 sz = type_size_of(proc->module->allocator, default_type(src)); + i64 dz = type_size_of(proc->module->allocator, default_type(dst)); + irConvKind kind = irConv_trunc; + + if (dz < sz) { + kind = irConv_trunc; + } else if (dz == sz) { + // NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment + // NOTE(bill): Copy the value just for type correctness + kind = irConv_bitcast; + } else if (dz > sz) { + if (is_type_unsigned(src)) { + kind = irConv_zext; // zero extent + } else { + kind = irConv_sext; // sign extent + } + } + + return ir_emit(proc, ir_instr_conv(proc, kind, value, src_type, t)); + } + + // boolean -> integer + if (is_type_boolean(src) && is_type_integer(dst)) { + return ir_emit(proc, ir_instr_conv(proc, irConv_zext, value, src_type, t)); + } + + // integer -> boolean + if (is_type_integer(src) && is_type_boolean(dst)) { + return ir_emit_comp(proc, Token_NotEq, value, v_zero); + } + + + // float -> float + if (is_type_float(src) && is_type_float(dst)) { + gbAllocator a = proc->module->allocator; + i64 sz = type_size_of(proc->module->allocator, src); + i64 dz = type_size_of(proc->module->allocator, dst); + if (sz == 2) { + switch (dz) { + case 2: return value; + case 4: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__gnu_h2f_ieee", args, 1); + } break; + case 8: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__f16_to_f64", args, 1); + } break; + } + } else if (dz == 2) { + switch (sz) { + case 2: return value; + case 4: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__gnu_f2h_ieee", args, 1); + } break; + case 8: { + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = value; + return ir_emit_global_call(proc, "__truncdfhf2", args, 1); + } break; + } + } + + irConvKind kind = irConv_fptrunc; + if (dz >= sz) { + kind = irConv_fpext; + } + return ir_emit(proc, ir_instr_conv(proc, kind, value, src_type, t)); + } + + if (is_type_complex(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst); + irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), imag); + return ir_emit_load(proc, gen); + } + + // float <-> integer + if (is_type_float(src) && is_type_integer(dst)) { + irConvKind kind = irConv_fptosi; + if (is_type_unsigned(dst)) { + kind = irConv_fptoui; + } + return ir_emit(proc, ir_instr_conv(proc, kind, value, src_type, t)); + } + if (is_type_integer(src) && is_type_float(dst)) { + irConvKind kind = irConv_sitofp; + if (is_type_unsigned(src)) { + kind = irConv_uitofp; + } + return ir_emit(proc, ir_instr_conv(proc, kind, value, src_type, t)); + } + + // Pointer <-> int + if (is_type_pointer(src) && is_type_int_or_uint(dst)) { + return ir_emit(proc, ir_instr_conv(proc, irConv_ptrtoint, value, src_type, t)); + } + if (is_type_int_or_uint(src) && is_type_pointer(dst)) { + return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, value, src_type, t)); + } + + if (is_type_union(dst)) { + for (isize i = 1; i < dst->Record.variant_count; i++) { + Entity *f = dst->Record.variants[i]; + if (are_types_identical(f->type, src_type)) { + ir_emit_comment(proc, str_lit("union - child to parent")); + gbAllocator a = proc->module->allocator; + irValue *parent = ir_add_local_generated(proc, t); + irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(a, f->type)); + ir_emit_store(proc, underlying, value); + + irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); + ir_emit_store(proc, tag_ptr, ir_const_int(a, i)); + + return ir_emit_load(proc, parent); + } + } + } + + // NOTE(bill): This has to be done before `Pointer <-> Pointer` as it's + // subtype polymorphism casting + if (check_is_assignable_to_using_subtype(src_type, t)) { + Type *st = type_deref(src_type); + Type *pst = st; + st = type_deref(st); + + bool st_is_ptr = st != pst; + st = base_type(st); + + Type *dt = t; + bool dt_is_ptr = is_type_pointer(dt); + + GB_ASSERT(is_type_struct(st) || is_type_union(st)); + String field_name = ir_lookup_polymorphic_field(proc->module->info, t, st); + // gb_printf("field_name: %.*s\n", LIT(field_name)); + if (field_name.len > 0) { + // NOTE(bill): It can be casted + Selection sel = lookup_field(proc->module->allocator, st, field_name, false); + if (sel.entity != NULL) { + ir_emit_comment(proc, str_lit("cast - polymorphism")); + if (st_is_ptr) { + irValue *res = ir_emit_deep_field_gep(proc, value, sel); + if (!dt_is_ptr) { + res = ir_emit_load(proc, res); + } + return res; + } else { + if (is_type_pointer(ir_type(value))) { + if (!dt_is_ptr) { + value = ir_emit_load(proc, value); + } else { + value = ir_emit_deep_field_gep(proc, value, sel); + return ir_emit_load(proc, value); + } + } + + return ir_emit_deep_field_ev(proc, value, sel); + + } + } + } + } + + + + // Pointer <-> Pointer + if (is_type_pointer(src) && is_type_pointer(dst)) { + return ir_emit_bitcast(proc, value, t); + } + + + + // proc <-> proc + if (is_type_proc(src) && is_type_proc(dst)) { + return ir_emit_bitcast(proc, value, t); + } + + // pointer -> proc + if (is_type_pointer(src) && is_type_proc(dst)) { + return ir_emit_bitcast(proc, value, t); + } + // proc -> pointer + if (is_type_proc(src) && is_type_pointer(dst)) { + return ir_emit_bitcast(proc, value, t); + } + + + + // []byte/[]u8 <-> string + if (is_type_u8_slice(src) && is_type_string(dst)) { + irValue *elem = ir_slice_elem(proc, value); + irValue *len = ir_slice_count(proc, value); + return ir_emit_string(proc, elem, len); + } + if (is_type_string(src) && is_type_u8_slice(dst)) { + irValue *elem = ir_string_elem(proc, value); + irValue *elem_ptr = ir_add_local_generated(proc, ir_type(elem)); + ir_emit_store(proc, elem_ptr, elem); + + irValue *len = ir_string_len(proc, value); + irValue *cap = len; + irValue *slice = ir_add_local_slice(proc, t, elem_ptr, v_zero, len, cap); + return ir_emit_load(proc, slice); + } + + if (is_type_vector(dst)) { + Type *dst_elem = dst->Vector.elem; + value = ir_emit_conv(proc, value, dst_elem); + irValue *v = ir_add_local_generated(proc, t); + isize index_count = dst->Vector.count; + + for (i32 i = 0; i < index_count; i++) { + irValue *elem = ir_emit_array_epi(proc, v, i); + ir_emit_store(proc, elem, value); + } + return ir_emit_load(proc, v); + } + + if (is_type_any(dst)) { + irValue *result = ir_add_local_generated(proc, t_any); + + if (is_type_untyped_nil(src)) { + return ir_emit_load(proc, result); + } + + Type *st = default_type(src_type); + + irValue *data = NULL; + if (value->kind == irValue_Instr && + value->Instr.kind == irInstr_Load) { + // NOTE(bill): Addreirble value + data = value->Instr.Load.address; + } else { + // NOTE(bill): Non-addreirble value + data = ir_add_local_generated(proc, st); + ir_emit_store(proc, data, value); + } + GB_ASSERT(is_type_pointer(ir_type(data))); + GB_ASSERT_MSG(is_type_typed(st), "%s", type_to_string(st)); + data = ir_emit_conv(proc, data, t_rawptr); + + + irValue *ti = ir_type_info(proc, st); + + ir_emit_store(proc, ir_emit_struct_ep(proc, result, 0), data); + ir_emit_store(proc, ir_emit_struct_ep(proc, result, 1), ti); + + return ir_emit_load(proc, result); + } + + + gb_printf_err("ir_emit_conv: src -> dst\n"); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); + + + GB_PANIC("Invalid type conversion: `%s` to `%s` for procedure `%.*s`", + type_to_string(src_type), type_to_string(t), + LIT(proc->name)); + + return NULL; +} + +bool ir_is_type_aggregate(Type *t) { + t = base_type(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + case Basic_any: + return true; + + // case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + return true; + } + break; + + case Type_Pointer: + return false; + + case Type_Vector: + case Type_Array: + case Type_Slice: + case Type_Record: + case Type_Tuple: + case Type_DynamicArray: + case Type_Map: + case Type_BitField: + return true; + + case Type_Named: + return ir_is_type_aggregate(t->Named.base); + } + + return false; +} + +irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) { + Type *src_type = ir_type(value); + if (are_types_identical(t, src_type)) { + return value; + } + + Type *src = base_type(src_type); + Type *dst = base_type(t); +#if 0 + if (are_types_identical(t, src_type)) { + return value; + } +#endif + irModule *m = proc->module; + + i64 sz = type_size_of(m->allocator, src); + i64 dz = type_size_of(m->allocator, dst); + + GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); + + if (ir_is_type_aggregate(src) || ir_is_type_aggregate(dst)) { + irValue *s = ir_address_from_load_or_generate_local(proc, value); + irValue *d = ir_emit_bitcast(proc, s, make_type_pointer(m->allocator, t)); + return ir_emit_load(proc, d); + } + + // TODO(bill): Actually figure out what the conversion needs to be correctly 'cause LLVM + + return ir_emit_bitcast(proc, value, dst); +} + +irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) { + GB_ASSERT(is_type_pointer(ir_type(value))); + gbAllocator allocator = proc->module->allocator; + + String field_name = check_down_cast_name(t, type_deref(ir_type(value))); + GB_ASSERT(field_name.len > 0); + Selection sel = lookup_field(proc->module->allocator, t, field_name, false); + irValue *bytes = ir_emit_conv(proc, value, t_u8_ptr); + + i64 offset_ = type_offset_of_from_selection(allocator, type_deref(t), sel); + irValue *offset = ir_const_int(allocator, -offset_); + irValue *head = ir_emit_ptr_offset(proc, bytes, offset); + return ir_emit_conv(proc, head, t); +} + +irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) { + gbAllocator a = proc->module->allocator; + + Type *src_type = ir_type(value); + 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(a, type); + } + + irValue *v = ir_add_local_generated(proc, tuple); + + if (is_ptr) { + Type *src = base_type(type_deref(src_type)); + Type *src_ptr = src_type; + GB_ASSERT(is_type_union(src)); + Type *dst_ptr = tuple->Tuple.variables[0]->type; + Type *dst = type_deref(dst_ptr); + + irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value)); + irValue *dst_tag = NULL; + for (isize i = 1; i < src->Record.variant_count; i++) { + Entity *f = src->Record.variants[i]; + if (are_types_identical(f->type, dst)) { + dst_tag = ir_const_int(a, i); + break; + } + } + GB_ASSERT(dst_tag != NULL); + + irBlock *ok_block = ir_new_block(proc, NULL, "union_cast.ok"); + irBlock *end_block = ir_new_block(proc, NULL, "union_cast.end"); + irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag); + ir_emit_if(proc, cond, ok_block, end_block); + ir_start_block(proc, ok_block); + + irValue *gep0 = ir_emit_struct_ep(proc, v, 0); + irValue *gep1 = ir_emit_struct_ep(proc, v, 1); + + irValue *data = ir_emit_conv(proc, value, dst_ptr); + ir_emit_store(proc, gep0, data); + ir_emit_store(proc, gep1, v_true); + + ir_emit_jump(proc, end_block); + ir_start_block(proc, end_block); + + } else { + Type *src = base_type(src_type); + GB_ASSERT(is_type_union(src)); + Type *dst = tuple->Tuple.variables[0]->type; + Type *dst_ptr = make_type_pointer(a, dst); + + irValue *value_ = ir_address_from_load_or_generate_local(proc, value); + + irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_)); + irValue *dst_tag = NULL; + for (isize i = 1; i < src->Record.variant_count; i++) { + Entity *f = src->Record.variants[i]; + if (are_types_identical(f->type, dst)) { + dst_tag = ir_const_int(a, i); + break; + } + } + GB_ASSERT(dst_tag != NULL); + + irBlock *ok_block = ir_new_block(proc, NULL, "union_cast.ok"); + irBlock *end_block = ir_new_block(proc, NULL, "union_cast.end"); + irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag); + ir_emit_if(proc, cond, ok_block, end_block); + ir_start_block(proc, ok_block); + + irValue *gep0 = ir_emit_struct_ep(proc, v, 0); + irValue *gep1 = ir_emit_struct_ep(proc, v, 1); + + irValue *data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0))); + ir_emit_store(proc, gep0, data); + ir_emit_store(proc, gep1, v_true); + + ir_emit_jump(proc, end_block); + ir_start_block(proc, end_block); + } + + if (!is_tuple) { + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; + + irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1)); + irValue **args = gb_alloc_array(a, irValue *, 6); + args[0] = ok; + + args[1] = ir_const_string(a, pos.file); + args[2] = ir_const_int(a, pos.line); + args[3] = ir_const_int(a, pos.column); + + args[4] = ir_type_info(proc, src_type); + args[5] = ir_type_info(proc, dst_type); + ir_emit_global_call(proc, "__type_assertion_check", args, 6); + + return ir_emit_load(proc, ir_emit_struct_ep(proc, v, 0)); + } + return ir_emit_load(proc, v); +} + +irAddr ir_emit_any_cast_addr(irProcedure *proc, irValue *value, Type *type, TokenPos pos) { + gbAllocator a = proc->module->allocator; + Type *src_type = ir_type(value); + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(a, type); + } + Type *dst_type = tuple->Tuple.variables[0]->type; + + irValue *v = ir_add_local_generated(proc, tuple); + + irValue *ti_ptr = ir_type_info(proc, dst_type); + irValue *any_ti = ir_emit_struct_ev(proc, value, 1); + + + irBlock *ok_block = ir_new_block(proc, NULL, "any_cast.ok"); + irBlock *end_block = ir_new_block(proc, NULL, "any_cast.end"); + irValue *cond = ir_emit_comp(proc, Token_CmpEq, any_ti, ti_ptr); + ir_emit_if(proc, cond, ok_block, end_block); + ir_start_block(proc, ok_block); + + irValue *gep0 = ir_emit_struct_ep(proc, v, 0); + irValue *gep1 = ir_emit_struct_ep(proc, v, 1); + + irValue *any_data = ir_emit_struct_ev(proc, value, 0); + irValue *ptr = ir_emit_conv(proc, any_data, make_type_pointer(a, dst_type)); + ir_emit_store(proc, gep0, ir_emit_load(proc, ptr)); + ir_emit_store(proc, gep1, v_true); + + ir_emit_jump(proc, end_block); + ir_start_block(proc, end_block); + + if (!is_tuple) { + // NOTE(bill): Panic on invalid conversion + + irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1)); + irValue **args = gb_alloc_array(a, irValue *, 6); + args[0] = ok; + + args[1] = ir_const_string(a, pos.file); + args[2] = ir_const_int(a, pos.line); + args[3] = ir_const_int(a, pos.column); + + args[4] = any_ti; + args[5] = ti_ptr; + ir_emit_global_call(proc, "__type_assertion_check", args, 6); + + return ir_addr(ir_emit_struct_ep(proc, v, 0)); + } + return ir_addr(v); +} +irValue *ir_emit_any_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) { + return ir_addr_load(proc, ir_emit_any_cast_addr(proc, value, type, pos)); +} + + + +isize ir_type_info_index(CheckerInfo *info, Type *type) { + type = default_type(type); + + isize entry_index = -1; + HashKey key = hash_pointer(type); + isize *found_entry_index = map_isize_get(&info->type_info_map, key); + if (found_entry_index) { + entry_index = *found_entry_index; + } + if (entry_index < 0) { + // NOTE(bill): Do manual search + // TODO(bill): This is O(n) and can be very slow + for_array(i, info->type_info_map.entries){ + MapIsizeEntry *e = &info->type_info_map.entries.e[i]; + Type *prev_type = cast(Type *)e->key.ptr; + if (are_types_identical(prev_type, type)) { + entry_index = e->value; + // NOTE(bill): Add it to the search map + map_isize_set(&info->type_info_map, key, entry_index); + break; + } + } + } + + if (entry_index < 0) { + compiler_error("TypeInfo for `%s` could not be found", type_to_string(type)); + } + return entry_index; +} + + +// TODO(bill): Try and make a lot of this constant aggregate literals in LLVM IR +gb_global irValue *ir_global_type_info_data = NULL; +gb_global irValue *ir_global_type_info_member_types = NULL; +gb_global irValue *ir_global_type_info_member_names = NULL; +gb_global irValue *ir_global_type_info_member_offsets = NULL; +gb_global irValue *ir_global_type_info_member_usings = NULL; + +gb_global i32 ir_global_type_info_data_index = 0; +gb_global i32 ir_global_type_info_member_types_index = 0; +gb_global i32 ir_global_type_info_member_names_index = 0; +gb_global i32 ir_global_type_info_member_offsets_index = 0; +gb_global i32 ir_global_type_info_member_usings_index = 0; + + +irValue *ir_type_info(irProcedure *proc, Type *type) { + CheckerInfo *info = proc->module->info; + + type = default_type(type); + + i32 entry_index = ir_type_info_index(info, type); + + // gb_printf_err("%d %s\n", entry_index, type_to_string(type)); + + return ir_emit_array_ep(proc, ir_global_type_info_data, ir_const_i32(proc->module->allocator, entry_index)); +} + + + +irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { + ast_node(be, BinaryExpr, expr); +#if 0 + irBlock *true_ = ir_new_block(proc, NULL, "logical.cmp.true"); + irBlock *false_ = ir_new_block(proc, NULL, "logical.cmp.false"); + irBlock *done = ir_new_block(proc, NULL, "logical.cmp.done"); + + irValue *result = ir_add_local_generated(proc, t_bool); + ir_build_cond(proc, expr, true_, false_); + + ir_start_block(proc, true_); + ir_emit_store(proc, result, v_true); + ir_emit_jump(proc, done); + + ir_start_block(proc, false_); + ir_emit_store(proc, result, v_false); + ir_emit_jump(proc, done); + + ir_start_block(proc, done); + + return ir_emit_load(proc, result); +#else + irBlock *rhs = ir_new_block(proc, NULL, "logical.cmp.rhs"); + irBlock *done = ir_new_block(proc, NULL, "logical.cmp.done"); + + Type *type = type_of_expr(proc->module->info, expr); + type = default_type(type); + + irValue *short_circuit = NULL; + if (be->op.kind == Token_CmpAnd) { + ir_build_cond(proc, be->left, rhs, done); + short_circuit = v_false; + } else if (be->op.kind == Token_CmpOr) { + ir_build_cond(proc, be->left, done, rhs); + short_circuit = v_true; + } + + if (rhs->preds.count == 0) { + ir_start_block(proc, done); + return short_circuit; + } + + if (done->preds.count == 0) { + ir_start_block(proc, rhs); + return ir_build_expr(proc, be->right); + } + + irValueArray edges = {}; + array_init_reserve(&edges, proc->module->allocator, done->preds.count+1); + for_array(i, done->preds) { + array_add(&edges, short_circuit); + } + + ir_start_block(proc, rhs); + array_add(&edges, ir_build_expr(proc, be->right)); + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + return ir_emit(proc, ir_instr_phi(proc, edges, type)); +#endif +} + + +void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValue *len) { + if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { + return; + } + + index = ir_emit_conv(proc, index, t_int); + len = ir_emit_conv(proc, len, t_int); + + ir_emit(proc, ir_instr_bounds_check(proc, token.pos, index, len)); +} + +void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *max, bool is_substring) { + if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { + return; + } + + low = ir_emit_conv(proc, low, t_int); + high = ir_emit_conv(proc, high, t_int); + + ir_emit(proc, ir_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring)); +} + + + +//////////////////////////////////////////////////////////////// +// +// @Build +// +//////////////////////////////////////////////////////////////// + +String ir_mangle_name(irGen *s, String path, Entity *e) { + // NOTE(bill): prefix names not in the init scope + // TODO(bill): make robust and not just rely on the file's name + String name = e->token.string; + irModule *m = &s->module; + CheckerInfo *info = m->info; + gbAllocator a = m->allocator; + AstFile *file = *map_ast_file_get(&info->files, hash_string(path)); + + char *str = gb_alloc_array(a, char, path.len+1); + gb_memmove(str, path.text, path.len); + str[path.len] = 0; + for (isize i = 0; i < path.len; i++) { + if (str[i] == '\\') { + str[i] = '/'; + } + } + + char const *base = gb_path_base_name(str); + char const *ext = gb_path_extension(base); + isize base_len = ext-1-base; + + isize max_len = base_len + 1 + 1 + 10 + 1 + name.len; + bool is_overloaded = check_is_entity_overloaded(e); + if (is_overloaded) { + max_len += 21; + } + + u8 *new_name = gb_alloc_array(a, u8, max_len); + isize new_name_len = 0; + if ((base_len > 0 && gb_char_is_digit(base[0])) || + base_len == 0) { + new_name_len = gb_snprintf( + cast(char *)new_name, max_len, + "_%.*s-%u.%.*s", + cast(int)base_len, base, + file->id, + LIT(name)); + } else { + new_name_len = gb_snprintf( + cast(char *)new_name, max_len, + "%.*s-%u.%.*s", + cast(int)base_len, base, + file->id, + LIT(name)); + } + if (is_overloaded) { + char *str = cast(char *)new_name + new_name_len-1; + isize len = max_len-new_name_len; + isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); + new_name_len += extra-1; + } + + return make_string(new_name, new_name_len-1); +} + + +void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) { + if (field->kind != Entity_TypeName) { + return; + } + + String cn = field->token.string; + isize len = parent.len + 1 + 16 + 1 + cn.len; + u8 *text = gb_alloc_array(m->allocator, u8, len); + isize new_name_len = gb_snprintf(cast(char *)text, len, + "%.*s.%.*s", LIT(parent), LIT(cn)); + + String child = {text, new_name_len-1}; + map_string_set(&m->entity_names, hash_pointer(field), child); + ir_gen_global_type_name(m, field, child); +} + + +irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) { + GB_ASSERT(ident->kind == AstNode_Ident); + Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(ident)); + GB_ASSERT(found != NULL); + Entity *e = *found; + GB_ASSERT(e->kind == Entity_Label); + for_array(i, proc->branch_blocks) { + irBranchBlocks *b = &proc->branch_blocks.e[i]; + if (b->label == e->Label.node) { + return *b; + } + } + + GB_PANIC("Unreachable"); + return irBranchBlocks{}; +} + + +void ir_push_target_list(irProcedure *proc, AstNode *label, irBlock *break_, irBlock *continue_, irBlock *fallthrough_) { + irTargetList *tl = gb_alloc_item(proc->module->allocator, irTargetList); + tl->prev = proc->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + proc->target_list = tl; + + if (label != NULL) { // Set label blocks + GB_ASSERT(label->kind == AstNode_Label); + + for_array(i, proc->branch_blocks) { + irBranchBlocks *b = &proc->branch_blocks.e[i]; + GB_ASSERT(b->label != NULL && label != NULL); + GB_ASSERT(b->label->kind == AstNode_Label); + if (b->label == label) { + b->break_ = break_; + b->continue_ = continue_; + return; + } + } + + GB_PANIC("ir_set_label_blocks: Unreachable"); + } +} + +void ir_pop_target_list(irProcedure *proc) { + proc->target_list = proc->target_list->prev; +} + + +void ir_gen_global_type_name(irModule *m, Entity *e, String name) { + irValue *t = ir_value_type_name(m->allocator, name, e->type); + ir_module_add_value(m, e, t); + map_ir_value_set(&m->members, hash_string(name), t); + + if (is_type_union(e->type)) { + Type *bt = base_type(e->type); + // NOTE(bill): Zeroth entry is null (for `match type` stmts) + for (isize j = 1; j < bt->Record.variant_count; j++) { + ir_mangle_add_sub_type_name(m, bt->Record.variants[j], name); + } + } +} + + + + +void ir_build_defer_stmt(irProcedure *proc, irDefer d) { + irBlock *b = ir_new_block(proc, NULL, "defer"); + // NOTE(bill): The prev block may defer injection before it's terminator + irInstr *last_instr = ir_get_last_instr(proc->curr_block); + if (last_instr == NULL || !ir_is_instr_terminating(last_instr)) { + ir_emit_jump(proc, b); + } + ir_start_block(proc, b); + ir_emit_comment(proc, str_lit("defer")); + if (d.kind == irDefer_Node) { + ir_build_stmt(proc, d.stmt); + } else if (d.kind == irDefer_Instr) { + // NOTE(bill): Need to make a new copy + irValue *instr = cast(irValue *)gb_alloc_copy(proc->module->allocator, d.instr, gb_size_of(irValue)); + ir_emit(proc, instr); + } +} + + +irValue *ir_emit_clamp(irProcedure *proc, Type *t, irValue *x, irValue *min, irValue *max) { + irValue *cond = NULL; + ir_emit_comment(proc, str_lit("clamp")); + x = ir_emit_conv(proc, x, t); + min = ir_emit_conv(proc, min, t); + max = ir_emit_conv(proc, max, t); + + cond = ir_emit_comp(proc, Token_Gt, min, x); + x = ir_emit_select(proc, cond, min, x); + cond = ir_emit_comp(proc, Token_Lt, max, x); + x = ir_emit_select(proc, cond, max, x); + return x; +} + + +irValue *ir_find_global_variable(irProcedure *proc, String name) { + irValue **value = map_ir_value_get(&proc->module->members, hash_string(name)); + GB_ASSERT_MSG(value != NULL, "Unable to find global variable `%.*s`", LIT(name)); + return *value; +} + +void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts); + + +bool is_double_pointer(Type *t) { + if (!is_type_pointer(t)) { + return false; + } + Type *td = type_deref(t); + if (td == NULL || td == t) { + return false; + } + return is_type_pointer(td); +} + +irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { + expr = unparen_expr(expr); + + TypeAndValue tv = type_and_value_of_expr(proc->module->info, expr); + GB_ASSERT(tv.mode != Addressing_Invalid); + + if (tv.value.kind != ExactValue_Invalid) { + // NOTE(bill): Edge case + if (tv.value.kind != ExactValue_Compound && + is_type_vector(tv.type)) { + Type *elem = base_vector_type(tv.type); + ExactValue value = convert_exact_value_for_type(tv.value, elem); + irValue *x = ir_add_module_constant(proc->module, elem, value); + return ir_emit_conv(proc, x, tv.type); + } + + 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; + GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(token_strings[bl->kind])); + 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, Implicit, expr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + + case_ast_node(i, Ident, expr); + Entity *e = *map_entity_get(&proc->module->info->uses, hash_pointer(expr)); + if (e->kind == Entity_Builtin) { + Token token = ast_node_token(expr); + GB_PANIC("TODO(bill): ir_build_single_expr Entity_Builtin `%.*s`\n" + "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name), + LIT(token.pos.file), token.pos.line, token.pos.column); + return NULL; + } else if (e->kind == Entity_Nil) { + return ir_value_nil(proc->module->allocator, tv.type); + } + + irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e)); + if (found) { + irValue *v = *found; + if (v->kind == irValue_Proc) { + return v; + } + // if (e->kind == Entity_Variable && e->Variable.param) { + // return v; + // } + return ir_emit_load(proc, v); + } else if (e != NULL && e->kind == Entity_Variable) { + return ir_addr_load(proc, ir_build_addr(proc, expr)); + } + GB_PANIC("NULL value for expression from identifier: %.*s", LIT(i->string)); + return NULL; + case_end; + + case_ast_node(re, RunExpr, expr); + // TODO(bill): Run Expression + return ir_build_expr(proc, re->expr); + case_end; + + case_ast_node(de, DerefExpr, expr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + + case_ast_node(se, SelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(proc->module->info, expr); + GB_ASSERT(tav.mode != Addressing_Invalid); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + + case_ast_node(te, TernaryExpr, expr); + ir_emit_comment(proc, str_lit("TernaryExpr")); + + irValueArray edges = {}; + array_init_reserve(&edges, proc->module->allocator, 2); + + GB_ASSERT(te->y != NULL); + irBlock *then = ir_new_block(proc, NULL, "if.then"); + irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later + irBlock *else_ = ir_new_block(proc, NULL, "if.else"); + + irValue *cond = ir_build_cond(proc, te->cond, then, else_); + ir_start_block(proc, then); + + Type *type = type_of_expr(proc->module->info, expr); + + ir_open_scope(proc); + array_add(&edges, ir_emit_conv(proc, ir_build_expr(proc, te->x), type)); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + ir_start_block(proc, else_); + + ir_open_scope(proc); + array_add(&edges, ir_emit_conv(proc, ir_build_expr(proc, te->y), type)); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + return ir_emit(proc, ir_instr_phi(proc, edges, type)); + case_end; + +#if 0 + case_ast_node(ie, IfExpr, expr); + ir_emit_comment(proc, str_lit("IfExpr")); + if (ie->init != NULL) { + irBlock *init = ir_new_block(proc, expr, "if.init"); + ir_emit_jump(proc, init); + ir_start_block(proc, init); + ir_build_stmt(proc, ie->init); + } + + irValueArray edges = {}; + array_init_reserve(&edges, proc->module->allocator, 2); + + GB_ASSERT(ie->else_expr != NULL); + irBlock *then = ir_new_block(proc, expr, "if.then"); + irBlock *done = ir_new_block(proc, expr, "if.done"); // NOTE(bill): Append later + irBlock *else_ = ir_new_block(proc, ie->else_expr, "if.else"); + + irValue *cond = ir_build_cond(proc, ie->cond, then, else_); + ir_start_block(proc, then); + + ir_open_scope(proc); + array_add(&edges, ir_build_expr(proc, ie->body)); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + ir_start_block(proc, else_); + + ir_open_scope(proc); + array_add(&edges, ir_build_expr(proc, ie->else_expr)); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + Type *type = type_of_expr(proc->module->info, expr); + + return ir_emit(proc, ir_instr_phi(proc, edges, type)); + case_end; +#endif + + case_ast_node(ta, TypeAssertion, expr); + TokenPos pos = ast_node_token(expr).pos; + Type *type = tv.type; + irValue *e = ir_build_expr(proc, ta->expr); + Type *t = type_deref(ir_type(e)); + if (is_type_union(t)) { + ir_emit_comment(proc, str_lit("cast - union_cast")); + return ir_emit_union_cast(proc, e, type, pos); + } else if (is_type_any(t)) { + ir_emit_comment(proc, str_lit("cast - any_cast")); + return ir_emit_any_cast(proc, e, type, pos); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(ir_type(e))); + } + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_And: + return ir_emit_ptr_offset(proc, ir_build_addr(proc, ue->expr).addr, v_zero); // Make a copy of the pointer + default: + return ir_emit_unary_arith(proc, ue->op.kind, ir_build_expr(proc, ue->expr), tv.type); + } + case_end; + + case_ast_node(be, BinaryExpr, expr); + irValue *left = ir_build_expr(proc, be->left); + 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_ModMod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: + case Token_Shl: + case Token_Shr: { + irValue *right = ir_build_expr(proc, be->right); + return ir_emit_arith(proc, be->op.kind, left, right, type); + } + + + case Token_CmpEq: + case Token_NotEq: + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: { + irValue *right = ir_build_expr(proc, be->right); + irValue *cmp = ir_emit_comp(proc, be->op.kind, left, right); + return ir_emit_conv(proc, cmp, type); + } break; + + case Token_CmpAnd: + case Token_CmpOr: + return ir_emit_logical_binary_expr(proc, expr); + + default: + GB_PANIC("Invalid binary expression"); + break; + } + case_end; + + case_ast_node(pl, ProcLit, expr); + // NOTE(bill): Generate a new name + // parent$count + isize name_len = proc->name.len + 1 + 8 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)proc->children.count); + String name = make_string(name_text, name_len-1); + + Type *type = type_of_expr(proc->module->info, expr); + irValue *value = ir_value_procedure(proc->module->allocator, + proc->module, NULL, type, pl->type, pl->body, name); + + value->Proc.tags = pl->tags; + value->Proc.parent = proc; + + array_add(&proc->children, &value->Proc); + array_add(&proc->module->procs_to_generate, value); + + return value; + case_end; + + + case_ast_node(cl, CompoundLit, expr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + + + case_ast_node(ce, CallExpr, expr); + if (map_tav_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + irValue *x = ir_build_expr(proc, ce->args.e[0]); + irValue *y = ir_emit_conv(proc, x, tv.type); + return y; + } + + AstNode *p = unparen_expr(ce->proc); + if (p->kind == AstNode_Ident) { + Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(p)); + if (found && (*found)->kind == Entity_Builtin) { + Entity *e = *found; + switch (e->Builtin.id) { + case BuiltinProc_type_info: { + Type *t = default_type(type_of_expr(proc->module->info, ce->args.e[0])); + return ir_type_info(proc, t); + } break; + case BuiltinProc_type_info_of_val: { + Type *t = default_type(type_of_expr(proc->module->info, ce->args.e[0])); + return ir_type_info(proc, t); + } break; + + case BuiltinProc_transmute: { + irValue *x = ir_build_expr(proc, ce->args.e[1]); + return ir_emit_transmute(proc, x, tv.type); + } + + case BuiltinProc_len: { + irValue *v = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(ir_type(v)); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = ir_emit_load(proc, v); + t = type_deref(t); + } + if (is_type_string(t)) { + return ir_string_len(proc, v); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_vector(t)) { + GB_PANIC("Vector lengths are constant"); + } else if (is_type_slice(t)) { + return ir_slice_count(proc, v); + } else if (is_type_dynamic_array(t)) { + return ir_dynamic_array_count(proc, v); + } else if (is_type_dynamic_map(t)) { + ir_emit_comment(proc, str_lit("len: map")); + irValue *entries = ir_emit_struct_ev(proc, v, 1); + return ir_dynamic_array_count(proc, entries); + } + + GB_PANIC("Unreachable"); + } break; + + case BuiltinProc_cap: { + irValue *v = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(ir_type(v)); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = ir_emit_load(proc, v); + t = type_deref(t); + } + if (is_type_string(t)) { + GB_PANIC("Unreachable"); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_vector(t)) { + GB_PANIC("Unreachable"); + } else if (is_type_slice(t)) { + return ir_slice_capacity(proc, v); + } else if (is_type_dynamic_array(t)) { + return ir_dynamic_array_capacity(proc, v); + } else if (is_type_map(t)) { + irValue *entries = ir_emit_struct_ev(proc, v, 1); + return ir_dynamic_array_capacity(proc, entries); + } + + GB_PANIC("Unreachable"); + + } break; + + case BuiltinProc_new: { + ir_emit_comment(proc, str_lit("new")); + // new :: proc(Type) -> ^Type + gbAllocator allocator = proc->module->allocator; + + Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + Type *ptr_type = make_type_pointer(allocator, type); + + i64 s = type_size_of(allocator, type); + i64 a = type_align_of(allocator, type); + + irValue **args = gb_alloc_array(allocator, irValue *, 2); + args[0] = ir_const_int(allocator, s); + args[1] = ir_const_int(allocator, a); + irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2); + irValue *v = ir_emit_conv(proc, call, ptr_type); + return v; + } break; + + #if 0 + case BuiltinProc_new_slice: { + ir_emit_comment(proc, str_lit("new_slice")); + // new_slice :: proc(Type, len: int) -> []Type + // new_slice :: proc(Type, len, cap: int) -> []Type + gbAllocator allocator = proc->module->allocator; + + Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + Type *ptr_type = make_type_pointer(allocator, type); + Type *slice_type = make_type_slice(allocator, type); + + i64 s = type_size_of(allocator, type); + i64 a = type_align_of(allocator, type); + + irValue *elem_size = ir_const_int(allocator, s); + irValue *elem_align = ir_const_int(allocator, a); + + irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *capacity = count; + + if (ce->args.count == 3) { + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); + + irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); + + irValue **args = gb_alloc_array(allocator, irValue *, 2); + args[0] = slice_size; + args[1] = elem_align; + irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2); + + irValue *ptr = ir_emit_conv(proc, call, ptr_type); + irValue *slice = ir_add_local_generated(proc, slice_type); + + ir_fill_slice(proc, slice, ptr, count, capacity); + return ir_emit_load(proc, slice); + } break; + #endif + case BuiltinProc_make: { + ir_emit_comment(proc, str_lit("make")); + gbAllocator a = proc->module->allocator; + Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + + if (is_type_slice(type)) { + Type *elem_type = core_type(type)->Slice.elem; + Type *elem_ptr_type = make_type_pointer(a, elem_type); + + irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type)); + irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type)); + + irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *capacity = count; + + if (ce->args.count == 3) { + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); + + irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); + + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = slice_size; + args[1] = elem_align; + irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2); + + irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type); + irValue *slice = ir_add_local_generated(proc, type); + + ir_fill_slice(proc, slice, ptr, count, capacity); + return ir_emit_load(proc, slice); + } else if (is_type_dynamic_map(type)) { + irValue *int_16 = ir_const_int(a, 16); + irValue *cap = int_16; + if (ce->args.count == 2) { + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + } + + irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero); + cap = ir_emit_select(proc, cond, cap, int_16); + + irValue *map = ir_add_local_generated(proc, type); + irValue *header = ir_gen_map_header(proc, map, base_type(type)); + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = header; + args[1] = cap; + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + + return ir_emit_load(proc, map); + } else if (is_type_dynamic_array(type)) { + Type *elem_type = base_type(type)->DynamicArray.elem; + irValue *len = v_zero; + if (ce->args.count > 1) { + len = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + } + irValue *cap = len; + if (ce->args.count > 2) { + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[0]), v_zero, len, cap, false); + + irValue *array = ir_add_local_generated(proc, type); + irValue **args = gb_alloc_array(a, irValue *, 5); + args[0] = ir_emit_conv(proc, array, t_rawptr); + args[1] = ir_const_int(a, type_size_of(a, elem_type)); + args[2] = ir_const_int(a, type_align_of(a, elem_type));; + args[3] = len; + args[4] = cap; + ir_emit_global_call(proc, "__dynamic_array_make", args, 5); + + return ir_emit_load(proc, array); + } + } break; + + case BuiltinProc_free: { + ir_emit_comment(proc, str_lit("free")); + + gbAllocator a = proc->module->allocator; + + AstNode *node = ce->args.e[0]; + TypeAndValue tav = type_and_value_of_expr(proc->module->info, node); + Type *type = base_type(tav.type); + + if (is_type_dynamic_array(type)) { + irValue *val = ir_build_expr(proc, node); + irValue *da_allocator = ir_emit_struct_ev(proc, val, 3); + + irValue *ptr = ir_emit_struct_ev(proc, val, 0); + ptr = ir_emit_conv(proc, ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = da_allocator; + args[1] = ptr; + return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); + } else if (is_type_dynamic_map(type)) { + irValue *map = ir_build_expr(proc, node); + irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map); + + { + irValue *array = ir_emit_struct_ep(proc, map_ptr, 0); + + irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); + irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); + da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = da_allocator; + args[1] = da_ptr; + ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); + } + { + irValue *array = ir_emit_struct_ep(proc, map_ptr, 1); + + irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); + irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); + da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = da_allocator; + args[1] = da_ptr; + ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); + } + return NULL; + } + + irValue *val = ir_build_expr(proc, node); + irValue *ptr = NULL; + if (is_type_pointer(type)) { + ptr = val; + } else if (is_type_slice(type)) { + ptr = ir_slice_elem(proc, val); + } else if (is_type_string(type)) { + ptr = ir_string_elem(proc, val); + } else { + GB_PANIC("Invalid type to `free`"); + } + + if (ptr == NULL) { + return NULL; + } + + ptr = ir_emit_conv(proc, ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = ptr; + return ir_emit_global_call(proc, "free_ptr", args, 1); + } break; + + case BuiltinProc_reserve: { + ir_emit_comment(proc, str_lit("reserve")); + gbAllocator a = proc->module->allocator; + + irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr; + Type *type = ir_type(ptr); + GB_ASSERT(is_type_pointer(type)); + type = base_type(type_deref(type)); + + irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + + if (is_type_dynamic_array(type)) { + Type *elem = type->DynamicArray.elem; + + irValue *elem_size = ir_const_int(a, type_size_of(a, elem)); + irValue *elem_align = ir_const_int(a, type_align_of(a, elem)); + + ptr = ir_emit_conv(proc, ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ptr; + args[1] = elem_size; + args[2] = elem_align; + args[3] = capacity; + return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4); + } else if (is_type_dynamic_map(type)) { + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = ir_gen_map_header(proc, ptr, type); + args[1] = capacity; + return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + } else { + GB_PANIC("Unknown type for `reserve`"); + } + } break; + + case BuiltinProc_clear: { + ir_emit_comment(proc, str_lit("clear")); + Type *original_type = type_of_expr(proc->module->info, ce->args.e[0]); + irAddr addr = ir_build_addr(proc, ce->args.e[0]); + irValue *ptr = addr.addr; + if (is_double_pointer(ir_type(ptr))) { + ptr = ir_addr_load(proc, addr); + } + Type *t = base_type(type_deref(original_type)); + if (is_type_dynamic_array(t)) { + irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, count_ptr, v_zero); + } else if (is_type_dynamic_map(t)) { + irValue *ha = ir_emit_struct_ep(proc, ptr, 0); + irValue *ea = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero); + ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero); + } else if (is_type_slice(t)) { + irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, count_ptr, v_zero); + } else { + GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t)); + } + return NULL; + } break; + + case BuiltinProc_append: { + ir_emit_comment(proc, str_lit("append")); + gbAllocator a = proc->module->allocator; + + Type *value_type = type_of_expr(proc->module->info, ce->args.e[0]); + irAddr array_addr = ir_build_addr(proc, ce->args.e[0]); + irValue *array_ptr = array_addr.addr; + if (is_double_pointer(ir_type(array_ptr))) { + array_ptr = ir_addr_load(proc, array_addr); + } + Type *type = ir_type(array_ptr); + { + TokenPos pos = ast_node_token(ce->args.e[0]).pos; + GB_ASSERT_MSG(is_type_pointer(type), "%.*s(%td) %s", + LIT(pos.file), pos.line, + type_to_string(type)); + } + type = base_type(type_deref(type)); + Type *elem_type = NULL; + bool is_slice = false; + if (is_type_dynamic_array(type)) { + elem_type = type->DynamicArray.elem; + } else if (is_type_slice(type)) { + is_slice = true; + elem_type = type->Slice.elem; + } else { + GB_PANIC("Invalid type to append"); + } + + irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type)); + irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type)); + + array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr); + + isize arg_index = 0; + isize arg_count = 0; + for_array(i, ce->args) { + AstNode *a = ce->args.e[i]; + Type *at = base_type(type_of_expr(proc->module->info, a)); + if (at->kind == Type_Tuple) { + arg_count += at->Tuple.variable_count; + } else { + arg_count++; + } + } + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count); + bool vari_expand = ce->ellipsis.pos.line != 0; + + for_array(i, ce->args) { + irValue *a = ir_build_expr(proc, ce->args.e[i]); + Type *at = ir_type(a); + if (at->kind == Type_Tuple) { + for (isize i = 0; i < at->Tuple.variable_count; i++) { + Entity *e = at->Tuple.variables[i]; + irValue *v = ir_emit_struct_ev(proc, a, i); + args[arg_index++] = v; + } + } else { + args[arg_index++] = a; + } + } + + if (!vari_expand) { + for (isize i = 1; i < arg_count; i++) { + args[i] = ir_emit_conv(proc, args[i], elem_type); + } + } + + if (!vari_expand) { + ir_emit_comment(proc, str_lit("variadic call argument generation")); + Type *slice_type = make_type_slice(a, elem_type); + irValue *slice = ir_add_local_generated(proc, slice_type); + isize slice_len = arg_count-1; + + if (slice_len > 0) { + irValue *base_array = ir_add_local_generated(proc, make_type_array(a, elem_type, slice_len)); + + for (isize i = 1; i < arg_count; i++) { + irValue *addr = ir_emit_array_epi(proc, base_array, i-1); + ir_emit_store(proc, addr, args[i]); + } + + irValue *base_elem = ir_emit_array_epi(proc, base_array, 0); + irValue *len = ir_const_int(a, slice_len); + ir_fill_slice(proc, slice, base_elem, len, len); + } + + arg_count = 2; + args[arg_count-1] = ir_emit_load(proc, slice); + } + + irValue *item_slice = args[1]; + irValue *items = ir_slice_elem(proc, item_slice); + irValue *item_count = ir_slice_count(proc, item_slice); + + irValue **daa_args = gb_alloc_array(a, irValue *, 5); + daa_args[0] = array_ptr; + daa_args[1] = elem_size; + daa_args[2] = elem_align; + daa_args[3] = ir_emit_conv(proc, items, t_rawptr); + daa_args[4] = ir_emit_conv(proc, item_count, t_int); + + if (is_slice) { + return ir_emit_global_call(proc, "__slice_append", daa_args, 5); + } + return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5); + } break; + + case BuiltinProc_delete: { + ir_emit_comment(proc, str_lit("delete")); + irValue *map = ir_build_expr(proc, ce->args.e[0]); + irValue *key = ir_build_expr(proc, ce->args.e[1]); + Type *map_type = ir_type(map); + GB_ASSERT(is_type_dynamic_map(map_type)); + Type *key_type = base_type(map_type)->Map.key; + + irValue *addr = ir_address_from_load_or_generate_local(proc, map); + + gbAllocator a = proc->module->allocator; + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = ir_gen_map_header(proc, addr, map_type); + args[1] = ir_gen_map_key(proc, key, key_type); + return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2); + } break; + + + case BuiltinProc_assert: { + ir_emit_comment(proc, str_lit("assert")); + irValue *cond = ir_build_expr(proc, ce->args.e[0]); + GB_ASSERT(is_type_boolean(ir_type(cond))); + + cond = ir_emit_comp(proc, Token_CmpEq, cond, v_false); + irBlock *err = ir_new_block(proc, NULL, "builtin.assert.err"); + irBlock *done = ir_new_block(proc, NULL, "builtin.assert.done"); + + ir_emit_if(proc, cond, err, done); + ir_start_block(proc, err); + + // TODO(bill): Cleanup allocations here + Token token = ast_node_token(ce->args.e[0]); + TokenPos pos = token.pos; + gbString expr = expr_to_string(ce->args.e[0]); + isize expr_len = gb_string_length(expr); + String expr_str = {}; + expr_str.text = cast(u8 *)gb_alloc_copy_align(proc->module->allocator, expr, expr_len, 1); + expr_str.len = expr_len; + gb_string_free(expr); + + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4); + args[0] = ir_const_string(proc->module->allocator, pos.file); + args[1] = ir_const_int(proc->module->allocator, pos.line); + args[2] = ir_const_int(proc->module->allocator, pos.column); + args[3] = ir_const_string(proc->module->allocator, expr_str); + ir_emit_global_call(proc, "__assert", args, 4); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + return cond; + } break; + + case BuiltinProc_panic: { + ir_emit_comment(proc, str_lit("panic")); + irValue *msg = ir_build_expr(proc, ce->args.e[0]); + GB_ASSERT(is_type_string(ir_type(msg))); + + Token token = ast_node_token(ce->args.e[0]); + TokenPos pos = token.pos; + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4); + args[0] = ir_const_string(proc->module->allocator, pos.file); + args[1] = ir_const_int(proc->module->allocator, pos.line); + args[2] = ir_const_int(proc->module->allocator, pos.column); + args[3] = msg; + ir_emit_global_call(proc, "__panic", args, 4); + + return NULL; + } break; + + + case BuiltinProc_copy: { + ir_emit_comment(proc, str_lit("copy")); + // copy :: proc(dst, src: []Type) -> int + AstNode *dst_node = ce->args.e[0]; + AstNode *src_node = ce->args.e[1]; + irValue *dst_slice = ir_build_expr(proc, dst_node); + irValue *src_slice = ir_build_expr(proc, src_node); + Type *slice_type = base_type(ir_type(dst_slice)); + GB_ASSERT(slice_type->kind == Type_Slice); + Type *elem_type = slice_type->Slice.elem; + i64 size_of_elem = type_size_of(proc->module->allocator, elem_type); + + irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr); + irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr); + + irValue *len_dst = ir_slice_count(proc, dst_slice); + irValue *len_src = ir_slice_count(proc, src_slice); + + irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src); + irValue *len = ir_emit_select(proc, cond, len_dst, len_src); + + irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem); + irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int); + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); + args[0] = dst; + args[1] = src; + args[2] = byte_count; + + ir_emit_global_call(proc, "__mem_copy", args, 3); + + return len; + } break; + case BuiltinProc_swizzle: { + ir_emit_comment(proc, str_lit("swizzle.begin")); + irAddr vector_addr = ir_build_addr(proc, ce->args.e[0]); + isize index_count = ce->args.count-1; + if (index_count == 0) { + return ir_addr_load(proc, vector_addr); + } + irValue *src = vector_addr.addr; + irValue *dst = ir_add_local_generated(proc, tv.type); + + for (i32 i = 1; i < ce->args.count; i++) { + TypeAndValue tv = type_and_value_of_expr(proc->module->info, ce->args.e[i]); + GB_ASSERT(is_type_integer(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Integer); + + i32 src_index = cast(i32)i128_to_i64(tv.value.value_integer); + i32 dst_index = i-1; + + irValue *src_elem = ir_emit_array_epi(proc, src, src_index); + irValue *dst_elem = ir_emit_array_epi(proc, dst, dst_index); + + ir_emit_store(proc, dst_elem, ir_emit_load(proc, src_elem)); + } + ir_emit_comment(proc, str_lit("swizzle.end")); + return ir_emit_load(proc, dst); + // return ir_emit(proc, ir_instr_vector_shuffle(proc, vector, indices, index_count)); + } break; + + case BuiltinProc_complex: { + ir_emit_comment(proc, str_lit("complex")); + irValue *real = ir_build_expr(proc, ce->args.e[0]); + irValue *imag = ir_build_expr(proc, ce->args.e[1]); + irValue *dst = ir_add_local_generated(proc, tv.type); + + Type *ft = base_complex_elem_type(tv.type); + real = ir_emit_conv(proc, real, ft); + imag = ir_emit_conv(proc, imag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), imag); + + return ir_emit_load(proc, dst); + } break; + + case BuiltinProc_real: { + ir_emit_comment(proc, str_lit("real")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *real = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, real, tv.type); + } break; + case BuiltinProc_imag: { + ir_emit_comment(proc, str_lit("imag")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } break; + + case BuiltinProc_conj: { + ir_emit_comment(proc, str_lit("conj")); + irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *res = NULL; + Type *t = ir_type(val); + if (is_type_complex(t)) { + res = ir_add_local_generated(proc, tv.type); + irValue *real = ir_emit_struct_ev(proc, val, 0); + irValue *imag = ir_emit_struct_ev(proc, val, 1); + imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + } + return ir_emit_load(proc, res); + } break; + + case BuiltinProc_slice_ptr: { + ir_emit_comment(proc, str_lit("slice_ptr")); + irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + irValue *count = ir_build_expr(proc, ce->args.e[1]); + count = ir_emit_conv(proc, count, t_int); + irValue *capacity = count; + if (ce->args.count > 2) { + capacity = ir_build_expr(proc, ce->args.e[2]); + capacity = ir_emit_conv(proc, capacity, t_int); + } + + Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr))); + irValue *slice = ir_add_local_generated(proc, slice_type); + ir_fill_slice(proc, slice, ptr, count, capacity); + return ir_emit_load(proc, slice); + } break; + + case BuiltinProc_slice_to_bytes: { + ir_emit_comment(proc, str_lit("slice_to_bytes")); + irValue *s = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(ir_type(s)); + if (is_type_u8_slice(t)) { + return ir_emit_conv(proc, s, tv.type); + } + irValue *slice = ir_add_local_generated(proc, tv.type); + i64 elem_size = type_size_of(proc->module->allocator, t->Slice.elem); + + irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr); + irValue *count = ir_slice_count(proc, s); + irValue *capacity = ir_slice_capacity(proc, s); + count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int); + capacity = ir_emit_arith(proc, Token_Mul, capacity, ir_const_int(proc->module->allocator, elem_size), t_int); + ir_fill_slice(proc, slice, ptr, count, capacity); + return ir_emit_load(proc, slice); + } break; + + case BuiltinProc_min: { + ir_emit_comment(proc, str_lit("min")); + Type *t = type_of_expr(proc->module->info, expr); + irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[0]), t); + irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t); + irValue *cond = ir_emit_comp(proc, Token_Lt, x, y); + return ir_emit_select(proc, cond, x, y); + } break; + + case BuiltinProc_max: { + ir_emit_comment(proc, str_lit("max")); + Type *t = type_of_expr(proc->module->info, expr); + irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[0]), t); + irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t); + irValue *cond = ir_emit_comp(proc, Token_Gt, x, y); + return ir_emit_select(proc, cond, x, y); + } break; + + case BuiltinProc_abs: { + ir_emit_comment(proc, str_lit("abs")); + irValue *x = ir_build_expr(proc, ce->args.e[0]); + Type *t = ir_type(x); + if (is_type_complex(t)) { + gbAllocator a = proc->module->allocator; + i64 sz = 8*type_size_of(a, t); + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = x; + switch (sz) { + case 64: return ir_emit_global_call(proc, "__abs_complex64", args, 1); + case 128: return ir_emit_global_call(proc, "__abs_complex128", args, 1); + } + GB_PANIC("Unknown complex type"); + } + irValue *zero = ir_emit_conv(proc, v_zero, t); + irValue *cond = ir_emit_comp(proc, Token_Lt, x, zero); + irValue *neg = ir_emit(proc, ir_instr_unary_op(proc, Token_Sub, x, t)); + return ir_emit_select(proc, cond, neg, x); + } break; + + case BuiltinProc_clamp: { + ir_emit_comment(proc, str_lit("clamp")); + Type *t = type_of_expr(proc->module->info, expr); + return ir_emit_clamp(proc, t, + ir_build_expr(proc, ce->args.e[0]), + ir_build_expr(proc, ce->args.e[1]), + ir_build_expr(proc, ce->args.e[2])); + } break; + } + } + } + + // NOTE(bill): Regular call + irValue *value = ir_build_expr(proc, ce->proc); + GB_ASSERT(value != NULL); + Type *proc_type_ = base_type(ir_type(value)); + GB_ASSERT(proc_type_->kind == Type_Proc); + TypeProc *type = &proc_type_->Proc; + + isize arg_index = 0; + + isize arg_count = 0; + for_array(i, ce->args) { + AstNode *a = ce->args.e[i]; + Type *at = base_type(type_of_expr(proc->module->info, a)); + if (at->kind == Type_Tuple) { + arg_count += at->Tuple.variable_count; + } else { + arg_count++; + } + } + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count); + bool variadic = proc_type_->Proc.variadic; + bool vari_expand = ce->ellipsis.pos.line != 0; + + for_array(i, ce->args) { + irValue *a = ir_build_expr(proc, ce->args.e[i]); + Type *at = ir_type(a); + if (at->kind == Type_Tuple) { + for (isize i = 0; i < at->Tuple.variable_count; i++) { + Entity *e = at->Tuple.variables[i]; + irValue *v = ir_emit_struct_ev(proc, a, i); + args[arg_index++] = v; + } + } else { + args[arg_index++] = a; + } + } + + TypeTuple *pt = &type->params->Tuple; + + if (variadic) { + isize i = 0; + for (; i < type->param_count-1; i++) { + args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type); + } + if (!vari_expand) { + Type *variadic_type = pt->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = base_type(variadic_type)->Slice.elem; + for (; i < arg_count; i++) { + args[i] = ir_emit_conv(proc, args[i], variadic_type); + } + } + } else { + for (isize i = 0; i < arg_count; i++) { + args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type); + } + } + + if (variadic && !vari_expand) { + ir_emit_comment(proc, str_lit("variadic call argument generation")); + gbAllocator allocator = proc->module->allocator; + Type *slice_type = pt->variables[type->param_count-1]->type; + Type *elem_type = base_type(slice_type)->Slice.elem; + irValue *slice = ir_add_local_generated(proc, slice_type); + isize slice_len = arg_count+1 - type->param_count; + + if (slice_len > 0) { + irValue *base_array = ir_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len)); + + for (isize i = type->param_count-1, j = 0; i < arg_count; i++, j++) { + irValue *addr = ir_emit_array_epi(proc, base_array, j); + ir_emit_store(proc, addr, args[i]); + } + + irValue *base_elem = ir_emit_array_epi(proc, base_array, 0); + irValue *len = ir_const_int(allocator, slice_len); + ir_fill_slice(proc, slice, base_elem, len, len); + } + + arg_count = type->param_count; + args[arg_count-1] = ir_emit_load(proc, slice); + } + + return ir_emit_call(proc, value, args, arg_count); + case_end; + + case_ast_node(se, SliceExpr, expr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); + case_end; + } + + GB_PANIC("Unexpected expression: %.*s", LIT(ast_node_strings[expr->kind])); + return NULL; +} + +irValue *ir_get_using_variable(irProcedure *proc, Entity *e) { + GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); + 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 { + GB_ASSERT_MSG(e->using_expr != NULL, "%.*s", LIT(name)); + v = ir_build_addr(proc, e->using_expr).addr; + } + GB_ASSERT(v != NULL); + GB_ASSERT(parent->type == type_deref(ir_type(v))); + return ir_emit_deep_field_gep(proc, v, sel); +} + +// irValue *ir_add_using_variable(irProcedure *proc, Entity *e) { +// irValue *var = ir_get_using_variable(proc, e); +// map_ir_value_set(&proc->module->values, hash_pointer(e), var); +// return var; +// } + + +bool ir_is_elem_const(irModule *m, AstNode *elem, Type *elem_type) { + if (base_type(elem_type) == t_any) { + return false; + } + if (elem->kind == AstNode_FieldValue) { + elem = elem->FieldValue.value; + } + TypeAndValue tav = type_and_value_of_expr(m->info, elem); + GB_ASSERT(tav.mode != Addressing_Invalid); + return tav.value.kind != ExactValue_Invalid; +} + +irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) { + GB_ASSERT(e != NULL); + GB_ASSERT(e->kind != Entity_Constant); + + irValue *v = NULL; + irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e)); + if (found) { + v = *found; + } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { + // NOTE(bill): Calculate the using variable every time + v = ir_get_using_variable(proc, e); + } + + if (v == NULL) { + GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind])); + } + + return ir_addr(v); +} + +irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { + switch (expr->kind) { + case_ast_node(i, Implicit, expr); + irValue *v = NULL; + switch (i->kind) { + case Token_context: + v = ir_find_global_variable(proc, str_lit("__context")); + break; + } + + GB_ASSERT(v != NULL); + return ir_addr(v); + case_end; + + case_ast_node(i, Ident, expr); + if (ir_is_blank_ident(expr)) { + irAddr val = {}; + return val; + } + Entity *e = entity_of_ident(proc->module->info, expr); + return ir_build_addr_from_entity(proc, e, expr); + case_end; + + case_ast_node(pe, ParenExpr, expr); + return ir_build_addr(proc, unparen_expr(expr)); + case_end; + + case_ast_node(se, SelectorExpr, expr); + ir_emit_comment(proc, str_lit("SelectorExpr")); + AstNode *sel = unparen_expr(se->selector); + if (sel->kind == AstNode_Ident) { + String selector = sel->Ident.string; + TypeAndValue tav = type_and_value_of_expr(proc->module->info, se->expr); + + if (tav.mode == Addressing_Invalid) { + // NOTE(bill): Imports + Entity *imp = entity_of_ident(proc->module->info, se->expr); + if (imp != NULL) { + GB_ASSERT(imp->kind == Entity_ImportName); + } + return ir_build_addr(proc, unparen_expr(se->selector)); + } + + + Type *type = base_type(tav.type); + if (tav.mode == Addressing_Type) { // Addressing_Type + Selection sel = lookup_field(proc->module->allocator, type, selector, true); + Entity *e = sel.entity; + GB_ASSERT(e->kind == Entity_Variable); + GB_ASSERT(e->flags & EntityFlag_TypeField); + String name = e->token.string; + if (str_eq(name, str_lit("names"))) { + irValue *ti_ptr = ir_type_info(proc, type); + + irValue *names_ptr = NULL; + + if (is_type_enum(type)) { + irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); + names_ptr = ir_emit_struct_ep(proc, enum_info, 3); + } else if (type->kind == Type_Record) { + irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_record_ptr); + names_ptr = ir_emit_struct_ep(proc, record_info, 3); + } + return ir_addr(names_ptr); + } else { + GB_PANIC("Unhandled TypeField %.*s", LIT(name)); + } + GB_PANIC("Unreachable"); + } + + Selection sel = lookup_field(proc->module->allocator, type, selector, false); + GB_ASSERT(sel.entity != NULL); + + if (sel.entity->type->kind == Type_BitFieldValue) { + irAddr addr = ir_build_addr(proc, se->expr); + Type *bft = type_deref(ir_addr_type(addr)); + if (sel.index.count == 1) { + GB_ASSERT(is_type_bit_field(bft)); + i32 index = sel.index.e[0]; + return ir_addr_bit_field(addr.addr, index); + } else { + Selection s = sel; + s.index.count--; + i32 index = s.index.e[s.index.count-1]; + irValue *a = addr.addr; + a = ir_emit_deep_field_gep(proc, a, s); + return ir_addr_bit_field(a, index); + } + } else { + irValue *a = ir_build_addr(proc, se->expr).addr; + a = ir_emit_deep_field_gep(proc, a, sel); + return ir_addr(a); + } + } else { + Type *type = type_deref(type_of_expr(proc->module->info, se->expr)); + Type *selector_type = base_type(type_of_expr(proc->module->info, se->selector)); + GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type)); + ExactValue val = type_and_value_of_expr(proc->module->info, sel).value; + i64 index = i128_to_i64(val.value_integer); + + Selection sel = lookup_field_from_index(proc->module->allocator, type, index); + GB_ASSERT(sel.entity != NULL); + + irValue *a = ir_build_addr(proc, se->expr).addr; + a = ir_emit_deep_field_gep(proc, a, sel); + return ir_addr(a); + } + case_end; + + case_ast_node(ta, TypeAssertion, expr); + gbAllocator a = proc->module->allocator; + TokenPos pos = ast_node_token(expr).pos; + irValue *e = ir_build_expr(proc, ta->expr); + Type *t = type_deref(ir_type(e)); + if (is_type_union(t)) { + Type *type = type_of_expr(proc->module->info, expr); + irValue *v = ir_add_local_generated(proc, type); + ir_emit_comment(proc, str_lit("cast - union_cast")); + ir_emit_store(proc, v, ir_emit_union_cast(proc, ir_build_expr(proc, ta->expr), type, pos)); + return ir_addr(v); + } else if (is_type_any(t)) { + ir_emit_comment(proc, str_lit("cast - any_cast")); + Type *type = type_of_expr(proc->module->info, expr); + return ir_emit_any_cast_addr(proc, ir_build_expr(proc, ta->expr), type, pos); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(ir_type(e))); + } + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_And: { + return ir_build_addr(proc, ue->expr); + } + default: + GB_PANIC("Invalid unary expression for ir_build_addr"); + } + case_end; + + case_ast_node(be, BinaryExpr, expr); + GB_PANIC("Invalid binary expression for ir_build_addr: %.*s\n", LIT(be->op.string)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + ir_emit_comment(proc, str_lit("IndexExpr")); + Type *t = base_type(type_of_expr(proc->module->info, ie->expr)); + gbAllocator a = proc->module->allocator; + + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); + + if (is_type_map(t)) { + irAddr map_addr = ir_build_addr(proc, ie->expr); + irValue *map_val = map_addr.addr; + irValue *key = ir_build_expr(proc, ie->index); + key = ir_emit_conv(proc, key, t->Map.key); + + Type *result_type = type_of_expr(proc->module->info, expr); + return ir_addr_map(map_val, key, t, result_type); + } + + irValue *using_addr = NULL; + if (!is_type_indexable(t)) { + // Using index expression + Entity *using_field = find_using_index_expr(t); + if (using_field != NULL) { + Selection sel = lookup_field(a, t, using_field->token.string, false); + irValue *e = ir_build_addr(proc, ie->expr).addr; + using_addr = ir_emit_deep_field_gep(proc, e, sel); + + t = using_field->type; + } + } + + + switch (t->kind) { + case Type_Vector: { + irValue *vector = NULL; + if (using_addr != NULL) { + vector = using_addr; + } else { + vector = ir_build_addr(proc, ie->expr).addr; + if (deref) { + vector = ir_emit_load(proc, vector); + } + } + irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + irValue *elem = ir_emit_array_ep(proc, vector, index); + irValue *len = ir_const_int(a, t->Vector.count); + ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len); + return ir_addr(elem); + } break; + + case Type_Array: { + irValue *array = NULL; + if (using_addr != NULL) { + array = using_addr; + } else { + array = ir_build_addr(proc, ie->expr).addr; + if (deref) { + array = ir_emit_load(proc, array); + } + } + irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + irValue *elem = ir_emit_array_ep(proc, array, index); + irValue *len = ir_const_int(a, t->Vector.count); + ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len); + return ir_addr(elem); + } break; + + case Type_Slice: { + irValue *slice = NULL; + if (using_addr != NULL) { + slice = ir_emit_load(proc, using_addr); + } else { + slice = ir_build_expr(proc, ie->expr); + if (deref) { + slice = ir_emit_load(proc, slice); + } + } + irValue *elem = ir_slice_elem(proc, slice); + irValue *len = ir_slice_count(proc, slice); + irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len); + irValue *v = ir_emit_ptr_offset(proc, elem, index); + return ir_addr(v); + } break; + + case Type_DynamicArray: { + irValue *dynamic_array = NULL; + if (using_addr != NULL) { + dynamic_array = ir_emit_load(proc, using_addr); + } else { + dynamic_array = ir_build_expr(proc, ie->expr); + if (deref) { + dynamic_array = ir_emit_load(proc, dynamic_array); + } + } + irValue *elem = ir_dynamic_array_elem(proc, dynamic_array); + irValue *len = ir_dynamic_array_count(proc, dynamic_array); + irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len); + irValue *v = ir_emit_ptr_offset(proc, elem, index); + return ir_addr(v); + } break; + + + case Type_Basic: { // Basic_string + irValue *str; + irValue *elem; + irValue *len; + irValue *index; + + if (using_addr != NULL) { + str = ir_emit_load(proc, using_addr); + } else { + str = ir_build_expr(proc, ie->expr); + if (deref) { + str = ir_emit_load(proc, str); + } + } + elem = ir_string_elem(proc, str); + len = ir_string_len(proc, str); + + index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int); + ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len); + + return ir_addr(ir_emit_ptr_offset(proc, elem, index)); + } break; + } + case_end; + + case_ast_node(se, SliceExpr, expr); + ir_emit_comment(proc, str_lit("SliceExpr")); + gbAllocator a = proc->module->allocator; + irValue *low = v_zero; + irValue *high = NULL; + irValue *max = NULL; + + if (se->low != NULL) low = ir_build_expr(proc, se->low); + if (se->high != NULL) high = ir_build_expr(proc, se->high); + if (se->max != NULL) max = ir_build_expr(proc, se->max); + + if (high != NULL && se->interval0.kind == Token_Ellipsis) { + high = ir_emit_arith(proc, Token_Add, high, v_one, t_int); + } + + if (max != NULL && se->interval1.kind == Token_Ellipsis) { + max = ir_emit_arith(proc, Token_Add, max, v_one, t_int); + } + + irValue *addr = ir_build_addr(proc, se->expr).addr; + irValue *base = ir_emit_load(proc, addr); + Type *type = base_type(ir_type(base)); + + if (is_type_pointer(type)) { + type = type_deref(type); + addr = base; + base = ir_emit_load(proc, base); + } + // TODO(bill): Cleanup like mad! + + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + + if (high == NULL) high = ir_slice_count(proc, base); + if (max == NULL) max = ir_slice_capacity(proc, base); + + ir_emit_slice_bounds_check(proc, se->open, low, high, max, false); + + irValue *elem = ir_emit_ptr_offset(proc, ir_slice_elem(proc, base), low); + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); + irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int); + + irValue *slice = ir_add_local_generated(proc, slice_type); + ir_fill_slice(proc, slice, elem, len, cap); + return ir_addr(slice); + } + + case Type_DynamicArray: { + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = make_type_slice(a, elem_type); + + if (high == NULL) high = ir_dynamic_array_count(proc, base); + if (max == NULL) max = ir_dynamic_array_capacity(proc, base); + + ir_emit_slice_bounds_check(proc, se->open, low, high, max, false); + + irValue *elem = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low); + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); + irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int); + + irValue *slice = ir_add_local_generated(proc, slice_type); + ir_fill_slice(proc, slice, elem, len, cap); + return ir_addr(slice); + } + + + case Type_Array: { + Type *slice_type = make_type_slice(a, type->Array.elem); + + if (high == NULL) high = ir_array_len(proc, base); + if (max == NULL) max = ir_array_len(proc, base); + + ir_emit_slice_bounds_check(proc, se->open, low, high, max, false); + + irValue *elem = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low); + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); + irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int); + + irValue *slice = ir_add_local_generated(proc, slice_type); + ir_fill_slice(proc, slice, elem, len, cap); + return ir_addr(slice); + } + + case Type_Basic: { + GB_ASSERT(type == t_string); + if (high == NULL) high = ir_string_len(proc, base); + // if (max == NULL) max = ir_string_len(proc, base); + + ir_emit_slice_bounds_check(proc, se->open, low, high, NULL, true); + + irValue *elem = ir_emit_ptr_offset(proc, ir_string_elem(proc, base), low); + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); + + irValue *str = ir_add_local_generated(proc, t_string); + ir_fill_string(proc, str, elem, len); + return ir_addr(str); + } break; + } + + GB_PANIC("Unknown slicable type"); + case_end; + + case_ast_node(de, DerefExpr, expr); + // TODO(bill): Is a ptr copy needed? + irValue *addr = ir_build_expr(proc, de->expr); + addr = ir_emit_ptr_offset(proc, addr, v_zero); + return ir_addr(addr); + case_end; + + case_ast_node(ce, CallExpr, expr); + // NOTE(bill): This is make sure you never need to have an `array_ev` + irValue *e = ir_build_expr(proc, expr); + irValue *v = ir_add_local_generated(proc, ir_type(e)); + ir_emit_store(proc, v, e); + return ir_addr(v); + case_end; + + case_ast_node(cl, CompoundLit, expr); + ir_emit_comment(proc, str_lit("CompoundLit")); + Type *type = type_of_expr(proc->module->info, expr); + Type *bt = base_type(type); + irValue *v = ir_add_local_generated(proc, type); + + Type *et = NULL; + switch (bt->kind) { + case Type_Vector: et = bt->Vector.elem; break; + case Type_Array: et = bt->Array.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + } + + switch (bt->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + + case Type_Vector: { + if (cl->elems.count == 1 && bt->Vector.count > 1) { + isize index_count = bt->Vector.count; + irValue *elem_val = ir_build_expr(proc, cl->elems.e[0]); + for (isize i = 0; i < index_count; i++) { + ir_emit_store(proc, ir_emit_array_epi(proc, v, i), elem_val); + } + } else if (cl->elems.count > 0) { + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irValue *field_expr = ir_build_expr(proc, elem); + Type *t = ir_type(field_expr); + GB_ASSERT(t->kind != Type_Tuple); + irValue *ev = ir_emit_conv(proc, field_expr, et); + irValue *gep = ir_emit_array_epi(proc, v, i); + ir_emit_store(proc, gep, ev); + } + } + } break; + + case Type_Record: { + // TODO(bill): "constant" unions are not initialized constantly at the moment. + // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR + bool is_union = is_type_union(bt); + GB_ASSERT(is_type_struct(bt) || is_type_union(bt)); + TypeRecord *st = &bt->Record; + if (cl->elems.count > 0) { + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + + irValue *field_expr = NULL; + Entity *field = NULL; + isize index = field_index; + + if (elem->kind == AstNode_FieldValue) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.string; + Selection sel = lookup_field(proc->module->allocator, bt, name, false); + index = sel.index.e[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem); + Selection sel = lookup_field_from_index(proc->module->allocator, bt, st->fields_in_src_order[field_index]->Variable.field_index); + index = sel.index.e[0]; + } + + field = st->fields[index]; + Type *ft = field->type; + if (!is_union && !is_type_union(ft) && + ir_is_elem_const(proc->module, elem, ft)) { + continue; + } + + field_expr = ir_build_expr(proc, elem); + + GB_ASSERT(ir_type(field_expr)->kind != Type_Tuple); + + irValue *fv = ir_emit_conv(proc, field_expr, ft); + irValue *gep = ir_emit_struct_ep(proc, v, index); + ir_emit_store(proc, gep, fv); + } + } + } break; + + case Type_DynamicArray: { + if (cl->elems.count == 0) { + break; + } + Type *elem = bt->DynamicArray.elem; + gbAllocator a = proc->module->allocator; + irValue *size = ir_const_int(a, type_size_of(a, elem)); + irValue *align = ir_const_int(a, type_align_of(a, elem)); + { + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ir_emit_conv(proc, v, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = ir_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4); + } + + i64 item_count = cl->elems.count; + irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("__dacl$"), cast(i64)cast(intptr)expr); + + for_array(field_index, cl->elems) { + AstNode *f = cl->elems.e[field_index]; + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem); + irValue *ep = ir_emit_array_epi(proc, items, field_index); + ir_emit_store(proc, ep, value); + } + + { + irValue **args = gb_alloc_array(a, irValue *, 5); + args[0] = ir_emit_conv(proc, v, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = ir_emit_conv(proc, items, t_rawptr); + args[4] = ir_const_int(a, item_count); + ir_emit_global_call(proc, "__dynamic_array_append", args, 5); + } + } break; + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + gbAllocator a = proc->module->allocator; + { + irValue **args = gb_alloc_array(a, irValue *, 2); + args[0] = ir_gen_map_header(proc, v, type); + args[1] = ir_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + } + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + ast_node(fv, FieldValue, elem); + + irValue *key = ir_build_expr(proc, fv->field); + irValue *value = ir_build_expr(proc, fv->value); + ir_insert_dynamic_map_key_and_value(proc, v, type, key, value); + } + } break; + + case Type_Array: { + if (cl->elems.count > 0) { + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irValue *field_expr = ir_build_expr(proc, elem); + Type *t = ir_type(field_expr); + GB_ASSERT(t->kind != Type_Tuple); + irValue *ev = ir_emit_conv(proc, field_expr, et); + irValue *gep = ir_emit_array_epi(proc, v, i); + ir_emit_store(proc, gep, ev); + } + } + } break; + case Type_Slice: { + if (cl->elems.count > 0) { + Type *elem_type = bt->Slice.elem; + Type *elem_ptr_type = make_type_pointer(proc->module->allocator, elem_type); + Type *elem_ptr_ptr_type = make_type_pointer(proc->module->allocator, elem_ptr_type); + irValue *slice = ir_add_module_constant(proc->module, type, exact_value_compound(expr)); + GB_ASSERT(slice->kind == irValue_ConstantSlice); + + irValue *data = ir_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32); + + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + + irValue *field_expr = ir_build_expr(proc, elem); + Type *t = ir_type(field_expr); + GB_ASSERT(t->kind != Type_Tuple); + irValue *ev = ir_emit_conv(proc, field_expr, elem_type); + irValue *offset = ir_emit_ptr_offset(proc, data, ir_const_int(proc->module->allocator, i)); + ir_emit_store(proc, offset, ev); + } + + irValue *count = ir_const_int(proc->module->allocator, slice->ConstantSlice.count); + ir_fill_slice(proc, v, data, count, count); + } + } break; + + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + if (cl->elems.count > 0) { + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); + String field_names[2] = { + str_lit("data"), + str_lit("type_info"), + }; + Type *field_types[2] = { + t_rawptr, + t_type_info_ptr, + }; + + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + + irValue *field_expr = NULL; + isize index = field_index; + + if (elem->kind == AstNode_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false); + index = sel.index.e[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem); + Selection sel = lookup_field(proc->module->allocator, bt, field_names[field_index], false); + index = sel.index.e[0]; + } + + field_expr = ir_build_expr(proc, elem); + + GB_ASSERT(ir_type(field_expr)->kind != Type_Tuple); + + Type *ft = field_types[index]; + irValue *fv = ir_emit_conv(proc, field_expr, ft); + irValue *gep = ir_emit_struct_ep(proc, v, index); + ir_emit_store(proc, gep, fv); + } + } + } + } + + return ir_addr(v); + case_end; + } + + TokenPos token_pos = ast_node_token(expr).pos; + GB_PANIC("Unexpected address expression\n" + "\tAstNode: %.*s @ " + "%.*s(%td:%td)\n", + LIT(ast_node_strings[expr->kind]), + LIT(token_pos.file), token_pos.line, token_pos.column); + + + return ir_addr(NULL); +} + +void ir_build_assign_op(irProcedure *proc, irAddr lhs, irValue *value, TokenKind op) { + irValue *old_value = ir_addr_load(proc, lhs); + Type *type = ir_type(old_value); + + irValue *change = value; + if (is_type_pointer(type) && is_type_integer(ir_type(value))) { + change = ir_emit_conv(proc, value, default_type(ir_type(value))); + } else { + change = ir_emit_conv(proc, value, type); + } + irValue *new_value = ir_emit_arith(proc, op, old_value, change, type); + ir_addr_store(proc, lhs, new_value); +} + +irValue *ir_build_cond(irProcedure *proc, AstNode *cond, irBlock *true_block, irBlock *false_block) { + switch (cond->kind) { + case_ast_node(pe, ParenExpr, cond); + return ir_build_cond(proc, pe->expr, true_block, false_block); + case_end; + + case_ast_node(ue, UnaryExpr, cond); + if (ue->op.kind == Token_Not) { + return ir_build_cond(proc, ue->expr, false_block, true_block); + } + case_end; + + case_ast_node(be, BinaryExpr, cond); + if (be->op.kind == Token_CmpAnd) { + irBlock *block = ir_new_block(proc, NULL, "cmp.and"); + ir_build_cond(proc, be->left, block, false_block); + ir_start_block(proc, block); + return ir_build_cond(proc, be->right, true_block, false_block); + } else if (be->op.kind == Token_CmpOr) { + irBlock *block = ir_new_block(proc, NULL, "cmp.or"); + ir_build_cond(proc, be->left, true_block, block); + ir_start_block(proc, block); + return ir_build_cond(proc, be->right, true_block, false_block); + } + case_end; + } + + irValue *v = ir_build_expr(proc, cond); + v = ir_emit_conv(proc, v, t_bool); + ir_emit_if(proc, v, true_block, false_block); + return v; +} + + + + +void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts) { + for_array(i, stmts) { + ir_build_stmt(proc, stmts.e[i]); + } +} + +void ir_build_stmt_internal(irProcedure *proc, AstNode *node); +void ir_build_stmt(irProcedure *proc, AstNode *node) { + u32 prev_stmt_state_flags = proc->module->stmt_state_flags; + + if (node->stmt_state_flags != 0) { + u32 in = node->stmt_state_flags; + u32 out = proc->module->stmt_state_flags; + + if (in & StmtStateFlag_bounds_check) { + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; + } else if (in & StmtStateFlag_no_bounds_check) { + out |= StmtStateFlag_no_bounds_check; + out &= ~StmtStateFlag_bounds_check; + } + + proc->module->stmt_state_flags = out; + } + + ir_build_stmt_internal(proc, node); + + proc->module->stmt_state_flags = prev_stmt_state_flags; +} + +void ir_build_when_stmt(irProcedure *proc, AstNodeWhenStmt *ws) { + irValue *cond = ir_build_expr(proc, ws->cond); + GB_ASSERT(cond->kind == irValue_Constant && + is_type_boolean(ir_type(cond))); + + GB_ASSERT(cond->Constant.value.kind == ExactValue_Bool); + if (cond->Constant.value.value_bool) { + ir_build_stmt_list(proc, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case AstNode_BlockStmt: + ir_build_stmt_list(proc, ws->else_stmt->BlockStmt.stmts); + break; + case AstNode_WhenStmt: + ir_build_when_stmt(proc, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid `else` statement in `when` statement"); + break; + } + } +} + +void ir_emit_increment(irProcedure *proc, irValue *addr) { + GB_ASSERT(is_type_pointer(ir_type(addr))); + Type *type = type_deref(ir_type(addr)); + ir_emit_store(proc, addr, ir_emit_arith(proc, Token_Add, ir_emit_load(proc, addr), v_one, type)); + +} + + +void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr, + irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) { + irValue *count = NULL; + Type *expr_type = base_type(type_deref(ir_type(expr))); + switch (expr_type->kind) { + case Type_Array: + count = ir_const_int(proc->module->allocator, expr_type->Array.count); + break; + case Type_Vector: + count = ir_const_int(proc->module->allocator, expr_type->Vector.count); + break; + } + + irValue *val = NULL; + irValue *idx = NULL; + irBlock *loop = NULL; + irBlock *done = NULL; + irBlock *body = NULL; + + irValue *key = NULL; + if (expr_type->kind == Type_Map) { + key = ir_add_local_generated(proc, expr_type->Map.key); + } + + irValue *index = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, index, ir_const_int(proc->module->allocator, -1)); + + loop = ir_new_block(proc, NULL, "for.index.loop"); + ir_emit_jump(proc, loop); + ir_start_block(proc, loop); + + irValue *incr = ir_emit_arith(proc, Token_Add, ir_emit_load(proc, index), v_one, t_int); + ir_emit_store(proc, index, incr); + + body = ir_new_block(proc, NULL, "for.index.body"); + done = ir_new_block(proc, NULL, "for.index.done"); + if (count == NULL) { + count = ir_emit_load(proc, count_ptr); + } + irValue *cond = ir_emit_comp(proc, Token_Lt, incr, count); + ir_emit_if(proc, cond, body, done); + ir_start_block(proc, body); + + idx = ir_emit_load(proc, index); + if (val_type != NULL) { + switch (expr_type->kind) { + case Type_Array: { + val = ir_emit_load(proc, ir_emit_array_ep(proc, expr, idx)); + } break; + case Type_Vector: { + val = ir_emit_load(proc, ir_emit_array_ep(proc, expr, idx)); + } break; + case Type_Slice: { + irValue *elem = ir_slice_elem(proc, expr); + val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx)); + } break; + case Type_DynamicArray: { + irValue *elem = ir_emit_struct_ep(proc, expr, 0); + elem = ir_emit_load(proc, elem); + val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx)); + } break; + case Type_Map: { + irValue *entries = ir_emit_struct_ep(proc, expr, 1); + irValue *elem = ir_emit_struct_ep(proc, entries, 0); + elem = ir_emit_load(proc, elem); + + irValue *entry = ir_emit_ptr_offset(proc, elem, idx); + val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); + + irValue *hash = ir_emit_struct_ep(proc, entry, 0); + if (is_type_string(expr_type->Map.key)) { + irValue *str = ir_emit_struct_ep(proc, hash, 1); + ir_emit_store(proc, key, ir_emit_load(proc, str)); + } else { + irValue *hash_ptr = ir_emit_struct_ep(proc, hash, 0); + hash_ptr = ir_emit_conv(proc, hash_ptr, ir_type(key)); + ir_emit_store(proc, key, ir_emit_load(proc, hash_ptr)); + } + + + } break; + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + } + + if (key != NULL) { + idx = ir_emit_load(proc, key); + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + +void ir_build_range_string(irProcedure *proc, irValue *expr, Type *val_type, + irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) { + irValue *count = v_zero; + Type *expr_type = base_type(ir_type(expr)); + switch (expr_type->kind) { + case Type_Basic: + count = ir_string_len(proc, expr); + break; + default: + GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type)); + break; + } + + irValue *val = NULL; + irValue *idx = NULL; + irBlock *loop = NULL; + irBlock *done = NULL; + irBlock *body = NULL; + + + irValue *offset_ = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, offset_, v_zero); + + loop = ir_new_block(proc, NULL, "for.string.loop"); + ir_emit_jump(proc, loop); + ir_start_block(proc, loop); + + + + body = ir_new_block(proc, NULL, "for.string.body"); + done = ir_new_block(proc, NULL, "for.string.done"); + + irValue *offset = ir_emit_load(proc, offset_); + irValue *cond = ir_emit_comp(proc, Token_Lt, offset, count); + ir_emit_if(proc, cond, body, done); + ir_start_block(proc, body); + + + irValue *str_elem = ir_emit_ptr_offset(proc, ir_string_elem(proc, expr), offset); + irValue *str_len = ir_emit_arith(proc, Token_Sub, count, offset, t_int); + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + args[0] = ir_emit_string(proc, str_elem, str_len); + irValue *rune_and_len = ir_emit_global_call(proc, "__string_decode_rune", args, 1); + irValue *len = ir_emit_struct_ev(proc, rune_and_len, 1); + ir_emit_store(proc, offset_, ir_emit_arith(proc, Token_Add, offset, len, t_int)); + + + idx = offset; + if (val_type != NULL) { + val = ir_emit_struct_ev(proc, rune_and_len, 0); + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + +void ir_build_range_interval(irProcedure *proc, AstNodeBinaryExpr *node, Type *val_type, + irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) { + // TODO(bill): How should the behaviour work for lower and upper bounds checking for iteration? + // If `lower` is changed, should `val` do so or is that not typical behaviour? + + irValue *lower = ir_build_expr(proc, node->left); + irValue *upper = NULL; + + irValue *val = NULL; + irValue *idx = NULL; + irBlock *loop = NULL; + irBlock *done = NULL; + irBlock *body = NULL; + + if (val_type == NULL) { + val_type = ir_type(lower); + } + irValue *value = ir_add_local_generated(proc, val_type); + ir_emit_store(proc, value, lower); + + irValue *index = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, index, ir_const_int(proc->module->allocator, 0)); + + loop = ir_new_block(proc, NULL, "for.interval.loop"); + ir_emit_jump(proc, loop); + ir_start_block(proc, loop); + + body = ir_new_block(proc, NULL, "for.interval.body"); + done = ir_new_block(proc, NULL, "for.interval.done"); + + + TokenKind op = Token_Lt; + switch (node->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + + upper = ir_build_expr(proc, node->right); + + irValue *cond = ir_emit_comp(proc, op, ir_emit_load(proc, value), upper); + ir_emit_if(proc, cond, body, done); + ir_start_block(proc, body); + + if (value != NULL) { + val = ir_emit_load(proc, value); + } + idx = ir_emit_load(proc, index); + + ir_emit_increment(proc, value); + ir_emit_increment(proc, index); + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + +void ir_store_type_case_implicit(irProcedure *proc, AstNode *clause, irValue *value) { + Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause)); + GB_ASSERT(found != NULL); + Entity *e = *found; GB_ASSERT(e != NULL); + irValue *x = ir_add_local(proc, e, NULL); + ir_emit_store(proc, x, value); +} + +void ir_type_case_body(irProcedure *proc, AstNode *label, AstNode *clause, irBlock *body, irBlock *done) { + ast_node(cc, CaseClause, clause); + + ir_push_target_list(proc, label, done, NULL, NULL); + ir_open_scope(proc); + ir_build_stmt_list(proc, cc->stmts); + ir_close_scope(proc, irDeferExit_Default, body); + ir_pop_target_list(proc); + + ir_emit_jump(proc, done); +} + + +void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { + switch (node->kind) { + case_ast_node(bs, EmptyStmt, node); + case_end; + + case_ast_node(us, UsingStmt, node); + for_array(i, us->list) { + AstNode *decl = unparen_expr(us->list.e[i]); + if (decl->kind == AstNode_ValueDecl) { + ir_build_stmt(proc, decl); + } + } + case_end; + + case_ast_node(ws, WhenStmt, node); + ir_build_when_stmt(proc, ws); + case_end; + + case_ast_node(s, IncDecStmt, node); + TokenKind op = Token_Add; + if (s->op.kind == Token_Dec) { + op = Token_Sub; + } + irAddr addr = ir_build_addr(proc, s->expr); + ir_build_assign_op(proc, addr, v_one, op); + case_end; + + case_ast_node(vd, ValueDecl, node); + if (vd->is_var) { + irModule *m = proc->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + + if (vd->values.count == 0) { // declared and zero-initialized + for_array(i, vd->names) { + AstNode *name = vd->names.e[i]; + if (!ir_is_blank_ident(name)) { + ir_add_local_for_identifier(proc, name, true); + } + } + } else { // Tuple(s) + Array(irAddr) lvals = {}; + irValueArray inits = {}; + 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]; + irAddr lval = ir_addr(NULL); + if (!ir_is_blank_ident(name)) { + ir_add_local_for_identifier(proc, name, false); + lval = ir_build_addr(proc, name); + } + + array_add(&lvals, lval); + } + + for_array(i, vd->values) { + irValue *init = ir_build_expr(proc, vd->values.e[i]); + Type *t = ir_type(init); + if (t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + irValue *v = ir_emit_struct_ev(proc, init, i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + + for_array(i, inits) { + ir_addr_store(proc, lvals.e[i], inits.e[i]); + } + } + + gb_temp_arena_memory_end(tmp); + } else { + for_array(i, vd->names) { + AstNode *ident = vd->names.e[i]; + GB_ASSERT(ident->kind == AstNode_Ident); + Entity *e = entity_of_ident(proc->module->info, ident); + GB_ASSERT(e != NULL); + switch (e->kind) { + case Entity_TypeName: { + // NOTE(bill): Generate a new name + // parent_proc.name-guid + String ts_name = e->token.string; + isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + i32 guid = cast(i32)proc->module->members.entries.count; + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid); + String name = make_string(name_text, name_len-1); + + irValue *value = ir_value_type_name(proc->module->allocator, + name, e->type); + map_string_set(&proc->module->entity_names, hash_pointer(e), name); + ir_gen_global_type_name(proc->module, e, name); + } break; + case Entity_Procedure: { + DeclInfo **decl_info = map_decl_info_get(&proc->module->info->entities, hash_pointer(e)); + GB_ASSERT(decl_info != NULL); + DeclInfo *dl = *decl_info; + ast_node(pd, ProcLit, dl->proc_lit); + if (pd->body != NULL) { + CheckerInfo *info = proc->module->info; + + if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + break; + } + + // NOTE(bill): Generate a new name + // parent.name-guid + String original_name = e->token.string; + String pd_name = original_name; + if (pd->link_name.len > 0) { + pd_name = pd->link_name; + } + + isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + i32 guid = cast(i32)proc->children.count; + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid); + String name = make_string(name_text, name_len-1); + + + irValue *value = ir_value_procedure(proc->module->allocator, + proc->module, e, e->type, pd->type, pd->body, name); + + value->Proc.tags = pd->tags; + value->Proc.parent = proc; + + ir_module_add_value(proc->module, e, value); + array_add(&proc->children, &value->Proc); + array_add(&proc->module->procs_to_generate, value); + } else { + CheckerInfo *info = proc->module->info; + + // FFI - Foreign function interace + String original_name = e->token.string; + String name = original_name; + if (pd->foreign_name.len > 0) { + name = pd->foreign_name; + } + + irValue *value = ir_value_procedure(proc->module->allocator, + proc->module, e, e->type, pd->type, pd->body, name); + + value->Proc.tags = pd->tags; + + ir_module_add_value(proc->module, e, value); + ir_build_proc(value, proc); + + if (value->Proc.tags & ProcTag_foreign) { + HashKey key = hash_string(name); + irValue **prev_value = map_ir_value_get(&proc->module->members, key); + if (prev_value == NULL) { + // NOTE(bill): Don't do mutliple declarations in the IR + map_ir_value_set(&proc->module->members, key, value); + } + } else { + array_add(&proc->children, &value->Proc); + } + } + } break; + } + } + } + case_end; + + case_ast_node(as, AssignStmt, node); + ir_emit_comment(proc, str_lit("AssignStmt")); + + irModule *m = proc->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + + switch (as->op.kind) { + case Token_Eq: { + Array(irAddr) lvals; + array_init(&lvals, m->tmp_allocator); + + for_array(i, as->lhs) { + AstNode *lhs = as->lhs.e[i]; + irAddr lval = {}; + if (!ir_is_blank_ident(lhs)) { + lval = ir_build_addr(proc, lhs); + } + array_add(&lvals, lval); + } + + if (as->lhs.count == as->rhs.count) { + if (as->lhs.count == 1) { + AstNode *rhs = as->rhs.e[0]; + irValue *init = ir_build_expr(proc, rhs); + ir_addr_store(proc, lvals.e[0], init); + } else { + irValueArray inits; + array_init_reserve(&inits, m->tmp_allocator, lvals.count); + + for_array(i, as->rhs) { + irValue *init = ir_build_expr(proc, as->rhs.e[i]); + array_add(&inits, init); + } + + for_array(i, inits) { + ir_addr_store(proc, lvals.e[i], inits.e[i]); + } + } + } else { + irValueArray inits; + array_init_reserve(&inits, m->tmp_allocator, lvals.count); + + for_array(i, as->rhs) { + irValue *init = ir_build_expr(proc, as->rhs.e[i]); + Type *t = ir_type(init); + // TODO(bill): refactor for code reuse as this is repeated a bit + if (t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + irValue *v = ir_emit_struct_ev(proc, init, i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + for_array(i, inits) { + ir_addr_store(proc, lvals.e[i], inits.e[i]); + } + } + + } break; + + default: { + // NOTE(bill): Only 1 += 1 is allowed, no tuples + // +=, -=, etc + i32 op = cast(i32)as->op.kind; + op += Token_Add - Token_AddEq; // Convert += to + + irAddr lhs = ir_build_addr(proc, as->lhs.e[0]); + irValue *value = ir_build_expr(proc, as->rhs.e[0]); + ir_build_assign_op(proc, 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 + ir_build_expr(proc, es->expr); + case_end; + + case_ast_node(bs, BlockStmt, node); + ir_open_scope(proc); + ir_build_stmt_list(proc, bs->stmts); + ir_close_scope(proc, irDeferExit_Default, NULL); + case_end; + + case_ast_node(ds, DeferStmt, node); + ir_emit_comment(proc, str_lit("DeferStmt")); + isize scope_index = proc->scope_index; + if (ds->stmt->kind == AstNode_BlockStmt) { + scope_index--; + } + ir_add_defer_node(proc, scope_index, ds->stmt); + case_end; + + case_ast_node(rs, ReturnStmt, node); + ir_emit_comment(proc, str_lit("ReturnStmt")); + irValue *v = NULL; + TypeTuple *return_type_tuple = &proc->type->Proc.results->Tuple; + isize return_count = proc->type->Proc.result_count; + if (return_count == 0) { + // No return values + } else if (return_count == 1) { + Entity *e = return_type_tuple->variables[0]; + v = ir_build_expr(proc, rs->results.e[0]); + v = ir_emit_conv(proc, v, e->type); + } else { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); + + irValueArray results; + array_init_reserve(&results, proc->module->tmp_allocator, return_count); + + for_array(res_index, rs->results) { + irValue *res = ir_build_expr(proc, rs->results.e[res_index]); + Type *t = ir_type(res); + if (t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + irValue *v = ir_emit_struct_ev(proc, res, i); + array_add(&results, v); + } + } else { + array_add(&results, res); + } + } + + Type *ret_type = proc->type->Proc.results; + v = ir_add_local_generated(proc, ret_type); + for_array(i, results) { + Entity *e = return_type_tuple->variables[i]; + irValue *res = ir_emit_conv(proc, results.e[i], e->type); + irValue *field = ir_emit_struct_ep(proc, v, i); + ir_emit_store(proc, field, res); + } + + v = ir_emit_load(proc, v); + + gb_temp_arena_memory_end(tmp); + } + + ir_emit_return(proc, v); + + case_end; + + case_ast_node(is, IfStmt, node); + ir_emit_comment(proc, str_lit("IfStmt")); + if (is->init != NULL) { + irBlock *init = ir_new_block(proc, node, "if.init"); + ir_emit_jump(proc, init); + ir_start_block(proc, init); + ir_build_stmt(proc, is->init); + } + irBlock *then = ir_new_block(proc, node, "if.then"); + irBlock *done = ir_new_block(proc, node, "if.done"); + irBlock *else_ = done; + if (is->else_stmt != NULL) { + else_ = ir_new_block(proc, is->else_stmt, "if.else"); + } + + ir_build_cond(proc, is->cond, then, else_); + ir_start_block(proc, then); + + ir_open_scope(proc); + ir_build_stmt(proc, is->body); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + + if (is->else_stmt != NULL) { + ir_start_block(proc, else_); + + ir_open_scope(proc); + ir_build_stmt(proc, is->else_stmt); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + } + + ir_start_block(proc, done); + case_end; + + case_ast_node(fs, ForStmt, node); + ir_emit_comment(proc, str_lit("ForStmt")); + + if (fs->init != NULL) { + irBlock *init = ir_new_block(proc, node, "for.init"); + ir_emit_jump(proc, init); + ir_start_block(proc, init); + ir_build_stmt(proc, fs->init); + } + irBlock *body = ir_new_block(proc, node, "for.body"); + irBlock *done = ir_new_block(proc, node, "for.done"); // NOTE(bill): Append later + irBlock *loop = body; + if (fs->cond != NULL) { + loop = ir_new_block(proc, node, "for.loop"); + } + irBlock *post = loop; + if (fs->post != NULL) { + post = ir_new_block(proc, node, "for.post"); + } + + + ir_emit_jump(proc, loop); + ir_start_block(proc, loop); + + if (loop != body) { + ir_build_cond(proc, fs->cond, body, done); + ir_start_block(proc, body); + } + + ir_push_target_list(proc, fs->label, done, post, NULL); + + ir_open_scope(proc); + ir_build_stmt(proc, fs->body); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_pop_target_list(proc); + + ir_emit_jump(proc, post); + + if (fs->post != NULL) { + ir_start_block(proc, post); + ir_build_stmt(proc, fs->post); + ir_emit_jump(proc, loop); + } + + ir_start_block(proc, done); + case_end; + + + case_ast_node(rs, RangeStmt, node); + ir_emit_comment(proc, str_lit("RangeStmt")); + + Type *val_type = NULL; + Type *idx_type = NULL; + if (rs->value != NULL && !ir_is_blank_ident(rs->value)) { + val_type = type_of_expr(proc->module->info, rs->value); + } + if (rs->index != NULL && !ir_is_blank_ident(rs->index)) { + idx_type = type_of_expr(proc->module->info, rs->index); + } + + if (val_type != NULL) { + ir_add_local_for_identifier(proc, rs->value, true); + } + if (idx_type != NULL) { + ir_add_local_for_identifier(proc, rs->index, true); + } + + irValue *val = NULL; + irValue *index = NULL; + irBlock *loop = NULL; + irBlock *done = NULL; + AstNode *expr = unparen_expr(rs->expr); + + TypeAndValue tav = type_and_value_of_expr(proc->module->info, expr); + + if (is_ast_node_a_range(expr)) { + ir_build_range_interval(proc, &expr->BinaryExpr, val_type, &val, &index, &loop, &done); + } else if (tav.mode == Addressing_Type) { + TokenPos pos = ast_node_token(expr).pos; + gbAllocator a = proc->module->allocator; + Type *t = tav.type; + GB_ASSERT(is_type_enum(t)); + Type *enum_ptr = make_type_pointer(a, t); + t = base_type(t); + Type *core_elem = core_type(t); + i64 enum_count = t->Record.field_count; + irValue *max_count = ir_const_int(a, enum_count); + + irValue *eti = ir_emit_union_cast(proc, ir_type_info(proc, t), t_type_info_enum_ptr, pos); + irValue *values = ir_emit_load(proc, ir_emit_struct_ep(proc, eti, 4)); + irValue *values_data = ir_slice_elem(proc, values); + + + irValue *offset_ = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, offset_, v_zero); + + loop = ir_new_block(proc, NULL, "for.enum.loop"); + ir_emit_jump(proc, loop); + ir_start_block(proc, loop); + + irBlock *body = ir_new_block(proc, NULL, "for.enum.body"); + done = ir_new_block(proc, NULL, "for.enum.done"); + + irValue *offset = ir_emit_load(proc, offset_); + irValue *cond = ir_emit_comp(proc, Token_Lt, offset, max_count); + ir_emit_if(proc, cond, body, done); + ir_start_block(proc, body); + + + irValue *val_ptr = ir_emit_ptr_offset(proc, values_data, offset); + ir_emit_increment(proc, offset_); + + index = offset; + if (val_type != NULL) { + if (is_type_float(core_elem)) { + irValue *f = ir_emit_load(proc, ir_emit_conv(proc, val_ptr, t_f64_ptr)); + val = ir_emit_conv(proc, f, t); + } else if (is_type_integer(core_elem)) { + irValue *i = ir_emit_load(proc, ir_emit_conv(proc, val_ptr, t_i64_ptr)); + val = ir_emit_conv(proc, i, t); + } else { + GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem)); + } + } + } else { + Type *expr_type = type_of_expr(proc->module->info, rs->expr); + Type *et = base_type(type_deref(expr_type)); + switch (et->kind) { + case Type_Map: { + irAddr addr = ir_build_addr(proc, rs->expr); + irValue *map = addr.addr; + if (is_type_pointer(type_deref(ir_addr_type(addr)))) { + map = ir_addr_load(proc, addr); + } + irValue *entries_ptr = ir_emit_struct_ep(proc, map, 1); + irValue *count_ptr = ir_emit_struct_ep(proc, entries_ptr, 1); + ir_build_range_indexed(proc, map, val_type, count_ptr, &val, &index, &loop, &done); + } break; + case Type_Array: { + irValue *count_ptr = NULL; + irValue *array = ir_build_addr(proc, rs->expr).addr; + if (is_type_pointer(type_deref(ir_type(array)))) { + array = ir_emit_load(proc, array); + } + count_ptr = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, count_ptr, ir_const_int(proc->module->allocator, et->Array.count)); + ir_build_range_indexed(proc, array, val_type, count_ptr, &val, &index, &loop, &done); + } break; + case Type_Vector: { + irValue *count_ptr = NULL; + irValue *vector = ir_build_addr(proc, rs->expr).addr; + if (is_type_pointer(type_deref(ir_type(vector)))) { + vector = ir_emit_load(proc, vector); + } + count_ptr = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, count_ptr, ir_const_int(proc->module->allocator, et->Vector.count)); + ir_build_range_indexed(proc, vector, val_type, count_ptr, &val, &index, &loop, &done); + } break; + case Type_DynamicArray: { + irValue *count_ptr = NULL; + irValue *array = ir_build_addr(proc, rs->expr).addr; + if (is_type_pointer(type_deref(ir_type(array)))) { + array = ir_emit_load(proc, array); + } + count_ptr = ir_emit_struct_ep(proc, array, 1); + ir_build_range_indexed(proc, array, val_type, count_ptr, &val, &index, &loop, &done); + } break; + case Type_Slice: { + irValue *count_ptr = NULL; + irValue *slice = ir_build_expr(proc, rs->expr); + if (is_type_pointer(ir_type(slice))) { + count_ptr = ir_emit_struct_ep(proc, slice, 1); + slice = ir_emit_load(proc, slice); + } else { + count_ptr = ir_add_local_generated(proc, t_int); + ir_emit_store(proc, count_ptr, ir_slice_count(proc, slice)); + } + ir_build_range_indexed(proc, slice, val_type, count_ptr, &val, &index, &loop, &done); + } break; + case Type_Basic: { + irValue *string = ir_build_expr(proc, rs->expr); + if (is_type_pointer(ir_type(string))) { + string = ir_emit_load(proc, string); + } + if (is_type_untyped(expr_type)) { + irValue *s = ir_add_local_generated(proc, t_string); + ir_emit_store(proc, s, string); + string = ir_emit_load(proc, s); + } + ir_build_range_string(proc, string, val_type, &val, &index, &loop, &done); + } break; + default: + GB_PANIC("Cannot range over %s", type_to_string(expr_type)); + break; + } + } + + irAddr val_addr = {}; + irAddr idx_addr = {}; + if (val_type != NULL) { + val_addr = ir_build_addr(proc, rs->value); + } + if (idx_type != NULL) { + idx_addr = ir_build_addr(proc, rs->index); + } + if (val_type != NULL) { + ir_addr_store(proc, val_addr, val); + } + if (idx_type != NULL) { + ir_addr_store(proc, idx_addr, index); + } + + ir_push_target_list(proc, rs->label, done, loop, NULL); + + ir_open_scope(proc); + ir_build_stmt(proc, rs->body); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_pop_target_list(proc); + ir_emit_jump(proc, loop); + ir_start_block(proc, done); + case_end; + + case_ast_node(ms, MatchStmt, node); + ir_emit_comment(proc, str_lit("MatchStmt")); + if (ms->init != NULL) { + ir_build_stmt(proc, ms->init); + } + irValue *tag = v_true; + if (ms->tag != NULL) { + tag = ir_build_expr(proc, ms->tag); + } + irBlock *done = ir_new_block(proc, node, "match.done"); // NOTE(bill): Append later + + ast_node(body, BlockStmt, ms->body); + + AstNodeArray default_stmts = {}; + irBlock *default_fall = NULL; + irBlock *default_block = NULL; + + irBlock *fall = NULL; + bool append_fall = false; + + isize case_count = body->stmts.count; + for_array(i, body->stmts) { + AstNode *clause = body->stmts.e[i]; + irBlock *body = fall; + + ast_node(cc, CaseClause, clause); + + if (body == NULL) { + if (cc->list.count == 0) { + body = ir_new_block(proc, clause, "match.dflt.body"); + } else { + body = ir_new_block(proc, clause, "match.case.body"); + } + } + if (append_fall && body == fall) { + append_fall = false; + } + + fall = done; + if (i+1 < case_count) { + append_fall = true; + fall = ir_new_block(proc, clause, "match.fall.body"); + } + + if (cc->list.count == 0) { + // default case + default_stmts = cc->stmts; + default_fall = fall; + default_block = body; + continue; + } + + irBlock *next_cond = NULL; + for_array(j, cc->list) { + AstNode *expr = unparen_expr(cc->list.e[j]); + next_cond = ir_new_block(proc, clause, "match.case.next"); + irValue *cond = v_false; + if (is_ast_node_a_range(expr)) { + ast_node(ie, BinaryExpr, expr); + TokenKind op = {}; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + irValue *lhs = ir_build_expr(proc, ie->left); + irValue *rhs = ir_build_expr(proc, ie->right); + // TODO(bill): do short circuit here + irValue *cond_lhs = ir_emit_comp(proc, Token_LtEq, lhs, tag); + irValue *cond_rhs = ir_emit_comp(proc, op, tag, rhs); + cond = ir_emit_arith(proc, Token_And, cond_lhs, cond_rhs, t_bool); + } else { + cond = ir_emit_comp(proc, Token_CmpEq, tag, ir_build_expr(proc, expr)); + } + ir_emit_if(proc, cond, body, next_cond); + ir_start_block(proc, next_cond); + } + ir_start_block(proc, body); + + ir_push_target_list(proc, ms->label, done, NULL, fall); + ir_open_scope(proc); + ir_build_stmt_list(proc, cc->stmts); + ir_close_scope(proc, irDeferExit_Default, body); + ir_pop_target_list(proc); + + ir_emit_jump(proc, done); + proc->curr_block = next_cond; + // ir_start_block(proc, next_cond); + } + + if (default_block != NULL) { + ir_emit_jump(proc, default_block); + ir_start_block(proc, default_block); + + ir_push_target_list(proc, ms->label, done, NULL, default_fall); + ir_open_scope(proc); + ir_build_stmt_list(proc, default_stmts); + ir_close_scope(proc, irDeferExit_Default, default_block); + ir_pop_target_list(proc); + } + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + case_end; + + + case_ast_node(ms, TypeMatchStmt, node); + ir_emit_comment(proc, str_lit("TypeMatchStmt")); + gbAllocator allocator = proc->module->allocator; + + ast_node(as, AssignStmt, ms->tag); + GB_ASSERT(as->lhs.count == 1); + GB_ASSERT(as->rhs.count == 1); + + irValue *parent = ir_build_expr(proc, as->rhs.e[0]); + Type *parent_type = ir_type(parent); + bool is_parent_ptr = is_type_pointer(ir_type(parent)); + + MatchTypeKind match_type_kind = check_valid_type_match_type(ir_type(parent)); + GB_ASSERT(match_type_kind != MatchType_Invalid); + + irValue *parent_value = parent; + + irValue *parent_ptr = parent; + if (!is_parent_ptr) { + parent_ptr = ir_address_from_load_or_generate_local(proc, parent_ptr); + } + + irValue *tag_index = NULL; + irValue *union_data = NULL; + if (match_type_kind == MatchType_Union) { + ir_emit_comment(proc, str_lit("get union's tag")); + tag_index = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, parent_ptr)); + union_data = ir_emit_conv(proc, parent_ptr, t_rawptr); + } + + irBlock *start_block = ir_new_block(proc, node, "typematch.case.first"); + ir_emit_jump(proc, start_block); + ir_start_block(proc, start_block); + + // NOTE(bill): Append this later + irBlock *done = ir_new_block(proc, node, "typematch.done"); + AstNode *default_ = NULL; + + ast_node(body, BlockStmt, ms->body); + + gb_local_persist i32 weird_count = 0; + + for_array(i, body->stmts) { + AstNode *clause = body->stmts.e[i]; + ast_node(cc, CaseClause, clause); + if (cc->list.count == 0) { + default_ = clause; + continue; + } + + irBlock *body = ir_new_block(proc, clause, "typematch.body"); + irBlock *next = NULL; + Type *case_type = NULL; + for_array(type_index, cc->list) { + next = ir_new_block(proc, NULL, "typematch.next"); + case_type = type_of_expr(proc->module->info, cc->list.e[type_index]); + irValue *cond = NULL; + if (match_type_kind == MatchType_Union) { + Type *bt = type_deref(case_type); + irValue *index = NULL; + Type *ut = base_type(type_deref(parent_type)); + GB_ASSERT(ut->Record.kind == TypeRecord_Union); + for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) { + Entity *f = ut->Record.variants[variant_index]; + if (are_types_identical(f->type, bt)) { + index = ir_const_int(allocator, variant_index); + break; + } + } + GB_ASSERT(index != NULL); + cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index); + } else if (match_type_kind == MatchType_Any) { + irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1)); + irValue *case_ti = ir_type_info(proc, case_type); + cond = ir_emit_comp(proc, Token_CmpEq, any_ti, case_ti); + } + GB_ASSERT(cond != NULL); + + ir_emit_if(proc, cond, body, next); + ir_start_block(proc, next); + } + + Entity *case_entity = NULL; + { + Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause)); + GB_ASSERT(found != NULL); + case_entity = *found; + } + + + irValue *value = parent_value; + + ir_start_block(proc, body); + + if (cc->list.count == 1) { + bool any_or_not_ptr = is_type_any(type_deref(parent_type)) || !is_parent_ptr; + + Type *ct = case_entity->type; + if (any_or_not_ptr) { + ct = make_type_pointer(proc->module->allocator, ct); + } + GB_ASSERT_MSG(is_type_pointer(ct), "%s", type_to_string(ct)); + irValue *data = NULL; + if (match_type_kind == MatchType_Union) { + data = union_data; + } else if (match_type_kind == MatchType_Any) { + irValue *any_data = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 0)); + data = any_data; + } + value = ir_emit_conv(proc, data, ct); + if (any_or_not_ptr) { + value = ir_emit_load(proc, value); + } + } + + ir_store_type_case_implicit(proc, clause, value); + ir_type_case_body(proc, ms->label, clause, body, done); + ir_start_block(proc, next); + } + + if (default_ != NULL) { + ir_store_type_case_implicit(proc, default_, parent_value); + ir_type_case_body(proc, ms->label, default_, proc->curr_block, done); + } else { + ir_emit_jump(proc, done); + } + ir_start_block(proc, done); + case_end; + + case_ast_node(bs, BranchStmt, node); + irBlock *block = NULL; + + if (bs->label != NULL) { + irBranchBlocks bb = ir_lookup_branch_blocks(proc, bs->label); + switch (bs->token.kind) { + case Token_break: block = bb.break_; break; + case Token_continue: block = bb.continue_; break; + case Token_fallthrough: + GB_PANIC("fallthrough cannot have a label"); + break; + } + } else { + switch (bs->token.kind) { + case Token_break: + for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->break_; + } + break; + case Token_continue: + for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->continue_; + } + break; + case Token_fallthrough: + for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->fallthrough_; + } + break; + } + } + if (block != NULL) { + ir_emit_defer_stmts(proc, irDeferExit_Branch, block); + } + switch (bs->token.kind) { + case Token_break: ir_emit_comment(proc, str_lit("break")); break; + case Token_continue: ir_emit_comment(proc, str_lit("continue")); break; + case Token_fallthrough: ir_emit_comment(proc, str_lit("fallthrough")); break; + } + ir_emit_jump(proc, block); + ir_emit_unreachable(proc); + case_end; + + + + case_ast_node(pa, PushAllocator, node); + ir_emit_comment(proc, str_lit("PushAllocator")); + ir_open_scope(proc); + + irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context")); + irValue *prev_context = ir_add_local_generated(proc, t_context); + ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr)); + + ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false)); + + irValue *gep = ir_emit_struct_ep(proc, context_ptr, 1); + ir_emit_store(proc, gep, ir_build_expr(proc, pa->expr)); + + ir_build_stmt(proc, pa->body); + + ir_close_scope(proc, irDeferExit_Default, NULL); + case_end; + + + case_ast_node(pc, PushContext, node); + ir_emit_comment(proc, str_lit("PushContext")); + ir_open_scope(proc); + + irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context")); + irValue *prev_context = ir_add_local_generated(proc, t_context); + ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr)); + + ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false)); + + ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr)); + + ir_build_stmt(proc, pc->body); + + ir_close_scope(proc, irDeferExit_Default, NULL); + case_end; + + + } +} + + + + + + + +//////////////////////////////////////////////////////////////// +// +// @Procedure +// +//////////////////////////////////////////////////////////////// + +void ir_number_proc_registers(irProcedure *proc) { + i32 reg_index = 0; + for_array(i, proc->blocks) { + irBlock *b = proc->blocks.e[i]; + b->index = i; + for_array(j, b->instrs) { + irValue *value = b->instrs.e[j]; + GB_ASSERT(value->kind == irValue_Instr); + irInstr *instr = &value->Instr; + if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions + value->index = -1; + continue; + } + value->index = reg_index; + value->index_set = true; + reg_index++; + } + } +} + +void ir_begin_procedure_body(irProcedure *proc) { + array_add(&proc->module->procs, proc); + + array_init(&proc->blocks, heap_allocator()); + array_init(&proc->defer_stmts, heap_allocator()); + array_init(&proc->children, heap_allocator()); + array_init(&proc->branch_blocks, heap_allocator()); + + DeclInfo **found = map_decl_info_get(&proc->module->info->entities, hash_pointer(proc->entity)); + if (found != NULL) { + DeclInfo *decl = *found; + for_array(i, decl->labels) { + BlockLabel bl = decl->labels.e[i]; + irBranchBlocks bb = {bl.label, NULL, NULL}; + array_add(&proc->branch_blocks, bb); + } + } + + proc->decl_block = ir_new_block(proc, proc->type_expr, "decls"); + ir_start_block(proc, proc->decl_block); + proc->entry_block = ir_new_block(proc, proc->type_expr, "entry"); + ir_start_block(proc, proc->entry_block); + + if (proc->type->Proc.return_by_pointer) { + // NOTE(bill): this must be the first parameter stored + gbAllocator a = proc->module->allocator; + Type *ptr_type = make_type_pointer(a, reduce_tuple_to_single_type(proc->type->Proc.results)); + Entity *e = make_entity_param(a, NULL, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + + irValue *param = ir_value_param(a, proc, e, ptr_type); + param->Param.kind = irParamPass_Pointer; + + ir_module_add_value(proc->module, e, param); + proc->return_ptr = param; + } + + if (proc->type->Proc.params != NULL) { + ast_node(pt, ProcType, proc->type_expr); + isize param_index = 0; + isize q_index = 0; + + TypeTuple *params = &proc->type->Proc.params->Tuple; + for (isize i = 0; i < params->variable_count; i++) { + ast_node(fl, FieldList, pt->params); + GB_ASSERT(fl->list.count > 0); + GB_ASSERT(fl->list.e[0]->kind == AstNode_Field); + if (q_index == fl->list.e[param_index]->Field.names.count) { + q_index = 0; + param_index++; + } + ast_node(field, Field, fl->list.e[param_index]); + AstNode *name = field->names.e[q_index++]; + + Entity *e = params->variables[i]; + Type *abi_type = proc->type->Proc.abi_compat_params[i]; + if (!str_eq(e->token.string, str_lit("")) && + !str_eq(e->token.string, str_lit("_"))) { + irValue *param = ir_add_param(proc, e, name, abi_type); + array_add(&proc->params, param); + } + } + } + + +} + + +void ir_end_procedure_body(irProcedure *proc) { + if (proc->type->Proc.result_count == 0) { + ir_emit_return(proc, NULL); + } + + if (proc->curr_block->instrs.count == 0) { + ir_emit_unreachable(proc); + } + + proc->curr_block = proc->decl_block; + ir_emit_jump(proc, proc->entry_block); + proc->curr_block = NULL; + + ir_number_proc_registers(proc); +} + + +void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { + if (parent == NULL) { + if (str_eq(proc->name, str_lit("main"))) { + ir_emit_startup_runtime(proc); + } + } +} + +void ir_build_proc(irValue *value, irProcedure *parent) { + irProcedure *proc = &value->Proc; + + proc->parent = parent; + + if (proc->entity != NULL) { + irModule *m = proc->module; + CheckerInfo *info = m->info; + Entity *e = proc->entity; + String filename = e->token.pos.file; + AstFile **found = map_ast_file_get(&info->files, hash_string(filename)); + GB_ASSERT(found != NULL); + AstFile *f = *found; + irDebugInfo *di_file = NULL; + + irDebugInfo **di_file_found = map_ir_debug_info_get(&m->debug_info, hash_pointer(f)); + if (di_file_found) { + di_file = *di_file_found; + GB_ASSERT(di_file->kind == irDebugInfo_File); + } else { + di_file = ir_add_debug_info_file(proc, f); + } + + ir_add_debug_info_proc(proc, e, proc->name, di_file); + } + + if (proc->body != NULL) { + u32 prev_stmt_state_flags = proc->module->stmt_state_flags; + + if (proc->tags != 0) { + u32 in = proc->tags; + u32 out = proc->module->stmt_state_flags; + if (in & ProcTag_bounds_check) { + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; + } else if (in & ProcTag_no_bounds_check) { + out |= StmtStateFlag_no_bounds_check; + out &= ~StmtStateFlag_bounds_check; + } + proc->module->stmt_state_flags = out; + } + + + ir_begin_procedure_body(proc); + ir_insert_code_before_proc(proc, parent); + ir_build_stmt(proc, proc->body); + ir_end_procedure_body(proc); + + proc->module->stmt_state_flags = prev_stmt_state_flags; + } +} + + + + + + + +//////////////////////////////////////////////////////////////// +// +// @Module +// +//////////////////////////////////////////////////////////////// + + + +void ir_module_add_value(irModule *m, Entity *e, irValue *v) { + map_ir_value_set(&m->values, hash_pointer(e), v); +} + +void ir_init_module(irModule *m, Checker *c) { + // TODO(bill): Determine a decent size for the arena + isize token_count = c->parser->total_token_count; + isize arena_size = 4 * token_count * gb_size_of(irValue); + gb_arena_init_from_allocator(&m->arena, heap_allocator(), arena_size); + gb_arena_init_from_allocator(&m->tmp_arena, heap_allocator(), arena_size); + m->allocator = gb_arena_allocator(&m->arena); + m->tmp_allocator = gb_arena_allocator(&m->tmp_arena); + m->info = &c->info; + + map_ir_value_init(&m->values, heap_allocator()); + map_ir_value_init(&m->members, heap_allocator()); + map_ir_debug_info_init(&m->debug_info, heap_allocator()); + map_string_init(&m->entity_names, heap_allocator()); + array_init(&m->procs, heap_allocator()); + array_init(&m->procs_to_generate, heap_allocator()); + array_init(&m->foreign_library_paths, heap_allocator()); + + // Default states + m->stmt_state_flags = 0; + m->stmt_state_flags |= StmtStateFlag_bounds_check; + + { + // Add type info data + { + isize max_index = -1; + for_array(type_info_map_index, m->info->type_info_map.entries) { + MapIsizeEntry *entry = &m->info->type_info_map.entries.e[type_info_map_index]; + Type *t = cast(Type *)cast(uintptr)entry->key.key; + t = default_type(t); + isize entry_index = ir_type_info_index(m->info, t); + if (max_index < entry_index) { + max_index = entry_index; + } + } + isize max_type_info_count = max_index+1; + + String name = str_lit(IR_TYPE_INFO_DATA_NAME); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, max_type_info_count), false); + irValue *g = ir_value_global(m->allocator, e, NULL); + g->Global.is_private = true; + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + ir_global_type_info_data = g; + } + + // Type info member buffer + { + // NOTE(bill): Removes need for heap allocation by making it global memory + isize count = 0; + + for_array(entry_index, m->info->type_info_map.entries) { + MapIsizeEntry *entry = &m->info->type_info_map.entries.e[entry_index]; + Type *t = cast(Type *)cast(uintptr)entry->key.key; + + switch (t->kind) { + case Type_Record: + switch (t->Record.kind) { + case TypeRecord_Struct: + case TypeRecord_RawUnion: + count += t->Record.field_count; + break; + case TypeRecord_Union: + count += t->Record.field_count; + count += t->Record.variant_count; + break; + } + break; + case Type_Tuple: + count += t->Tuple.variable_count; + break; + } + } + + { + String name = str_lit(IR_TYPE_INFO_TYPES_NAME); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), + make_type_array(m->allocator, t_type_info_ptr, count), false); + irValue *g = ir_value_global(m->allocator, e, NULL); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + ir_global_type_info_member_types = g; + } + { + String name = str_lit(IR_TYPE_INFO_NAMES_NAME); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), + make_type_array(m->allocator, t_string, count), false); + irValue *g = ir_value_global(m->allocator, e, NULL); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + ir_global_type_info_member_names = g; + } + { + String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), + make_type_array(m->allocator, t_int, count), false); + irValue *g = ir_value_global(m->allocator, e, NULL); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + ir_global_type_info_member_offsets = g; + } + + { + String name = str_lit(IR_TYPE_INFO_USINGS_NAME); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), + make_type_array(m->allocator, t_bool, count), false); + irValue *g = ir_value_global(m->allocator, e, NULL); + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + ir_global_type_info_member_usings = g; + } + } + } + + { + irDebugInfo *di = ir_alloc_debug_info(m->allocator, irDebugInfo_CompileUnit); + di->CompileUnit.file = m->info->files.entries.e[0].value; // Zeroth is the init file + di->CompileUnit.producer = str_lit("odin"); + + map_ir_debug_info_set(&m->debug_info, hash_pointer(m), di); + } +} + +void ir_destroy_module(irModule *m) { + map_ir_value_destroy(&m->values); + map_ir_value_destroy(&m->members); + map_string_destroy(&m->entity_names); + map_ir_debug_info_destroy(&m->debug_info); + array_free(&m->procs); + array_free(&m->procs_to_generate); + array_free(&m->foreign_library_paths); + gb_arena_free(&m->arena); +} + + + +//////////////////////////////////////////////////////////////// +// +// @Code Generation +// +//////////////////////////////////////////////////////////////// + + +bool ir_gen_init(irGen *s, Checker *c) { + if (global_error_collector.count != 0) { + return false; + } + + isize tc = c->parser->total_token_count; + if (tc < 2) { + return false; + } + + ir_init_module(&s->module, c); + // s->module.generate_debug_info = false; + + String init_fullpath = c->parser->init_fullpath; + // TODO(bill): generate appropriate output name + int pos = cast(int)string_extension_position(init_fullpath); + int dir_pos = cast(int)string_extension_position(init_fullpath); + s->output_name = filename_from_path(init_fullpath); + s->output_base = make_string(init_fullpath.text, pos); + gbFileError err = gb_file_create(&s->output_file, gb_bprintf("%.*s.ll", pos, init_fullpath.text)); + if (err != gbFileError_None) { + return false; + } + + return true; +} + +void ir_gen_destroy(irGen *s) { + ir_destroy_module(&s->module); + gb_file_close(&s->output_file); +} + + + +// +// Type Info stuff +// +irValue *ir_get_type_info_ptr(irProcedure *proc, Type *type) { + i32 index = cast(i32)ir_type_info_index(proc->module->info, type); + // gb_printf_err("%d %s\n", index, type_to_string(type)); + irValue *ptr = ir_emit_array_epi(proc, ir_global_type_info_data, index); + return ir_emit_bitcast(proc, ptr, t_type_info_ptr); +} + +irValue *ir_type_info_member_types_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_types, ir_global_type_info_member_types_index); + ir_global_type_info_member_types_index += count; + return offset; +} +irValue *ir_type_info_member_names_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_names, ir_global_type_info_member_names_index); + ir_global_type_info_member_names_index += count; + return offset; +} +irValue *ir_type_info_member_offsets_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_offsets, ir_global_type_info_member_offsets_index); + ir_global_type_info_member_offsets_index += count; + return offset; +} +irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_usings, ir_global_type_info_member_usings_index); + ir_global_type_info_member_usings_index += count; + return offset; +} + + + + + +void ir_add_foreign_library_path(irModule *m, Entity *e) { + GB_ASSERT(e != NULL); + String library_path = e->LibraryName.path; + if (library_path.len == 0) { + return; + } + + for_array(path_index, m->foreign_library_paths) { + String path = m->foreign_library_paths.e[path_index]; +#if defined(GB_SYSTEM_WINDOWS) + if (str_eq_ignore_case(path, library_path)) { +#else + if (str_eq(path, library_path)) { +#endif + return; + } + } + array_add(&m->foreign_library_paths, library_path); +} + + +void ir_gen_tree(irGen *s) { + irModule *m = &s->module; + CheckerInfo *info = m->info; + gbAllocator a = m->allocator; + + if (v_zero == NULL) { + v_zero = ir_const_int (m->allocator, 0); + v_one = ir_const_int (m->allocator, 1); + v_zero32 = ir_const_i32 (m->allocator, 0); + v_one32 = ir_const_i32 (m->allocator, 1); + v_two32 = ir_const_i32 (m->allocator, 2); + v_false = ir_const_bool(m->allocator, false); + v_true = ir_const_bool(m->allocator, true); + v_raw_nil = ir_value_constant(m->allocator, t_rawptr, exact_value_pointer(0)); + } + + isize global_variable_max_count = 0; + Entity *entry_point = NULL; + bool has_dll_main = false; + bool has_win_main = false; + + for_array(i, info->entities.entries) { + MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + String name = e->token.string; + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } else if (e->kind == Entity_Procedure && !e->scope->is_global) { + if (e->scope->is_init && str_eq(name, str_lit("main"))) { + entry_point = e; + } + if ((e->Procedure.tags & ProcTag_export) != 0 || + (e->Procedure.link_name.len > 0) || + (e->scope->is_file && e->Procedure.link_name.len > 0)) { + if (!has_dll_main && str_eq(name, str_lit("DllMain"))) { + has_dll_main = true; + } else if (!has_win_main && str_eq(name, str_lit("WinMain"))) { + has_win_main = true; + } + } + } + } + + typedef struct irGlobalVariable { + irValue *var, *init; + DeclInfo *decl; + } irGlobalVariable; + Array(irGlobalVariable) global_variables; + array_init_reserve(&global_variables, m->tmp_allocator, global_variable_max_count); + + m->entry_point_entity = entry_point; + m->min_dep_map = generate_minimum_dependency_map(info, entry_point); + + for_array(i, info->entities.entries) { + MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + Entity *e = cast(Entity *)entry->key.ptr; + String name = e->token.string; + DeclInfo *decl = entry->value; + Scope *scope = e->scope; + + if (!scope->is_file) { + continue; + } + + if (map_entity_get(&m->min_dep_map, hash_pointer(e)) == NULL) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } + + if (!scope->is_global) { + if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) { + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + // Handle later + } else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) { + } else { + name = ir_mangle_name(s, e->token.pos.file, e); + } + } + map_string_set(&m->entity_names, hash_pointer(e), name); + + switch (e->kind) { + case Entity_TypeName: + GB_ASSERT(e->type->kind == Type_Named); + ir_gen_global_type_name(m, e, name); + break; + + case Entity_Variable: { + irValue *g = ir_value_global(a, e, NULL); + g->Global.name = name; + g->Global.is_thread_local = e->Variable.is_thread_local; + + irGlobalVariable var = {}; + var.var = g; + var.decl = decl; + + if (decl->init_expr != NULL) { + if (is_type_any(e->type)) { + + } else { + TypeAndValue tav = type_and_value_of_expr(info, decl->init_expr); + if (tav.mode != Addressing_Invalid) { + if (tav.value.kind != ExactValue_Invalid) { + ExactValue v = tav.value; + // if (v.kind != ExactValue_String) { + g->Global.value = ir_add_module_constant(m, tav.type, v); + // } + } + } + } + } + + if (g->Global.value == NULL) { + array_add(&global_variables, var); + } + + ir_module_add_value(m, e, g); + map_ir_value_set(&m->members, hash_string(name), g); + } break; + + case Entity_Procedure: { + ast_node(pd, ProcLit, decl->proc_lit); + String original_name = name; + AstNode *body = pd->body; + if (e->Procedure.is_foreign) { + name = e->token.string; // NOTE(bill): Don't use the mangled name + ir_add_foreign_library_path(m, e->Procedure.foreign_library); + } + if (pd->foreign_name.len > 0) { + name = pd->foreign_name; + } else if (pd->link_name.len > 0) { + name = pd->link_name; + } + + AstNode *type_expr = decl->proc_lit->ProcLit.type; + + irValue *p = ir_value_procedure(a, m, e, e->type, type_expr, body, name); + p->Proc.tags = pd->tags; + + ir_module_add_value(m, e, p); + HashKey hash_name = hash_string(name); + if (map_ir_value_get(&m->members, hash_name) == NULL) { + map_ir_value_multi_insert(&m->members, hash_name, p); + } + } break; + } + } + + for_array(i, m->members.entries) { + MapIrValueEntry *entry = &m->members.entries.e[i]; + irValue *v = entry->value; + if (v->kind == irValue_Proc) { + ir_build_proc(v, NULL); + } + } + + irDebugInfo *compile_unit = m->debug_info.entries.e[0].value; + GB_ASSERT(compile_unit->kind == irDebugInfo_CompileUnit); + irDebugInfo *all_procs = ir_alloc_debug_info(m->allocator, irDebugInfo_AllProcs); + + isize all_proc_max_count = 0; + for_array(i, m->debug_info.entries) { + MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + irDebugInfo *di = entry->value; + di->id = i; + if (di->kind == irDebugInfo_Proc) { + all_proc_max_count++; + } + } + + array_init_reserve(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count); + map_ir_debug_info_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped + compile_unit->CompileUnit.all_procs = all_procs; + + + for_array(i, m->debug_info.entries) { + MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + irDebugInfo *di = entry->value; + if (di->kind == irDebugInfo_Proc) { + array_add(&all_procs->AllProcs.procs, di); + } + } + +#if defined(GB_SYSTEM_WINDOWS) + if (build_context.is_dll && !has_dll_main) { + // DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32 + String name = str_lit("DllMain"); + Type *proc_params = make_type_tuple(a); + Type *proc_results = make_type_tuple(a); + + Scope *proc_scope = gb_alloc_item(a, Scope); + + proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 3); + proc_params->Tuple.variable_count = 3; + + proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1); + proc_results->Tuple.variable_count = 1; + + proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false); + proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false); + proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false); + + proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false); + + + Type *proc_type = make_type_proc(a, proc_scope, + proc_params, 3, + proc_results, 1, false, ProcCC_Std); + + AstNode *body = gb_alloc_item(a, AstNode); + Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); + irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name); + + map_ir_value_set(&m->values, hash_pointer(e), p); + map_ir_value_set(&m->members, hash_string(name), p); + + irProcedure *proc = &p->Proc; + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? + e->Procedure.link_name = name; + + ir_begin_procedure_body(proc); + + // NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx + // DLL_PROCESS_ATTACH == 1 + + irAddr reason_addr = ir_build_addr_from_entity(proc, proc_params->Tuple.variables[1], NULL); + irValue *cond = ir_emit_comp(proc, Token_CmpEq, ir_addr_load(proc, reason_addr), v_one32); + irBlock *then = ir_new_block(proc, NULL, "if.then"); + irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later + ir_emit_if(proc, cond, then, done); + ir_start_block(proc, then); + + { + String main_name = str_lit("main"); + irValue **found = map_ir_value_get(&m->members, hash_string(main_name)); + if (found != NULL) { + ir_emit_call(proc, *found, NULL, 0); + } else { + ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); + } + } + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + ir_emit_return(proc, v_one32); + + + ir_end_procedure_body(proc); + } +#endif +#if 0 && defined(GB_SYSTEM_WINDOWS) + if (!m->build_context->is_dll && !has_win_main) { + // WinMain :: proc(inst, prev: rawptr, cmd_line: ^byte, cmd_show: i32) -> i32 + String name = str_lit("WinMain"); + Type *proc_params = make_type_tuple(a); + Type *proc_results = make_type_tuple(a); + + Scope *proc_scope = gb_alloc_item(a, Scope); + + proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 4); + proc_params->Tuple.variable_count = 4; + + proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1); + proc_results->Tuple.variable_count = 1; + + proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false); + proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false); + proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false); + proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32, false); + + proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false); + + + Type *proc_type = make_type_proc(a, proc_scope, + proc_params, 4, + proc_results, 1, false, ProcCC_Std); + + AstNode *body = gb_alloc_item(a, AstNode); + Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); + irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name); + + m->entry_point_entity = e; + + map_ir_value_set(&m->values, hash_pointer(e), p); + map_ir_value_set(&m->members, hash_string(name), p); + + irProcedure *proc = &p->Proc; + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? + e->Procedure.link_name = name; + + ir_begin_procedure_body(proc); + ir_emit_global_call(proc, "main", NULL, 0); + ir_emit_return(proc, v_one32); + ir_end_procedure_body(proc); + } +#endif + { // Startup Runtime + // Cleanup(bill): probably better way of doing code insertion + String name = str_lit(IR_STARTUP_RUNTIME_PROC_NAME); + Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope), + NULL, 0, + NULL, 0, false, ProcCC_Odin); + AstNode *body = gb_alloc_item(a, AstNode); + Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); + irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name); + + map_ir_value_set(&m->values, hash_pointer(e), p); + map_ir_value_set(&m->members, hash_string(name), p); + + + irProcedure *proc = &p->Proc; + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? + + ir_begin_procedure_body(proc); + + // TODO(bill): Should do a dependency graph do check which order to initialize them in? + for_array(i, global_variables) { + irGlobalVariable *var = &global_variables.e[i]; + if (var->decl->init_expr != NULL) { + var->init = ir_build_expr(proc, var->decl->init_expr); + } + } + + // NOTE(bill): Initialize constants first + for_array(i, global_variables) { + irGlobalVariable *var = &global_variables.e[i]; + if (var->init != NULL && var->init->kind == irValue_Constant) { + Type *t = type_deref(ir_type(var->var)); + if (is_type_any(t)) { + // NOTE(bill): Edge case for `any` type + Type *var_type = default_type(ir_type(var->init)); + irValue *g = ir_add_global_generated(proc->module, var_type, var->init); + irValue *data = ir_emit_struct_ep(proc, var->var, 0); + irValue *ti = ir_emit_struct_ep(proc, var->var, 1); + ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); + ir_emit_store(proc, ti, ir_type_info(proc, var_type)); + } else { + ir_emit_store(proc, var->var, var->init); + } + } + } + + for_array(i, global_variables) { + irGlobalVariable *var = &global_variables.e[i]; + if (var->init != NULL && var->init->kind != irValue_Constant) { + Type *t = type_deref(ir_type(var->var)); + if (is_type_any(t)) { + // NOTE(bill): Edge case for `any` type + Type *var_type = default_type(ir_type(var->init)); + irValue *g = ir_add_global_generated(proc->module, var_type, var->init); + ir_emit_store(proc, g, var->init); + + irValue *data = ir_emit_struct_ep(proc, var->var, 0); + irValue *ti = ir_emit_struct_ep(proc, var->var, 1); + ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); + ir_emit_store(proc, ti, ir_type_info(proc, var_type)); + } else { + ir_emit_store(proc, var->var, var->init); + } + } + } + + { // NOTE(bill): Setup type_info data + CheckerInfo *info = proc->module->info; + + if (true) { + irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table")); + Type *type = base_type(type_deref(ir_type(ir_global_type_info_data))); + GB_ASSERT(is_type_array(type)); + irValue *len = ir_const_int(proc->module->allocator, type->Array.count); + ir_fill_slice(proc, global_type_table, + ir_emit_array_epi(proc, ir_global_type_info_data, 0), + len, len); + } + + + // Useful types + Type *t_i64_slice_ptr = make_type_pointer(a, make_type_slice(a, t_i64)); + Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string)); + + i32 type_info_member_types_index = 0; + i32 type_info_member_names_index = 0; + i32 type_info_member_offsets_index = 0; + + for_array(type_info_map_index, info->type_info_map.entries) { + MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index]; + Type *t = cast(Type *)cast(uintptr)entry->key.key; + t = default_type(t); + isize entry_index = ir_type_info_index(info, t); + + irValue *tag = NULL; + irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, entry_index); + + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 0), ir_const_int(a, type_size_of(a, t))); + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 1), ir_const_int(a, type_align_of(a, t))); + + + switch (t->kind) { + case Type_Named: { + ir_emit_comment(proc, str_lit("TypeInfoNamed")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_named_ptr); + + // TODO(bill): Which is better? The mangled name or actual name? + irValue *name = ir_const_string(a, t->Named.type_name->token.string); + irValue *gtip = ir_get_type_info_ptr(proc, t->Named.base); + + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), name); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), gtip); + } break; + + case Type_Basic: + ir_emit_comment(proc, str_lit("TypeInfoBasic")); + switch (t->Basic.kind) { + case Basic_bool: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_boolean_ptr); + break; + + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + case Basic_int: + case Basic_uint: { + tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr); + irValue *is_signed = ir_const_bool(a, (t->Basic.flags & BasicFlag_Unsigned) == 0); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), is_signed); + } break; + + case Basic_rune: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_rune_ptr); + break; + + // case Basic_f16: + case Basic_f32: + case Basic_f64: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr); + break; + + // case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr); + break; + + case Basic_rawptr: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); + break; + + case Basic_string: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_string_ptr); + break; + + case Basic_any: + tag = ir_emit_conv(proc, ti_ptr, t_type_info_any_ptr); + break; + } + break; + + case Type_Pointer: { + ir_emit_comment(proc, str_lit("TypeInfoPointer")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + } break; + case Type_Atomic: { + ir_emit_comment(proc, str_lit("TypeInfoAtomic")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_atomic_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + } break; + case Type_Array: { + ir_emit_comment(proc, str_lit("TypeInfoArray")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + + isize ez = type_size_of(a, t->Array.elem); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + ir_emit_store(proc, elem_size, ir_const_int(a, ez)); + + irValue *count = ir_emit_struct_ep(proc, tag, 4); + ir_emit_store(proc, count, ir_const_int(a, t->Array.count)); + + } break; + case Type_DynamicArray: { + ir_emit_comment(proc, str_lit("TypeInfoDynamicArray")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + + isize ez = type_size_of(a, t->DynamicArray.elem); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + ir_emit_store(proc, elem_size, ir_const_int(a, ez)); + } break; + case Type_Slice: { + ir_emit_comment(proc, str_lit("TypeInfoSlice")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + + isize ez = type_size_of(a, t->Slice.elem); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + ir_emit_store(proc, elem_size, ir_const_int(a, ez)); + } break; + case Type_Vector: { + ir_emit_comment(proc, str_lit("TypeInfoVector")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + + isize ez = type_size_of(a, t->Vector.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_int(a, ez)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ir_const_int(a, t->Vector.count)); + + } break; + case Type_Proc: { + ir_emit_comment(proc, str_lit("TypeInfoProc")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_procedure_ptr); + + irValue *params = ir_emit_struct_ep(proc, tag, 2); + irValue *results = ir_emit_struct_ep(proc, tag, 3); + irValue *variadic = ir_emit_struct_ep(proc, tag, 4); + irValue *convention = ir_emit_struct_ep(proc, tag, 5); + + if (t->Proc.params != NULL) { + ir_emit_store(proc, params, ir_get_type_info_ptr(proc, t->Proc.params)); + } + if (t->Proc.results != NULL) { + ir_emit_store(proc, results, ir_get_type_info_ptr(proc, t->Proc.results)); + } + ir_emit_store(proc, variadic, ir_const_bool(a, t->Proc.variadic)); + ir_emit_store(proc, convention, ir_const_int(a, t->Proc.calling_convention)); + + // TODO(bill): TypeInfo for procedures + } break; + case Type_Tuple: { + ir_emit_comment(proc, str_lit("TypeInfoTuple")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 2); + + irValue *memory_types = ir_type_info_member_types_offset(proc, t->Tuple.variable_count); + irValue *memory_names = ir_type_info_member_names_offset(proc, t->Tuple.variable_count); + + for (isize i = 0; i < t->Tuple.variable_count; i++) { + // NOTE(bill): offset is not used for tuples + Entity *f = t->Tuple.variables[i]; + + irValue *index = ir_const_int(a, i); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_const_string(a, f->token.string)); + } + } + + irValue *count = ir_const_int(a, t->Tuple.variable_count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); + } break; + case Type_Record: { + switch (t->Record.kind) { + case TypeRecord_Struct: { + ir_emit_comment(proc, str_lit("TypeInfoStruct")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 2); + + { + irValue *packed = ir_const_bool(a, t->Record.is_packed); + irValue *ordered = ir_const_bool(a, t->Record.is_ordered); + irValue *custom_align = ir_const_bool(a, t->Record.custom_align != 0); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), ordered); + ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), custom_align); + } + + irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count); + irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count); + irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count); + irValue *memory_usings = ir_type_info_member_usings_offset(proc, t->Record.field_count); + + type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet + for (isize source_index = 0; source_index < t->Record.field_count; source_index++) { + // TODO(bill): Order fields in source order not layout order + Entity *f = t->Record.fields_in_src_order[source_index]; + irValue *tip = ir_get_type_info_ptr(proc, f->type); + i64 foffset = t->Record.offsets[f->Variable.field_index]; + GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); + + irValue *index = ir_const_int(a, source_index); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index); + irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); + + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_const_string(a, f->token.string)); + } + ir_emit_store(proc, offset, ir_const_int(a, foffset)); + ir_emit_store(proc, is_using, ir_const_bool(a, (f->flags&EntityFlag_Using) != 0)); + } + + irValue *count = ir_const_int(a, t->Record.field_count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 3), memory_usings, count, count); + } break; + case TypeRecord_Union: { + ir_emit_comment(proc, str_lit("TypeInfoUnion")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr); + + { + irValue *common_fields = ir_emit_struct_ep(proc, tag, 2); + + isize field_count = t->Record.field_count; + irValue *memory_types = ir_type_info_member_types_offset(proc, field_count); + irValue *memory_names = ir_type_info_member_names_offset(proc, field_count); + irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, field_count); + + type_set_offsets(a, t); // NOTE(bill): Just incase the offsets have not been set yet + for (isize field_index = 0; field_index < field_count; field_index++) { + // TODO(bill): Order fields in source order not layout order + Entity *f = t->Record.fields[field_index]; + irValue *tip = ir_get_type_info_ptr(proc, f->type); + i64 foffset = t->Record.offsets[f->Variable.field_index]; + GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); + + irValue *index = ir_const_int(a, field_index); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index); + + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_const_string(a, f->token.string)); + } + ir_emit_store(proc, offset, ir_const_int(a, foffset)); + } + + + irValue *count = ir_const_int(a, field_count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, count, count); + } + + { + irValue *variant_names = ir_emit_struct_ep(proc, tag, 3); + irValue *variant_types = ir_emit_struct_ep(proc, tag, 4); + + isize variant_count = gb_max(0, t->Record.variant_count-1); + irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count); + irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count); + + // NOTE(bill): Zeroth is nil so ignore it + for (isize variant_index = 0; variant_index < variant_count; variant_index++) { + Entity *f = t->Record.variants[variant_index+1]; // Skip zeroth + irValue *tip = ir_get_type_info_ptr(proc, f->type); + + irValue *index = ir_const_int(a, variant_index); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_const_string(a, f->token.string)); + } + } + + irValue *count = ir_const_int(a, variant_count); + ir_fill_slice(proc, variant_names, memory_names, count, count); + ir_fill_slice(proc, variant_types, memory_types, count, count); + } + + } break; + case TypeRecord_RawUnion: { + ir_emit_comment(proc, str_lit("TypeInfoRawUnion")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr); + irValue *record = ir_emit_struct_ep(proc, tag, 2); + + irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count); + irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count); + irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count); + + for (isize i = 0; i < t->Record.field_count; i++) { + Entity *f = t->Record.fields[i]; + irValue *index = ir_const_int(a, i); + irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); + // NOTE(bill): Offsets are always 0 + + ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); + if (f->token.string.len > 0) { + irValue *name = ir_emit_ptr_offset(proc, memory_names, index); + ir_emit_store(proc, name, ir_const_string(a, f->token.string)); + } + } + + irValue *count = ir_const_int(a, t->Record.field_count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count); + } break; + case TypeRecord_Enum: + ir_emit_comment(proc, str_lit("TypeInfoEnum")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); + { + GB_ASSERT(t->Record.enum_base_type != NULL); + irValue *base = ir_type_info(proc, t->Record.enum_base_type); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), base); + + if (t->Record.field_count > 0) { + Entity **fields = t->Record.fields; + isize count = t->Record.field_count; + irValue *name_array = ir_generate_array(m, t_string, count, + str_lit("__$enum_names"), cast(i64)entry_index); + irValue *value_array = ir_generate_array(m, t_type_info_enum_value, count, + str_lit("__$enum_values"), cast(i64)entry_index); + + bool is_value_int = is_type_integer(t->Record.enum_base_type); + + for (isize i = 0; i < count; i++) { + irValue *name_ep = ir_emit_array_epi(proc, name_array, i); + irValue *value_ep = ir_emit_array_epi(proc, value_array, i); + + ExactValue value = fields[i]->Constant.value; + + if (is_value_int) { + value_ep = ir_emit_conv(proc, value_ep, t_i128_ptr); + ir_emit_store(proc, value_ep, ir_value_constant(a, t_i128, value)); + } else { + GB_ASSERT(is_type_float(t->Record.enum_base_type)); + f64 f = value.value_float; + value_ep = ir_emit_conv(proc, value_ep, t_f64_ptr); + ir_emit_store(proc, value_ep, ir_const_f64(a, f)); + } + + ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string)); + } + + irValue *v_count = ir_const_int(a, count); + + irValue *names = ir_emit_struct_ep(proc, tag, 3); + irValue *name_array_elem = ir_array_elem(proc, name_array); + ir_fill_slice(proc, names, name_array_elem, v_count, v_count); + + irValue *values = ir_emit_struct_ep(proc, tag, 4); + irValue *value_array_elem = ir_array_elem(proc, value_array); + ir_fill_slice(proc, values, value_array_elem, v_count, v_count); + } + } + break; + } + } break; + case Type_Map: { + ir_emit_comment(proc, str_lit("TypeInfoMap")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + + irValue *key = ir_emit_struct_ep(proc, tag, 2); + irValue *value = ir_emit_struct_ep(proc, tag, 3); + irValue *generated_struct = ir_emit_struct_ep(proc, tag, 4); + irValue *count = ir_emit_struct_ep(proc, tag, 5); + + ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key)); + ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value)); + ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type)); + ir_emit_store(proc, count, ir_const_int(a, t->Map.count)); + } break; + + case Type_BitField: { + ir_emit_comment(proc, str_lit("TypeInfoBitField")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + // names: []string, + // bits: []u32, + // offsets: []u32, + isize count = t->BitField.field_count; + if (count > 0) { + Entity **fields = t->BitField.fields; + irValue *name_array = ir_generate_array(m, t_string, count, str_lit("__$bit_field_names"), cast(i64)entry_index); + irValue *bit_array = ir_generate_array(m, t_u32, count, str_lit("__$bit_field_bits"), cast(i64)entry_index); + irValue *offset_array = ir_generate_array(m, t_u32, count, str_lit("__$bit_field_offsets"), cast(i64)entry_index); + + for (isize i = 0; i < count; i++) { + Entity *f = fields[i]; + GB_ASSERT(f->type != NULL); + GB_ASSERT(f->type->kind == Type_BitFieldValue); + irValue *name_ep = ir_emit_array_epi(proc, name_array, i); + irValue *bit_ep = ir_emit_array_epi(proc, bit_array, i); + irValue *offset_ep = ir_emit_array_epi(proc, offset_array, i); + + ir_emit_store(proc, name_ep, ir_const_string(a, f->token.string)); + ir_emit_store(proc, bit_ep, ir_const_u32(a, f->type->BitFieldValue.bits)); + ir_emit_store(proc, offset_ep, ir_const_u32(a, t->BitField.offsets[i])); + + } + + irValue *v_count = ir_const_int(a, count); + + irValue *names = ir_emit_struct_ep(proc, tag, 3); + irValue *name_array_elem = ir_array_elem(proc, name_array); + ir_fill_slice(proc, names, name_array_elem, v_count, v_count); + + irValue *bits = ir_emit_struct_ep(proc, tag, 4); + irValue *bit_array_elem = ir_array_elem(proc, bit_array); + ir_fill_slice(proc, bits, bit_array_elem, v_count, v_count); + + irValue *offsets = ir_emit_struct_ep(proc, tag, 5); + irValue *offset_array_elem = ir_array_elem(proc, offset_array); + ir_fill_slice(proc, offsets, offset_array_elem, v_count, v_count); + } + } break; + } + + + if (tag != NULL) { + Type *tag_type = type_deref(ir_type(tag)); + GB_ASSERT(is_type_named(tag_type)); + Type *ti = base_type(t_type_info); + bool found = false; + for (isize i = 1; i < ti->Record.variant_count; i++) { + Entity *f = ti->Record.variants[i]; + if (are_types_identical(f->type, tag_type)) { + found = true; + irValue *tag = ir_const_int(a, i); + irValue *ptr = ir_emit_union_tag_ptr(proc, ti_ptr); + ir_emit_store(proc, ptr, tag); + break; + } + } + GB_ASSERT_MSG(found, "%s", type_to_string(tag_type)); + } else { + GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t)); + } + } + } + + ir_end_procedure_body(proc); + } + + for_array(type_info_map_index, info->type_info_map.entries) { + MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index]; + Type *t = cast(Type *)cast(uintptr)entry->key.key; + t = default_type(t); + isize entry_index = entry->value; + + gbString s = type_to_string(t); + GB_ASSERT(s[0] != 0); + // gb_printf_err("%s\n", s); + } + + + + + for_array(i, m->procs_to_generate) { + ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent); + } + + // Number debug info + for_array(i, m->debug_info.entries) { + MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + irDebugInfo *di = entry->value; + di->id = i; + } + + + + // m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"); +} + -- cgit v1.2.3 From 13deb4706c37acbababc6f60a1b6ec58c630a3f5 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 12:37:07 +0100 Subject: Update `String` to use overloading --- src/build_settings.cpp | 26 ++++++++-------- src/check_decl.cpp | 4 +-- src/check_expr.cpp | 58 ++++++++++++++++++------------------ src/check_stmt.cpp | 14 ++++----- src/checker.cpp | 24 +++++++-------- src/entity.cpp | 2 +- src/exact_value.cpp | 4 ++- src/integer128.cpp | 8 ++--- src/ir.cpp | 22 +++++++------- src/ir_print.cpp | 8 ++--- src/main.cpp | 18 ++++------- src/map.cpp | 2 +- src/parser.cpp | 80 ++++++++++++++++++++++++------------------------- src/ssa.cpp | 16 +++++----- src/string.cpp | 81 +++++++++++++++++++++++++++++++++++--------------- src/tokenizer.cpp | 2 +- src/types.cpp | 30 +++++++++---------- 17 files changed, 213 insertions(+), 186 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 0ba38e30f..1229c466c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -65,7 +65,7 @@ String odin_root_dir(void) { GetModuleFileNameW(NULL, text, len); path = string16_to_string(heap_allocator(), make_string16(text, len)); for (i = path.len-1; i >= 0; i--) { - u8 c = path.text[i]; + u8 c = path[i]; if (c == '/' || c == '\\') { break; } @@ -118,7 +118,7 @@ String odin_root_dir(void) { path = make_string(text, len); for (i = path.len-1; i >= 0; i--) { - u8 c = path.text[i]; + u8 c = path[i]; if (c == '/' || c == '\\') { break; } @@ -175,7 +175,7 @@ String odin_root_dir(void) { path = make_string(text, len); for (i = path.len-1; i >= 0; i--) { - u8 c = path.text[i]; + u8 c = path[i]; if (c == '/' || c == '\\') { break; } @@ -200,10 +200,10 @@ String path_to_fullpath(gbAllocator a, String s) { String16 string16 = string_to_string16(string_buffer_allocator, s); String result = {0}; - DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL); + DWORD len = GetFullPathNameW(&string16[0], 0, NULL, NULL); if (len != 0) { wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); - GetFullPathNameW(string16.text, len, text, NULL); + GetFullPathNameW(&string16[0], len, text, NULL); text[len] = 0; result = string16_to_string(a, make_string16(text, len)); } @@ -212,7 +212,7 @@ String path_to_fullpath(gbAllocator a, String s) { } #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) String path_to_fullpath(gbAllocator a, String s) { - char *p = realpath(cast(char *)s.text, 0); + char *p = realpath(cast(char *)&s[0], 0); if(p == NULL) return make_string_c(""); return make_string_c(p); @@ -229,8 +229,8 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) { u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); isize i = 0; - gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len; - gb_memmove(str+i, path.text, path.len); + gb_memmove(str+i, &base_dir[0], base_dir.len); i += base_dir.len; + gb_memmove(str+i, &path[0], path.len); str[str_len] = '\0'; res = path_to_fullpath(a, make_string(str, str_len)); gb_free(heap_allocator(), str); @@ -247,9 +247,9 @@ String get_fullpath_core(gbAllocator a, String path) { isize str_len = module_dir.len + core_len + path.len; u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); - gb_memmove(str, module_dir.text, module_dir.len); + gb_memmove(str, &module_dir[0], module_dir.len); gb_memmove(str+module_dir.len, core, core_len); - gb_memmove(str+module_dir.len+core_len, path.text, path.len); + gb_memmove(str+module_dir.len+core_len, &path[0], path.len); str[str_len] = '\0'; res = path_to_fullpath(a, make_string(str, str_len)); @@ -294,7 +294,7 @@ void init_build_context(void) { // NOTE(zangent): MacOS systems are x64 only, so ld doesn't have // an architecture option. All compilation done on MacOS must be x64. - GB_ASSERT(str_eq(bc->ODIN_ARCH, str_lit("amd64"))); + GB_ASSERT(bc->ODIN_ARCH == "amd64"); #define LINK_FLAG_X64 "" #define LINK_FLAG_X86 "" @@ -311,12 +311,12 @@ void init_build_context(void) { #define LINK_FLAG_X86 "-arch x86" #endif - if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) { + if (bc->ODIN_ARCH == "amd64") { bc->word_size = 8; bc->max_align = 16; bc->llc_flags = str_lit("-march=x86-64 "); bc->link_flags = str_lit(LINK_FLAG_X64 " "); - } else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) { + } else if (bc->ODIN_ARCH == "x86") { bc->word_size = 4; bc->max_align = 8; bc->llc_flags = str_lit("-march=x86 "); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f31434c01..f8c74c0be 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -274,7 +274,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { bool is_require_results = (pd->tags & ProcTag_require_results) != 0; - if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) { + if (d->scope->is_file && e->token.string == "main") { if (proc_type != NULL) { TypeProc *pt = &proc_type->Proc; if (pt->param_count != 0 || @@ -334,7 +334,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { String name = foreign_library->Ident.string; Entity *found = scope_lookup_entity(c->context.scope, name); if (found == NULL) { - if (str_eq(name, str_lit("_"))) { + if (name == "_") { error_node(foreign_library, "`_` cannot be used as a value type"); } else { error_node(foreign_library, "Undeclared name: %.*s", LIT(name)); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0c8bb0ab0..86d0541af 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -427,9 +427,9 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls, Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)field_index); e->identifier = name; - if (str_eq(name_token.string, str_lit("_"))) { + if (name_token.string == "_") { fields[field_index++] = e; - } else if (str_eq(name_token.string, str_lit("__tag"))) { + } else if (name_token.string == "__tag") { error_node(name, "`__tag` is a reserved identifier for fields"); } else { HashKey key = hash_string(name_token.string); @@ -729,7 +729,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { type->Named.type_name = e; add_entity(c, c->context.scope, f->name, e); - if (str_eq(name_token.string, str_lit("_"))) { + if (name_token.string == "_") { error(name_token, "`_` cannot be used a union subtype"); continue; } @@ -857,21 +857,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod // NOTE(bill): Skip blank identifiers - if (str_eq(name, str_lit("_"))) { + if (name == "_") { continue; - } else if (str_eq(name, str_lit("count"))) { + } else if (name == "count") { error_node(field, "`count` is a reserved identifier for enumerations"); continue; - } else if (str_eq(name, str_lit("min_value"))) { + } else if (name == "min_value") { error_node(field, "`min_value` is a reserved identifier for enumerations"); continue; - } else if (str_eq(name, str_lit("max_value"))) { + } else if (name == "max_value") { error_node(field, "`max_value` is a reserved identifier for enumerations"); continue; - } else if (str_eq(name, str_lit("names"))) { + } else if (name == "names") { error_node(field, "`names` is a reserved identifier for enumerations"); continue; - }/* else if (str_eq(name, str_lit("base_type"))) { + }/* else if (name == "base_type") { error_node(field, "`base_type` is a reserved identifier for enumerations"); continue; } */ @@ -966,7 +966,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As e->flags |= EntityFlag_BitFieldValue; HashKey key = hash_string(name); - if (str_ne(name, str_lit("_")) && + if (name != "_" && map_entity_get(&entity_map, key) != NULL) { error_node(ident, "`%.*s` is already declared in this bit field", LIT(name)); } else { @@ -1164,15 +1164,15 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { for (isize i = 0; i < variable_index; i++) { String x = variables[i]->token.string; - if (x.len == 0 || str_eq(x, str_lit("_"))) { + if (x.len == 0 || x == "_") { continue; } for (isize j = i+1; j < variable_index; j++) { String y = variables[j]->token.string; - if (y.len == 0 || str_eq(y, str_lit("_"))) { + if (y.len == 0 || y == "_") { continue; } - if (str_eq(x, y)) { + if (x == y) { error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y)); } } @@ -1187,7 +1187,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { Type *new_type = original_type; - if (str_eq(build_context.ODIN_OS, str_lit("windows"))) { + if (build_context.ODIN_OS == "windows") { // NOTE(bill): Changing the passing parameter value type is to match C's ABI // IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment // SEE: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx @@ -1223,7 +1223,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { } } break; } - } else if (str_eq(build_context.ODIN_OS, str_lit("linux"))) { + } else if (build_context.ODIN_OS == "linux") { Type *bt = core_type(original_type); switch (bt->kind) { // Okay to pass by value @@ -1277,7 +1277,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { - if (str_eq(build_context.ODIN_OS, str_lit("windows"))) { + if (build_context.ODIN_OS == "windows") { Type *bt = core_type(reduce_tuple_to_single_type(original_type)); // NOTE(bill): This is just reversed engineered from LLVM IR output switch (bt->kind) { @@ -1301,7 +1301,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { } } break; } - } else if (str_eq(build_context.ODIN_OS, str_lit("linux"))) { + } else if (build_context.ODIN_OS == "linux") { } else { // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for @@ -1330,7 +1330,7 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a } - if (str_eq(build_context.ODIN_OS, str_lit("windows"))) { + if (build_context.ODIN_OS == "windows") { i64 size = 8*type_size_of(a, abi_return_type); switch (size) { case 0: @@ -1388,7 +1388,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * Entity *e = scope_lookup_entity(c->context.scope, name); if (e == NULL) { - if (str_eq(name, str_lit("_"))) { + if (name == "_") { error(n->Ident, "`_` cannot be used as a value type"); } else { error(n->Ident, "Undeclared name: %.*s", LIT(name)); @@ -1959,7 +1959,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { } if (is_type_typed(type)) { - add_type_and_value(&c->info, e, Addressing_Type, type, ExactValue{}); + add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value); } else { gbString name = type_to_string(type); error_node(e, "Invalid type definition of %s", name); @@ -3016,7 +3016,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { if (operand->mode == Addressing_Constant) { if (i128_eq(operand->value.value_integer, I128_ZERO)) { - if (str_ne(make_string_c(expr_str), str_lit("nil"))) { // HACK NOTE(bill): Just in case + if (make_string_c(expr_str) != "nil") { // HACK NOTE(bill): Just in case // NOTE(bill): Doesn't matter what the type is as it's still zero in the union extra_text = " - Did you want `nil`?"; } @@ -5213,7 +5213,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t case Token_Rune: t = t_untyped_rune; break; case Token_Imag: { String s = bl->string; - Rune r = s.text[s.len-1]; + Rune r = s[s.len-1]; switch (r) { case 'i': t = t_untyped_complex; break; } @@ -5226,13 +5226,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t case_end; case_ast_node(bd, BasicDirective, node); - if (str_eq(bd->name, str_lit("file"))) { + if (bd->name == "file") { o->type = t_untyped_string; o->value = exact_value_string(bd->token.pos.file); - } else if (str_eq(bd->name, str_lit("line"))) { + } else if (bd->name == "line") { o->type = t_untyped_integer; o->value = exact_value_i64(bd->token.pos.line); - } else if (str_eq(bd->name, str_lit("procedure"))) { + } else if (bd->name == "procedure") { if (c->proc_stack.count == 0) { error_node(node, "#procedure may only be used within procedures"); o->type = t_untyped_string; @@ -5448,7 +5448,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t bool all_fields_are_blank = true; for (isize i = 0; i < t->Record.field_count; i++) { Entity *field = t->Record.fields_in_src_order[i]; - if (str_ne(field->token.string, str_lit("_"))) { + if (field->token.string != "_") { all_fields_are_blank = false; break; } @@ -5466,7 +5466,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } Entity *field = t->Record.fields_in_src_order[index]; - if (!all_fields_are_blank && str_eq(field->token.string, str_lit("_"))) { + if (!all_fields_are_blank && field->token.string == "_") { // NOTE(bill): Ignore blank identifiers continue; } @@ -6153,7 +6153,7 @@ gbString write_record_fields_to_string(gbString str, AstNodeArray params) { gbString string_append_token(gbString str, Token token) { if (token.string.len > 0) { - return gb_string_append_length(str, token.string.text, token.string.len); + return gb_string_append_length(str, &token.string[0], token.string.len); } return str; } @@ -6186,7 +6186,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(bd, BasicDirective, node); str = gb_string_appendc(str, "#"); - str = gb_string_append_length(str, bd->name.text, bd->name.len); + str = gb_string_append_length(str, &bd->name[0], bd->name.len); case_end; case_ast_node(pl, ProcLit, node); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6031c9120..187dab3b7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -187,7 +187,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { // NOTE(bill): Ignore assignments to `_` if (node->kind == AstNode_Ident && - str_eq(node->Ident.string, str_lit("_"))) { + node->Ident.string == "_") { add_entity_definition(&c->info, node, NULL); check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier")); if (rhs->mode == Addressing_Invalid) { @@ -434,7 +434,7 @@ void check_label(Checker *c, AstNode *label) { return; } String name = l->name->Ident.string; - if (str_eq(name, str_lit("_"))) { + if (name == "_") { error_node(l->name, "A label's name cannot be a blank identifier"); return; } @@ -449,7 +449,7 @@ void check_label(Checker *c, AstNode *label) { bool ok = true; for_array(i, c->context.decl->labels) { BlockLabel bl = c->context.decl->labels.e[i]; - if (str_eq(bl.name, name)) { + if (bl.name == name) { error_node(label, "Duplicate label with the name `%.*s`", LIT(name)); ok = false; break; @@ -943,10 +943,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } if (x.mode != Addressing_Constant) { - x.value = ExactValue{}; + x.value = empty_exact_value; } if (y.mode != Addressing_Constant) { - y.value = ExactValue{}; + y.value = empty_exact_value; } @@ -1032,7 +1032,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { String str = token.string; Entity *found = NULL; - if (str_ne(str, str_lit("_"))) { + if (str != "_") { found = current_scope_lookup_entity(c->context.scope, str); } if (found == NULL) { @@ -1564,7 +1564,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { String str = token.string; Entity *found = NULL; // NOTE(bill): Ignore assignments to `_` - if (str_ne(str, str_lit("_"))) { + if (str != "_") { found = current_scope_lookup_entity(c->context.scope, str); } if (found == NULL) { diff --git a/src/checker.cpp b/src/checker.cpp index 9477dccb2..4922dd548 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -867,7 +867,7 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) { GB_ASSERT(identifier != NULL); if (identifier->kind == AstNode_Ident) { - if (str_eq(identifier->Ident.string, str_lit("_"))) { + if (identifier->Ident.string == "_") { return; } HashKey key = hash_pointer(identifier); @@ -879,7 +879,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { String name = entity->token.string; - if (!str_eq(name, str_lit("_"))) { + if (name != "_") { Entity *ie = scope_insert_entity(scope, entity); if (ie) { TokenPos pos = ie->token.pos; @@ -929,7 +929,7 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) { void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) { GB_ASSERT(identifier->kind == AstNode_Ident); GB_ASSERT(e != NULL && d != NULL); - GB_ASSERT(str_eq(identifier->Ident.string, e->token.string)); + GB_ASSERT(identifier->Ident.string == e->token.string); add_entity(c, e->scope, identifier, e); map_decl_info_set(&c->info.entities, hash_pointer(e), d); } @@ -1580,7 +1580,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) d->proc_lit = up_init; d->type_expr = vd->type; } else { - e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, ExactValue{}); + e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, empty_exact_value); d->type_expr = vd->type; d->init_expr = init; } @@ -1678,12 +1678,12 @@ void check_all_global_entities(Checker *c) { continue; } - if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) { + if (e->kind != Entity_Procedure && e->token.string == "main") { if (e->scope->is_init) { error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); continue; } - } else if (e->scope->is_global && str_eq(e->token.string, str_lit("main"))) { + } else if (e->scope->is_global && e->token.string == "main") { error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); continue; } @@ -1745,7 +1745,7 @@ String path_to_entity_name(String name, String fullpath) { isize slash = 0; isize dot = 0; for (isize i = filename.len-1; i >= 0; i--) { - u8 c = filename.text[i]; + u8 c = filename[i]; if (c == '/' || c == '\\') { break; } @@ -1757,7 +1757,7 @@ String path_to_entity_name(String name, String fullpath) { dot = filename.len; while (dot --> 0) { - u8 c = filename.text[dot]; + u8 c = filename[dot]; if (c == '.') { break; } @@ -1932,7 +1932,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { scope->has_been_imported = true; - if (str_eq(id->import_name.string, str_lit("."))) { + if (id->import_name.string == ".") { // NOTE(bill): Add imported entities to this file's scope for_array(elem_index, scope->elements.entries) { Entity *e = scope->elements.entries.e[elem_index].value; @@ -1958,7 +1958,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } } else { String import_name = path_to_entity_name(id->import_name.string, id->fullpath); - if (str_eq(import_name, str_lit("_"))) { + if (import_name == "_") { error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(id->import_name.string)); } else { GB_ASSERT(id->import_name.pos.line != 0); @@ -2010,7 +2010,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { String library_name = path_to_entity_name(fl->library_name.string, file_str); - if (str_eq(library_name, str_lit("_"))) { + if (library_name == "_") { error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); } else { GB_ASSERT(fl->library_name.pos.line != 0); @@ -2035,7 +2035,7 @@ void check_parsed_files(Checker *c) { scope->is_global = f->is_global_scope; scope->is_file = true; scope->file = f; - if (str_eq(f->tokenizer.fullpath, c->parser->init_fullpath)) { + if (f->tokenizer.fullpath == c->parser->init_fullpath) { scope->is_init = true; } diff --git a/src/entity.cpp b/src/entity.cpp index f029685c3..042f6f39f 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -148,7 +148,7 @@ bool is_entity_exported(Entity *e) { if (name.len == 0) { return false; } - return name.text[0] != '_'; + return name[0] != '_'; } gb_global u64 global_entity_id = 0; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index d8d015d47..2bdf3fdf5 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -36,6 +36,8 @@ typedef struct ExactValue { }; } ExactValue; +gb_global ExactValue const empty_exact_value = {}; + HashKey hash_exact_value(ExactValue v) { return hashing_proc(&v, gb_size_of(ExactValue)); } @@ -191,7 +193,7 @@ ExactValue exact_value_from_basic_literal(Token token) { case Token_Float: return exact_value_float_from_string(token.string); case Token_Imag: { String str = token.string; - Rune last_rune = cast(Rune)str.text[str.len-1]; + Rune last_rune = cast(Rune)str[str.len-1]; str.len--; // Ignore the `i|j|k` f64 imag = float_from_string(str); diff --git a/src/integer128.cpp b/src/integer128.cpp index 7682ae56c..39d834ab3 100644 --- a/src/integer128.cpp +++ b/src/integer128.cpp @@ -109,8 +109,8 @@ u128 u128_from_string(String string) { // TODO(bill): Allow for numbers with underscores in them u64 base = 10; bool has_prefix = false; - if (string.len > 2 && string.text[0] == '0') { - switch (string.text[1]) { + if (string.len > 2 && string[0] == '0') { + switch (string[1]) { case 'b': base = 2; has_prefix = true; break; case 'o': base = 8; has_prefix = true; break; case 'd': base = 10; has_prefix = true; break; @@ -160,8 +160,8 @@ i128 i128_from_string(String string) { // TODO(bill): Allow for numbers with underscores in them u64 base = 10; bool has_prefix = false; - if (string.len > 2 && string.text[0] == '0') { - switch (string.text[1]) { + if (string.len > 2 && string[0] == '0') { + switch (string[1]) { case 'b': base = 2; has_prefix = true; break; case 'o': base = 8; has_prefix = true; break; case 'd': base = 10; has_prefix = true; break; diff --git a/src/ir.cpp b/src/ir.cpp index 5c665bfa8..bab4027ef 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1399,8 +1399,8 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { String directory = filename; isize slash_index = 0; for (isize i = filename.len-1; i >= 0; i--) { - if (filename.text[i] == '\\' || - filename.text[i] == '/') { + if (filename[i] == '\\' || + filename[i] == '/') { break; } slash_index = i; @@ -1612,7 +1612,7 @@ void ir_emit_if(irProcedure *proc, irValue *cond, irBlock *true_block, irBlock * } void ir_emit_startup_runtime(irProcedure *proc) { - GB_ASSERT(proc->parent == NULL && str_eq(proc->name, str_lit("main"))); + GB_ASSERT(proc->parent == NULL && proc->name == "main"); ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); } @@ -4813,7 +4813,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { GB_ASSERT(e->kind == Entity_Variable); GB_ASSERT(e->flags & EntityFlag_TypeField); String name = e->token.string; - if (str_eq(name, str_lit("names"))) { + if (name == "names") { irValue *ti_ptr = ir_type_info(proc, type); irValue *names_ptr = NULL; @@ -6733,8 +6733,8 @@ void ir_begin_procedure_body(irProcedure *proc) { Entity *e = params->variables[i]; Type *abi_type = proc->type->Proc.abi_compat_params[i]; - if (!str_eq(e->token.string, str_lit("")) && - !str_eq(e->token.string, str_lit("_"))) { + if (e->token.string != "" && + e->token.string != "_") { irValue *param = ir_add_param(proc, e, name, abi_type); array_add(&proc->params, param); } @@ -6764,7 +6764,7 @@ void ir_end_procedure_body(irProcedure *proc) { void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { if (parent == NULL) { - if (str_eq(proc->name, str_lit("main"))) { + if (proc->name == "main") { ir_emit_startup_runtime(proc); } } @@ -7101,15 +7101,15 @@ void ir_gen_tree(irGen *s) { if (e->kind == Entity_Variable) { global_variable_max_count++; } else if (e->kind == Entity_Procedure && !e->scope->is_global) { - if (e->scope->is_init && str_eq(name, str_lit("main"))) { + if (e->scope->is_init && name == "main") { entry_point = e; } if ((e->Procedure.tags & ProcTag_export) != 0 || (e->Procedure.link_name.len > 0) || (e->scope->is_file && e->Procedure.link_name.len > 0)) { - if (!has_dll_main && str_eq(name, str_lit("DllMain"))) { + if (!has_dll_main && name == "DllMain") { has_dll_main = true; - } else if (!has_win_main && str_eq(name, str_lit("WinMain"))) { + } else if (!has_win_main && name == "WinMain") { has_win_main = true; } } @@ -7146,7 +7146,7 @@ void ir_gen_tree(irGen *s) { if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) { } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { // Handle later - } else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) { + } else if (scope->is_init && e->kind == Entity_Procedure && name == "main") { } else { name = ir_mangle_name(s, e->token.pos.file, e); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 2a4e79996..5bbe83e05 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -81,7 +81,7 @@ bool ir_valid_char(u8 c) { void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, bool prefix_with_dot) { isize extra = 0; for (isize i = 0; i < name.len; i++) { - u8 c = name.text[i]; + u8 c = name[i]; if (!ir_valid_char(c)) { extra += 2; } @@ -111,7 +111,7 @@ void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, boo } for (isize i = 0; i < name.len; i++) { - u8 c = name.text[i]; + u8 c = name[i]; if (ir_valid_char(c)) { buf[j++] = c; } else { @@ -1500,8 +1500,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_fprintf(f, " noalias"); } if (proc->body != NULL) { - if (!str_eq(e->token.string, str_lit("")) && - !str_eq(e->token.string, str_lit("_"))) { + if (e->token.string != "" && + e->token.string != "_") { ir_fprintf(f, " "); ir_print_encoded_local(f, e->token.string); } else { diff --git a/src/main.cpp b/src/main.cpp index 0e2bf2650..296a9e921 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,3 @@ -#if defined(__cplusplus) -extern "C" { -#endif - #define USE_CUSTOM_BACKEND false #include "common.cpp" @@ -154,27 +150,27 @@ int main(int argc, char **argv) { char *init_filename = NULL; bool run_output = false; String arg1 = make_string_c(argv[1]); - if (str_eq(arg1, str_lit("run"))) { + if (arg1 == "run") { if (argc != 3) { usage(argv[0]); return 1; } init_filename = argv[2]; run_output = true; - } else if (str_eq(arg1, str_lit("build_dll"))) { + } else if (arg1 == "build_dll") { if (argc != 3) { usage(argv[0]); return 1; } init_filename = argv[2]; build_context.is_dll = true; - } else if (str_eq(arg1, str_lit("build"))) { + } else if (arg1 == "build") { if (argc != 3) { usage(argv[0]); return 1; } init_filename = argv[2]; - } else if (str_eq(arg1, str_lit("version"))) { + } else if (arg1 == "version") { gb_printf("%s version %.*s\n", argv[0], LIT(build_context.ODIN_VERSION)); return 0; } else { @@ -382,7 +378,7 @@ int main(int argc, char **argv) { // without having to implement any new syntax specifically for MacOS. #if defined(GB_SYSTEM_OSX) isize len; - if(lib.len > 2 && lib.text[0] == '-' && lib.text[1] == 'f') { + if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); } else { @@ -460,7 +456,3 @@ int main(int argc, char **argv) { return 0; } - -#if defined(__cplusplus) -} -#endif diff --git a/src/map.cpp b/src/map.cpp index d616490e2..49ca604d0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -65,7 +65,7 @@ bool hash_key_equal(HashKey a, HashKey b) { // NOTE(bill): If two string's hashes collide, compare the strings themselves if (a.kind == HashKey_String) { if (b.kind == HashKey_String) { - return str_eq(a.string, b.string); + return a.string == b.string; } return false; } diff --git a/src/parser.cpp b/src/parser.cpp index ed87b2cb2..01510343e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1547,7 +1547,7 @@ bool allow_token(AstFile *f, TokenKind kind) { bool is_blank_ident(String str) { if (str.len == 1) { - return str.text[0] == '_'; + return str[0] == '_'; } return false; } @@ -1605,7 +1605,7 @@ void fix_advance_to_next_stmt(AstFile *f) { Token expect_closing(AstFile *f, TokenKind kind, String context) { if (f->curr_token.kind != kind && f->curr_token.kind == Token_Semicolon && - str_eq(f->curr_token.string, str_lit("\n"))) { + f->curr_token.string == "\n") { error(f->curr_token, "Missing `,` before newline in %.*s", LIT(context)); next_token(f); } @@ -1847,11 +1847,11 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str String tag_name = te->name.string; #define ELSE_IF_ADD_TAG(name) \ - else if (str_eq(tag_name, str_lit(#name))) { \ + else if (tag_name == #name) { \ check_proc_add_tag(f, tag_expr, tags, ProcTag_##name, tag_name); \ } - if (str_eq(tag_name, str_lit("foreign"))) { + if (tag_name == "foreign") { check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name); *foreign_library_token = parse_ident(f); if (f->curr_token.kind == Token_String) { @@ -1863,7 +1863,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str next_token(f); } - } else if (str_eq(tag_name, str_lit("link_name"))) { + } else if (tag_name == "link_name") { check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name); if (f->curr_token.kind == Token_String) { *link_name = f->curr_token.string; @@ -1885,25 +1885,25 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str ELSE_IF_ADD_TAG(no_inline) // ELSE_IF_ADD_TAG(dll_import) // ELSE_IF_ADD_TAG(dll_export) - else if (str_eq(tag_name, str_lit("cc_odin"))) { + else if (tag_name == "cc_odin") { if (cc == ProcCC_Invalid) { cc = ProcCC_Odin; } else { syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); } - } else if (str_eq(tag_name, str_lit("cc_c"))) { + } else if (tag_name == "cc_c") { if (cc == ProcCC_Invalid) { cc = ProcCC_C; } else { syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); } - } else if (str_eq(tag_name, str_lit("cc_std"))) { + } else if (tag_name == "cc_std") { if (cc == ProcCC_Invalid) { cc = ProcCC_Std; } else { syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); } - } else if (str_eq(tag_name, str_lit("cc_fast"))) { + } else if (tag_name == "cc_fast") { if (cc == ProcCC_Invalid) { cc = ProcCC_Fast; } else { @@ -2025,7 +2025,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { case Token_Hash: { Token token = expect_token(f, Token_Hash); Token name = expect_token(f, Token_Ident); - if (str_eq(name.string, str_lit("run"))) { + if (name.string == "run") { AstNode *expr = parse_expr(f, false); operand = ast_run_expr(f, token, name, expr); if (unparen_expr(expr)->kind != AstNode_CallExpr) { @@ -2033,11 +2033,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) { operand = ast_bad_expr(f, token, f->curr_token); } warning(token, "#run is not yet implemented"); - } else if (str_eq(name.string, str_lit("file"))) { return ast_basic_directive(f, token, name.string); - } 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 if (name.string == "file") { return ast_basic_directive(f, token, name.string); + } else if (name.string == "line") { return ast_basic_directive(f, token, name.string); + } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string); + } else if (name.string == "type") { return ast_helper_type(f, token, parse_type(f)); + } else if (!lhs && name.string == "alias") { return ast_alias(f, token, parse_expr(f, false)); } else { operand = ast_tag_expr(f, token, name, parse_expr(f, false)); } @@ -2721,7 +2721,7 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) { next_token(f); switch (f->curr_token.kind) { case Token_Ident: - if (str_eq(f->curr_token.string, str_lit("no_alias"))) { + if (f->curr_token.string == "no_alias") { return FieldPrefix_NoAlias; } break; @@ -2941,7 +2941,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Token hash_token = expect_token(f, Token_Hash); Token name = expect_token(f, Token_Ident); String tag = name.string; - if (str_eq(tag, str_lit("type"))) { + if (tag == "type") { AstNode *type = parse_type(f); return ast_helper_type(f, hash_token, type); } @@ -3023,17 +3023,17 @@ AstNode *parse_type_or_ident(AstFile *f) { while (allow_token(f, Token_Hash)) { Token tag = expect_token_after(f, Token_Ident, "#"); - if (str_eq(tag.string, str_lit("packed"))) { + if (tag.string == "packed") { if (is_packed) { syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); } is_packed = true; - } else if (str_eq(tag.string, str_lit("ordered"))) { + } else if (tag.string == "ordered") { if (is_ordered) { syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); } is_ordered = true; - } else if (str_eq(tag.string, str_lit("align"))) { + } else if (tag.string == "align") { if (align) { syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); } @@ -3157,7 +3157,7 @@ AstNode *parse_type_or_ident(AstFile *f) { while (allow_token(f, Token_Hash)) { Token tag = expect_token_after(f, Token_Ident, "#"); - if (str_eq(tag.string, str_lit("align"))) { + if (tag.string == "align") { if (align) { syntax_error(tag, "Duplicate bit_field tag `#%.*s`", LIT(tag.string)); } @@ -3687,7 +3687,7 @@ AstNode *parse_stmt(AstFile *f) { Token name = expect_token(f, Token_Ident); String tag = name.string; - if (str_eq(tag, str_lit("import"))) { + if (tag == "import") { AstNode *cond = NULL; Token import_name = {}; @@ -3706,7 +3706,7 @@ AstNode *parse_stmt(AstFile *f) { break; } - if (str_eq(import_name.string, str_lit("_"))) { + if (import_name.string == "_") { syntax_error(import_name, "Illegal #import name: `_`"); } @@ -3724,7 +3724,7 @@ AstNode *parse_stmt(AstFile *f) { } expect_semicolon(f, decl); return decl; - } else if (str_eq(tag, str_lit("load"))) { + } else if (tag == "load") { AstNode *cond = NULL; Token file_path = expect_token_after(f, Token_String, "#load"); Token import_name = file_path; @@ -3743,7 +3743,7 @@ AstNode *parse_stmt(AstFile *f) { } expect_semicolon(f, decl); return decl; - } else if (str_eq(tag, str_lit("shared_global_scope"))) { + } else if (tag == "shared_global_scope") { if (f->curr_proc == NULL) { f->is_global_scope = true; s = ast_empty_stmt(f, f->curr_token); @@ -3753,7 +3753,7 @@ AstNode *parse_stmt(AstFile *f) { } expect_semicolon(f, s); return s; - } else if (str_eq(tag, str_lit("foreign_system_library"))) { + } else if (tag == "foreign_system_library") { AstNode *cond = NULL; Token lib_name = {}; @@ -3767,7 +3767,7 @@ AstNode *parse_stmt(AstFile *f) { break; } - if (str_eq(lib_name.string, str_lit("_"))) { + if (lib_name.string == "_") { syntax_error(lib_name, "Illegal #foreign_library name: `_`"); } Token file_path = expect_token(f, Token_String); @@ -3784,7 +3784,7 @@ AstNode *parse_stmt(AstFile *f) { } expect_semicolon(f, s); return s; - } else if (str_eq(tag, str_lit("foreign_library"))) { + } else if (tag == "foreign_library") { AstNode *cond = NULL; Token lib_name = {}; @@ -3798,7 +3798,7 @@ AstNode *parse_stmt(AstFile *f) { break; } - if (str_eq(lib_name.string, str_lit("_"))) { + if (lib_name.string == "_") { syntax_error(lib_name, "Illegal #foreign_library name: `_`"); } Token file_path = expect_token(f, Token_String); @@ -3815,7 +3815,7 @@ AstNode *parse_stmt(AstFile *f) { } expect_semicolon(f, s); return s; - } else if (str_eq(tag, str_lit("thread_local"))) { + } else if (tag == "thread_local") { AstNode *s = parse_stmt(f); if (s->kind == AstNode_ValueDecl) { @@ -3831,14 +3831,14 @@ AstNode *parse_stmt(AstFile *f) { } syntax_error(token, "`thread_local` may only be applied to a variable declaration"); return ast_bad_stmt(f, token, f->curr_token); - } else if (str_eq(tag, str_lit("bounds_check"))) { + } else if (tag == "bounds_check") { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together"); } return s; - } else if (str_eq(tag, str_lit("no_bounds_check"))) { + } else if (tag == "no_bounds_check") { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_no_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_bounds_check) != 0) { @@ -3847,7 +3847,7 @@ AstNode *parse_stmt(AstFile *f) { return s; } - if (str_eq(tag, str_lit("include"))) { + if (tag == "include") { syntax_error(token, "#include is not a valid import declaration kind. Use #load instead"); s = ast_bad_stmt(f, token, f->curr_token); } else { @@ -3983,7 +3983,7 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) for_array(i, p->imports) { String import = p->imports.e[i].path; - if (str_eq(import, path)) { + if (import == path) { return false; } } @@ -4059,7 +4059,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray #if 0 isize colon_pos = -1; for (isize j = 0; j < file_str.len; j++) { - if (file_str.text[j] == ':') { + if (file_str[j] == ':') { colon_pos = j; break; } @@ -4077,12 +4077,12 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray } - if (str_eq(collection_name, str_lit("core"))) { + if (collection_name == "core") { String abs_path = get_fullpath_core(allocator, file_str); if (gb_file_exists(cast(char *)abs_path.text)) { // NOTE(bill): This should be null terminated import_file = abs_path; } - } else if (str_eq(collection_name, str_lit("local"))) { + } else if (collection_name == "local") { String rel_path = get_fullpath_relative(allocator, base_dir, file_str); if (gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated import_file = rel_path; @@ -4153,8 +4153,8 @@ void parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = filepath; for (isize i = filepath.len-1; i >= 0; i--) { - if (base_dir.text[i] == '\\' || - base_dir.text[i] == '/') { + if (base_dir[i] == '\\' || + base_dir[i] == '/') { break; } base_dir.len--; @@ -4202,7 +4202,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { if (err != ParseFile_None) { if (err == ParseFile_EmptyFile) { - if (str_eq(import_path, init_fullpath)) { + if (import_path == init_fullpath) { gb_printf_err("Initial file is empty - %.*s\n", LIT(init_fullpath)); gb_exit(1); } diff --git a/src/ssa.cpp b/src/ssa.cpp index d1f950858..b6bdb290a 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -378,9 +378,9 @@ ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa 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{}); } +ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, empty_exact_value); } 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{}); } +ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, empty_exact_value); } ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) { switch (8*type_size_of(p->allocator, t)) { @@ -413,7 +413,7 @@ void ssa_reset_value_args(ssaValue *v) { void ssa_reset(ssaValue *v, ssaOp op) { v->op = op; - v->exact_value = ExactValue{}; + v->exact_value = empty_exact_value; ssa_reset_value_args(v); } @@ -1071,7 +1071,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) { // GB_ASSERT(e->kind == Entity_Variable); // GB_ASSERT(e->flags & EntityFlag_TypeField); // String name = e->token.string; - // if (str_eq(name, str_lit("names"))) { + // if (name == "names") { // ssaValue *ti_ptr = ir_type_info(p, type); // ssaValue *names_ptr = NULL; @@ -2497,15 +2497,15 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { if (e->kind == Entity_Variable) { global_variable_max_count++; } else if (e->kind == Entity_Procedure && !e->scope->is_global) { - if (e->scope->is_init && str_eq(name, str_lit("main"))) { + if (e->scope->is_init && name == "main") { entry_point = e; } if ((e->Procedure.tags & ProcTag_export) != 0 || (e->Procedure.link_name.len > 0) || (e->scope->is_file && e->Procedure.link_name.len > 0)) { - if (!has_dll_main && str_eq(name, str_lit("DllMain"))) { + if (!has_dll_main && name == "DllMain") { has_dll_main = true; - } else if (!has_win_main && str_eq(name, str_lit("WinMain"))) { + } else if (!has_win_main && name == "WinMain") { has_win_main = true; } } @@ -2536,7 +2536,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) { } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { // Handle later - } else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) { + } else if (scope->is_init && e->kind == Entity_Procedure && name == "main") { } else { name = ssa_mangle_name(&m, e->token.pos.file, e); } diff --git a/src/string.cpp b/src/string.cpp index 3db3c21f4..105e9961b 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -12,6 +12,15 @@ void init_string_buffer_memory(void) { typedef struct String { u8 * text; isize len; + + u8 &operator[](isize i) { + GB_ASSERT(0 <= i && i < len); + return text[i]; + } + u8 const &operator[](isize i) const { + GB_ASSERT(0 <= i && i < len); + return text[i]; + } } String; // NOTE(bill): used for printf style arguments #define LIT(x) ((int)(x).len), (x).text @@ -23,6 +32,14 @@ typedef struct String { typedef struct String16 { wchar_t *text; isize len; + wchar_t &operator[](isize i) { + GB_ASSERT(0 <= i && i < len); + return text[i]; + } + wchar_t const &operator[](isize i) const { + GB_ASSERT(0 <= i && i < len); + return text[i]; + } } String16; @@ -56,8 +73,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) { if (a.len == b.len) { isize i; for (i = 0; i < a.len; i++) { - char x = cast(char)a.text[i]; - char y = cast(char)b.text[i]; + char x = cast(char)a[i]; + char y = cast(char)b[i]; if (gb_char_to_lower(x) != gb_char_to_lower(y)) return false; } @@ -88,16 +105,16 @@ int string_compare(String x, String y) { for (; curr_block < fast; curr_block++) { if (la[curr_block] ^ lb[curr_block]) { for (pos = curr_block*gb_size_of(isize); pos < n; pos++) { - if (x.text[pos] ^ y.text[pos]) { - return cast(int)x.text[pos] - cast(int)y.text[pos]; + if (x[pos] ^ y[pos]) { + return cast(int)x[pos] - cast(int)y[pos]; } } } } for (; offset < n; offset++) { - if (x.text[offset] ^ y.text[offset]) { - return cast(int)x.text[offset] - cast(int)y.text[offset]; + if (x[offset] ^ y[offset]) { + return cast(int)x[offset] - cast(int)y[offset]; } } } @@ -117,13 +134,29 @@ gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0; gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; } gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; } +bool operator == (String a, String b) { return str_eq(a, b); } +bool operator != (String a, String b) { return str_ne(a, b); } +bool operator < (String a, String b) { return str_lt(a, b); } +bool operator > (String a, String b) { return str_gt(a, b); } +bool operator <= (String a, String b) { return str_le(a, b); } +bool operator >= (String a, String b) { return str_ge(a, b); } + +template bool operator == (String a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); } +template bool operator != (String a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); } +template bool operator < (String a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); } +template bool operator > (String a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); } +template bool operator <= (String a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); } +template bool operator >= (String a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); } + + + gb_inline bool str_has_prefix(String s, String prefix) { isize i; if (prefix.len < s.len) { return false; } for (i = 0; i < prefix.len; i++) { - if (s.text[i] != prefix.text[i]) { + if (s[i] != prefix[i]) { return false; } } @@ -135,9 +168,9 @@ gb_inline isize string_extension_position(String str) { isize i = str.len; bool seen_dot = false; while (i --> 0) { - if (str.text[i] == GB_PATH_SEPARATOR) + if (str[i] == GB_PATH_SEPARATOR) break; - if (str.text[i] == '.') { + if (str[i] == '.') { dot_pos = i; break; } @@ -147,11 +180,11 @@ gb_inline isize string_extension_position(String str) { } String string_trim_whitespace(String str) { - while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) { + while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; } - while (str.len > 0 && rune_is_whitespace(str.text[0])) { + while (str.len > 0 && rune_is_whitespace(str[0])) { str.text++; str.len--; } @@ -166,7 +199,7 @@ gb_inline bool string_has_extension(String str, String ext) { } isize len = str.len; for (isize i = len-1; i >= 0; i--) { - if (str.text[i] == '.') { + if (str[i] == '.') { break; } len--; @@ -182,7 +215,7 @@ gb_inline bool string_has_extension(String str, String ext) { bool string_contains_char(String s, u8 c) { isize i; for (i = 0; i < s.len; i++) { - if (s.text[i] == c) + if (s[i] == c) return true; } return false; @@ -194,8 +227,8 @@ String filename_from_path(String s) { isize j = 0; s.len = i; for (j = i-1; j >= 0; j--) { - if (s.text[j] == '/' || - s.text[j] == '\\') { + if (s[j] == '/' || + s[j] == '\\') { break; } } @@ -315,18 +348,18 @@ String string16_to_string(gbAllocator a, String16 s) { bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) { u8 c; - if (s.text[0] == quote && + if (s[0] == quote && (quote == '\'' || quote == '"')) { return false; - } else if (s.text[0] >= 0x80) { + } else if (s[0] >= 0x80) { Rune r = -1; isize size = gb_utf8_decode(s.text, s.len, &r); *rune = r; *multiple_bytes = true; *tail_string = make_string(s.text+size, s.len-size); return true; - } else if (s.text[0] != '\\') { - *rune = s.text[0]; + } else if (s[0] != '\\') { + *rune = s[0]; *tail_string = make_string(s.text+1, s.len-1); return true; } @@ -334,7 +367,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String * if (s.len <= 1) { return false; } - c = s.text[1]; + c = s[1]; s = make_string(s.text+2, s.len-2); switch (c) { @@ -372,7 +405,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String * return false; } for (i = 0; i < 2; i++) { - i32 d = gb_digit_to_int(s.text[i]); + i32 d = gb_digit_to_int(s[i]); if (d < 0 || d > 7) { return false; } @@ -400,7 +433,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String * return false; } for (i = 0; i < count; i++) { - i32 d = gb_hex_digit_to_int(s.text[i]); + i32 d = gb_hex_digit_to_int(s[i]); if (d < 0) { return false; } @@ -433,8 +466,8 @@ i32 unquote_string(gbAllocator a, String *s_) { if (n < 2) { return 0; } - quote = s.text[0]; - if (quote != s.text[n-1]) { + quote = s[0]; + if (quote != s[n-1]) { return 0; } s.text += 1; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 06a527780..5c9809bd1 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -760,7 +760,7 @@ Token tokenizer_get_token(Tokenizer *t) { // NOTE(bill): All keywords are > 1 if (token.string.len > 1) { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { - if (str_eq(token.string, token_strings[k])) { + if (token.string == token_strings[k]) { token.kind = cast(TokenKind)k; break; } diff --git a/src/types.cpp b/src/types.cpp index a64e1e79e..41fc1f901 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1025,7 +1025,7 @@ bool are_types_identical(Type *x, Type *y) { if (!are_types_identical(xf->type, yf->type)) { return false; } - if (str_ne(xf->token.string, yf->token.string)) { + if (xf->token.string != yf->token.string) { return false; } bool xf_is_using = (xf->flags&EntityFlag_Using) != 0; @@ -1039,7 +1039,7 @@ bool are_types_identical(Type *x, Type *y) { if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) { return false; } - if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) { + if (x->Record.variants[i]->token.string != y->Record.variants[i]->token.string) { return false; } } @@ -1337,7 +1337,7 @@ gb_global Entity *entity__any_type_info = NULL; Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) { GB_ASSERT(type_ != NULL); - if (str_eq(field_name, str_lit("_"))) { + if (field_name == "_") { return empty_selection; } @@ -1362,11 +1362,11 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 1); } - if (str_eq(field_name, data_str)) { + if (field_name == data_str) { selection_add_index(&sel, 0); sel.entity = entity__any_data;; return sel; - } else if (str_eq(field_name, type_info_str)) { + } else if (field_name == type_info_str) { selection_add_index(&sel, 1); sel.entity = entity__any_type_info; return sel; @@ -1382,7 +1382,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n switch (type->Vector.count) { #define _VECTOR_FIELD_CASE(_length, _name) \ case (_length): \ - if (str_eq(field_name, str_lit(_name))) { \ + if (field_name == _name) { \ selection_add_index(&sel, (_length)-1); \ sel.entity = make_entity_vector_elem(a, NULL, make_token_ident(str_lit(_name)), type->Vector.elem, (_length)-1); \ return sel; \ @@ -1403,7 +1403,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n if (is_type) { if (type->kind == Type_Record) { if (type->Record.names != NULL && - str_eq(field_name, str_lit("names"))) { + field_name == "names") { sel.entity = type->Record.names; return sel; } @@ -1415,7 +1415,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n GB_ASSERT(f->kind == Entity_TypeName); String str = f->token.string; - if (str_eq(str, field_name)) { + if (str == field_name) { sel.entity = f; // selection_add_index(&sel, i); return sel; @@ -1424,15 +1424,15 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } else if (is_type_enum(type)) { // NOTE(bill): These may not have been added yet, so check in case if (type->Record.enum_count != NULL) { - if (str_eq(field_name, str_lit("count"))) { + if (field_name == "count") { sel.entity = type->Record.enum_count; return sel; } - if (str_eq(field_name, str_lit("min_value"))) { + if (field_name == "min_value") { sel.entity = type->Record.enum_min_value; return sel; } - if (str_eq(field_name, str_lit("max_value"))) { + if (field_name == "max_value") { sel.entity = type->Record.enum_max_value; return sel; } @@ -1443,7 +1443,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n GB_ASSERT(f->kind == Entity_Constant); String str = f->token.string; - if (str_eq(field_name, str)) { + if (field_name == str) { sel.entity = f; // selection_add_index(&sel, i); return sel; @@ -1457,7 +1457,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n continue; } String str = f->token.string; - if (str_eq(field_name, str)) { + if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; return sel; @@ -1479,7 +1479,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } if (type->Record.kind == TypeRecord_Union) { - if (str_eq(field_name, str_lit("__tag"))) { + if (field_name == "__tag") { Entity *e = type->Record.union__tag; GB_ASSERT(e != NULL); selection_add_index(&sel, -1); // HACK(bill): Leaky memory @@ -1496,7 +1496,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } String str = f->token.string; - if (str_eq(field_name, str)) { + if (field_name == str) { selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; return sel; -- cgit v1.2.3 From 2a89d8021cf95f4a4d7dab269a262a1d2237f71b Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 12:54:52 +0100 Subject: Use templated `Array` with bounds checking --- src/array.cpp | 184 ++++++++++++++--------------- src/build_settings.cpp | 12 +- src/check_decl.cpp | 14 +-- src/check_expr.cpp | 208 ++++++++++++++++----------------- src/check_stmt.cpp | 62 +++++----- src/checker.cpp | 130 ++++++++++----------- src/common.cpp | 4 - src/ir.cpp | 312 ++++++++++++++++++++++++------------------------- src/ir_opt.cpp | 74 ++++++------ src/ir_print.cpp | 36 +++--- src/main.cpp | 4 +- src/map.cpp | 68 +++++------ src/parser.cpp | 110 ++++++++--------- src/ssa.cpp | 105 +++++++++-------- src/timings.cpp | 10 +- src/tokenizer.cpp | 4 +- src/types.cpp | 34 +++--- 17 files changed, 687 insertions(+), 684 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/array.cpp b/src/array.cpp index bb9e789db..a46ccc47f 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -1,98 +1,7 @@ #define ARRAY_GROW_FORMULA(x) (2*(x) + 8) GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0); -#define Array(Type_) struct { \ - gbAllocator allocator; \ - Type_ * e; \ - isize count; \ - isize capacity; \ -} - -typedef Array(void) ArrayVoid; - -#define array_init_reserve(x_, allocator_, init_capacity_) do { \ - void **e = cast(void **)&((x_)->e); \ - GB_ASSERT((x_) != NULL); \ - (x_)->allocator = (allocator_); \ - (x_)->count = 0; \ - (x_)->capacity = (init_capacity_); \ - *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \ -} while (0) - -#define array_init_count(x_, allocator_, init_count_) do { \ - void **e = cast(void **)&((x_)->e); \ - GB_ASSERT((x_) != NULL); \ - (x_)->allocator = (allocator_); \ - (x_)->count = (init_count_); \ - (x_)->capacity = (init_count_); \ - *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \ -} while (0) - -#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0) -#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0) -#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0) - -#define array_grow(x_, min_capacity_) do { \ - isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \ - if (new_capacity < (min_capacity_)) { \ - new_capacity = (min_capacity_); \ - } \ - array_set_capacity(x_, new_capacity); \ -} while (0) - -#define array_add(x_, item_) do { \ - if ((x_)->capacity < (x_)->count+1) { \ - array_grow(x_, 0); \ - } \ - (x_)->e[(x_)->count++] = item_; \ -} while (0) - -#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0) -#define array_clear(x_) do { (x_)->count = 0; } while (0) - -#define array_resize(x_, new_count_) do { \ - if ((x_)->capacity < (new_count_)) { \ - array_grow((x_), (new_count_)); \ - } \ - (x_)->count = (new_count_); \ -} while (0) - -#define array_reserve(x_, new_capacity_) do { \ - if ((x_)->capacity < (new_capacity_)) { \ - array_set_capacity((x_), (new_capacity_)); \ - } \ -} while (0) - - - - -void array__set_capacity(void *ptr, isize capacity, isize element_size) { - ArrayVoid *x = cast(ArrayVoid *)ptr; - GB_ASSERT(ptr != NULL); - - GB_ASSERT(element_size > 0); - - if (capacity == x->capacity) { - return; - } - - if (capacity < x->count) { - if (x->capacity < capacity) { - isize new_capacity = ARRAY_GROW_FORMULA(x->capacity); - if (new_capacity < capacity) { - new_capacity = capacity; - } - array__set_capacity(ptr, new_capacity, element_size); - } - x->count = capacity; - } - - x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity); - x->capacity = capacity; -} - - -#if 0 +#if 1 template struct Array { gbAllocator allocator; @@ -224,6 +133,97 @@ void array_set_capacity(Array *array, isize capacity) { array->capacity = capacity; } +#endif + +#if 0 +#define Array(Type_) struct { \ + gbAllocator allocator; \ + Type_ * e; \ + isize count; \ + isize capacity; \ +} + +typedef Array(void) ArrayVoid; + +#define array_init_reserve(x_, allocator_, init_capacity_) do { \ + void **e = cast(void **)&((x_)->e); \ + GB_ASSERT((x_) != NULL); \ + (x_)->allocator = (allocator_); \ + (x_)->count = 0; \ + (x_)->capacity = (init_capacity_); \ + *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \ +} while (0) + +#define array_init_count(x_, allocator_, init_count_) do { \ + void **e = cast(void **)&((x_)->e); \ + GB_ASSERT((x_) != NULL); \ + (x_)->allocator = (allocator_); \ + (x_)->count = (init_count_); \ + (x_)->capacity = (init_count_); \ + *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \ +} while (0) +#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0) +#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0) +#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0) +#define array_grow(x_, min_capacity_) do { \ + isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \ + if (new_capacity < (min_capacity_)) { \ + new_capacity = (min_capacity_); \ + } \ + array_set_capacity(x_, new_capacity); \ +} while (0) + +#define array_add(x_, item_) do { \ + if ((x_)->capacity < (x_)->count+1) { \ + array_grow(x_, 0); \ + } \ + (x_)->e[(x_)->count++] = item_; \ +} while (0) + +#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0) +#define array_clear(x_) do { (x_)->count = 0; } while (0) + +#define array_resize(x_, new_count_) do { \ + if ((x_)->capacity < (new_count_)) { \ + array_grow((x_), (new_count_)); \ + } \ + (x_)->count = (new_count_); \ +} while (0) + +#define array_reserve(x_, new_capacity_) do { \ + if ((x_)->capacity < (new_capacity_)) { \ + array_set_capacity((x_), (new_capacity_)); \ + } \ +} while (0) + + + + +void array__set_capacity(void *ptr, isize capacity, isize element_size) { + ArrayVoid *x = cast(ArrayVoid *)ptr; + GB_ASSERT(ptr != NULL); + + GB_ASSERT(element_size > 0); + + if (capacity == x->capacity) { + return; + } + + if (capacity < x->count) { + if (x->capacity < capacity) { + isize new_capacity = ARRAY_GROW_FORMULA(x->capacity); + if (new_capacity < capacity) { + new_capacity = capacity; + } + array__set_capacity(ptr, new_capacity, element_size); + } + x->count = capacity; + } + + x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity); + x->capacity = capacity; +} #endif + diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 1229c466c..dac763010 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -35,7 +35,7 @@ String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; #if defined(GB_SYSTEM_WINDOWS) String odin_root_dir(void) { String path = global_module_path; - Array(wchar_t) path_buf; + Array path_buf; isize len, i; gbTempArenaMemory tmp; wchar_t *text; @@ -48,7 +48,7 @@ String odin_root_dir(void) { len = 0; for (;;) { - len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count); + len = GetModuleFileNameW(NULL, &path_buf[0], path_buf.count); if (len == 0) { return make_string(NULL, 0); } @@ -102,7 +102,7 @@ String odin_root_dir(void) { len = 0; for (;;) { int sz = path_buf.count; - int res = _NSGetExecutablePath(&path_buf.e[0], &sz); + int res = _NSGetExecutablePath(&path_buf[0], &sz); if(res == 0) { len = sz; break; @@ -114,7 +114,7 @@ String odin_root_dir(void) { tmp = gb_temp_arena_memory_begin(&string_buffer_arena); text = gb_alloc_array(string_buffer_allocator, u8, len + 1); - gb_memmove(text, &path_buf.e[0], len); + gb_memmove(text, &path_buf[0], len); path = make_string(text, len); for (i = path.len-1; i >= 0; i--) { @@ -158,7 +158,7 @@ String odin_root_dir(void) { // of this compiler, it should be _good enough_. // That said, there's no solid 100% method on Linux to get the program's // path without checking this link. Sorry. - len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count); + len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); if(len == 0) { return make_string(NULL, 0); } @@ -171,7 +171,7 @@ String odin_root_dir(void) { tmp = gb_temp_arena_memory_begin(&string_buffer_arena); text = gb_alloc_array(string_buffer_allocator, u8, len + 1); - gb_memmove(text, &path_buf.e[0], len); + gb_memmove(text, &path_buf[0], len); path = make_string(text, len); for (i = path.len-1; i >= 0; i--) { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f8c74c0be..1e7e23398 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -67,20 +67,20 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - ArrayOperand operands = {}; - array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count); + Array operands = {}; + array_init(&operands, c->tmp_allocator, 2*lhs_count); check_unpack_arguments(c, lhs_count, &operands, inits, true); isize rhs_count = operands.count; for_array(i, operands) { - if (operands.e[i].mode == Addressing_Invalid) { + if (operands[i].mode == Addressing_Invalid) { rhs_count--; } } isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { - check_init_variable(c, lhs[i], &operands.e[i], context_name); + check_init_variable(c, lhs[i], &operands[i], context_name); } if (rhs_count > 0 && lhs_count != rhs_count) { error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); @@ -432,7 +432,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } AstNodeArray inits; - array_init_reserve(&inits, c->allocator, 1); + array_init(&inits, c->allocator, 1); array_add(&inits, init_expr); check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration")); } @@ -514,7 +514,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); for_array(i, (*found)->elements.entries) { - Entity *f = (*found)->elements.entries.e[i].value; + Entity *f = (*found)->elements.entries[i].value; if (f->kind == Entity_Variable) { Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); uvar->Variable.is_immutable = is_immutable; @@ -555,7 +555,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod if (decl->parent != NULL) { // NOTE(bill): Add the dependencies from the procedure literal (lambda) for_array(i, decl->deps.entries) { - HashKey key = decl->deps.entries.e[i].key; + HashKey key = decl->deps.entries[i].key; Entity *e = cast(Entity *)key.ptr; map_bool_set(&decl->parent->deps, key, true); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 86d0541af..55670f7e5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -53,7 +53,7 @@ void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) { check_collect_entities(c, nodes, false); for_array(i, s->elements.entries) { - Entity *e = s->elements.entries.e[i].value; + Entity *e = s->elements.entries[i].value; switch (e->kind) { case Entity_Constant: case Entity_TypeName: @@ -70,7 +70,7 @@ void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) { } for_array(i, s->elements.entries) { - Entity *e = s->elements.entries.e[i].value; + Entity *e = s->elements.entries[i].value; if (e->kind != Entity_Procedure) { continue; } @@ -401,7 +401,7 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls, isize field_index = 0; for_array(decl_index, decls) { - AstNode *decl = decls.e[decl_index]; + AstNode *decl = decls[decl_index]; if (decl->kind != AstNode_Field) { continue; } @@ -412,13 +412,13 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls, if (is_using) { if (f->names.count > 1) { - error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type"); + error_node(f->names[0], "Cannot apply `using` to more than one of the same type"); is_using = false; } } for_array(name_index, f->names) { - AstNode *name = f->names.e[name_index]; + AstNode *name = f->names[name_index]; if (!ast_node_expect(name, AstNode_Ident)) { continue; } @@ -454,15 +454,15 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls, Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) && f->names.count >= 1 && - f->names.e[0]->kind == AstNode_Ident) { - Token name_token = f->names.e[0]->Ident; + f->names[0]->kind == AstNode_Ident) { + Token name_token = f->names[0]->Ident; if (is_type_indexable(t)) { bool ok = true; for_array(emi, entity_map.entries) { - Entity *e = entity_map.entries.e[emi].value; + Entity *e = entity_map.entries[emi].value; if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { if (is_type_indexable(e->type)) { - if (e->identifier != f->names.e[0]) { + if (e->identifier != f->names[0]) { ok = false; using_index_expr = e; break; @@ -545,7 +545,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { isize field_count = 0; for_array(field_index, st->fields) { - AstNode *field = st->fields.e[field_index]; + AstNode *field = st->fields[field_index]; switch (field->kind) { case_ast_node(f, Field, field); field_count += f->names.count; @@ -641,7 +641,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { isize variant_count = ut->variants.count+1; isize field_count = 0; for_array(i, ut->fields) { - AstNode *field = ut->fields.e[i]; + AstNode *field = ut->fields[i]; if (field->kind == AstNode_Field) { ast_node(f, Field, field); field_count += f->names.count; @@ -680,7 +680,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { } for_array(i, ut->variants) { - AstNode *variant = ut->variants.e[i]; + AstNode *variant = ut->variants[i]; if (variant->kind != AstNode_UnionField) { continue; } @@ -694,12 +694,12 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { // NOTE(bill): Copy the contents for the common fields for now AstNodeArray list = {}; array_init_count(&list, c->allocator, ut->fields.count+fl->list.count); - gb_memmove_array(list.e, ut->fields.e, ut->fields.count); - gb_memmove_array(list.e+ut->fields.count, fl->list.e, fl->list.count); + gb_memmove_array(list.data, ut->fields.data, ut->fields.count); + gb_memmove_array(list.data+ut->fields.count, fl->list.data, fl->list.count); isize list_count = 0; for_array(j, list) { - ast_node(f, Field, list.e[j]); + ast_node(f, Field, list[j]); list_count += f->names.count; } @@ -760,7 +760,7 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { isize field_count = 0; for_array(field_index, ut->fields) { - AstNode *field = ut->fields.e[field_index]; + AstNode *field = ut->fields[field_index]; switch (field->kind) { case_ast_node(f, Field, field); field_count += f->names.count; @@ -817,7 +817,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod ExactValue max_value = exact_value_i64(0); for_array(i, et->fields) { - AstNode *field = et->fields.e[i]; + AstNode *field = et->fields[i]; AstNode *ident = NULL; AstNode *init = NULL; if (field->kind == AstNode_FieldValue) { @@ -932,7 +932,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As u32 curr_offset = 0; for_array(i, bft->fields) { - AstNode *field = bft->fields.e[i]; + AstNode *field = bft->fields[i]; GB_ASSERT(field->kind == AstNode_FieldValue); AstNode *ident = field->FieldValue.field; AstNode *value = field->FieldValue.value; @@ -1041,7 +1041,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari isize variable_count = 0; for_array(i, params) { - AstNode *field = params.e[i]; + AstNode *field = params[i]; if (ast_node_expect(field, AstNode_Field)) { ast_node(f, Field, field); variable_count += gb_max(f->names.count, 1); @@ -1052,10 +1052,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; for_array(i, params) { - if (params.e[i]->kind != AstNode_Field) { + if (params[i]->kind != AstNode_Field) { continue; } - ast_node(p, Field, params.e[i]); + ast_node(p, Field, params[i]); AstNode *type_expr = p->type; if (type_expr) { if (type_expr->kind == AstNode_Ellipsis) { @@ -1063,20 +1063,20 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (i+1 == params.count) { is_variadic = true; } else { - error_node(params.e[i], "Invalid AST: Invalid variadic parameter"); + error_node(params[i], "Invalid AST: Invalid variadic parameter"); } } Type *type = check_type(c, type_expr); if (p->flags&FieldFlag_no_alias) { if (!is_type_pointer(type)) { - error_node(params.e[i], "`no_alias` can only be applied to fields of pointer type"); + error_node(params[i], "`no_alias` can only be applied to fields of pointer type"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } } for_array(j, p->names) { - AstNode *name = p->names.e[j]; + AstNode *name = p->names[j]; if (ast_node_expect(name, AstNode_Ident)) { Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, (p->flags&FieldFlag_using) != 0, (p->flags&FieldFlag_immutable) != 0); @@ -1127,7 +1127,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { isize variable_count = 0; for_array(i, results) { - AstNode *field = results.e[i]; + AstNode *field = results[i]; if (ast_node_expect(field, AstNode_Field)) { ast_node(f, Field, field); variable_count += gb_max(f->names.count, 1); @@ -1137,7 +1137,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; for_array(i, results) { - ast_node(field, Field, results.e[i]); + ast_node(field, Field, results[i]); Type *type = check_type(c, field->type); if (field->names.count == 0) { Token token = ast_node_token(field->type); @@ -1149,7 +1149,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { Token token = ast_node_token(field->type); token.string = str_lit(""); - AstNode *name = field->names.e[j]; + AstNode *name = field->names[j]; if (name->kind != AstNode_Ident) { error_node(name, "Expected an identifer for as the field name"); } else { @@ -3551,7 +3551,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // NOTE(bill): The first arg may be a Type, this will be checked case by case break; default: - check_multi_expr(c, operand, ce->args.e[0]); + check_multi_expr(c, operand, ce->args[0]); } switch (id) { @@ -3609,10 +3609,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_new: { // new :: proc(Type) -> ^Type Operand op = {}; - check_expr_or_type(c, &op, ce->args.e[0]); + check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `new`"); + error_node(ce->args[0], "Expected a type for `new`"); return false; } operand->mode = Addressing_Value; @@ -3623,16 +3623,16 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // new_slice :: proc(Type, len: int) -> []Type // new_slice :: proc(Type, len, cap: int) -> []Type Operand op = {}; - check_expr_or_type(c, &op, ce->args.e[0]); + check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `new_slice`"); + error_node(ce->args[0], "Expected a type for `new_slice`"); return false; } isize arg_count = ce->args.count; if (arg_count < 2 || 3 < arg_count) { - error_node(ce->args.e[0], "`new_slice` expects 2 or 3 arguments, found %td", arg_count); + error_node(ce->args[0], "`new_slice` expects 2 or 3 arguments, found %td", arg_count); // NOTE(bill): Return the correct type to reduce errors } else { // If any are constant @@ -3640,7 +3640,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id isize size_count = 0; for (isize i = 1; i < arg_count; i++) { i64 val = 0; - bool ok = check_index_value(c, ce->args.e[i], -1, &val); + bool ok = check_index_value(c, ce->args[i], -1, &val); if (ok && val >= 0) { GB_ASSERT(size_count < gb_count_of(sizes)); sizes[size_count++] = val; @@ -3648,7 +3648,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (size_count == 2 && sizes[0] > sizes[1]) { - error_node(ce->args.e[1], "`new_slice` count and capacity are swapped"); + error_node(ce->args[1], "`new_slice` count and capacity are swapped"); // No need quit } } @@ -3661,10 +3661,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // make :: proc(Type, len: int) -> Type // make :: proc(Type, len, cap: int) -> Type Operand op = {}; - check_expr_or_type(c, &op, ce->args.e[0]); + check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `make`"); + error_node(ce->args[0], "Expected a type for `make`"); return false; } @@ -3688,7 +3688,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id isize arg_count = ce->args.count; if (arg_count < min_args || max_args < arg_count) { - error_node(ce->args.e[0], "`make` expects %td or %d argument, found %td", min_args, max_args, arg_count); + error_node(ce->args[0], "`make` expects %td or %d argument, found %td", min_args, max_args, arg_count); return false; } @@ -3697,7 +3697,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id isize size_count = 0; for (isize i = 1; i < arg_count; i++) { i64 val = 0; - bool ok = check_index_value(c, false, ce->args.e[i], -1, &val); + bool ok = check_index_value(c, false, ce->args[i], -1, &val); if (ok && val >= 0) { GB_ASSERT(size_count < gb_count_of(sizes)); sizes[size_count++] = val; @@ -3705,7 +3705,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (size_count == 2 && sizes[0] > sizes[1]) { - error_node(ce->args.e[1], "`make` count and capacity are swapped"); + error_node(ce->args[1], "`make` count and capacity are swapped"); // No need quit } @@ -3755,7 +3755,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - AstNode *capacity = ce->args.e[1]; + AstNode *capacity = ce->args[1]; Operand op = {}; check_expr(c, &op, capacity); if (op.mode == Addressing_Invalid) { @@ -3846,7 +3846,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Type *key = base_type(type)->Map.key; Operand x = {Addressing_Invalid}; - AstNode *key_node = ce->args.e[1]; + AstNode *key_node = ce->args[1]; Operand op = {}; check_expr(c, &op, key_node); if (op.mode == Addressing_Invalid) { @@ -3868,9 +3868,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_size_of: { // size_of :: proc(Type) -> untyped int - Type *type = check_type(c, ce->args.e[0]); + Type *type = check_type(c, ce->args[0]); if (type == NULL || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `size_of`"); + error_node(ce->args[0], "Expected a type for `size_of`"); return false; } @@ -3894,9 +3894,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_align_of: { // align_of :: proc(Type) -> untyped int - Type *type = check_type(c, ce->args.e[0]); + Type *type = check_type(c, ce->args[0]); if (type == NULL || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `align_of`"); + error_node(ce->args[0], "Expected a type for `align_of`"); return false; } operand->mode = Addressing_Constant; @@ -3919,14 +3919,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_offset_of: { // offset_of :: proc(Type, field) -> untyped int Operand op = {}; - Type *bt = check_type(c, ce->args.e[0]); + Type *bt = check_type(c, ce->args[0]); Type *type = base_type(bt); if (type == NULL || type == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `offset_of`"); + error_node(ce->args[0], "Expected a type for `offset_of`"); return false; } - AstNode *field_arg = unparen_expr(ce->args.e[1]); + AstNode *field_arg = unparen_expr(ce->args[1]); if (field_arg == NULL || field_arg->kind != AstNode_Ident) { error_node(field_arg, "Expected an identifier for field argument"); @@ -3942,14 +3942,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Selection sel = lookup_field(c->allocator, type, arg->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { gbString type_str = type_to_string(bt); - error_node(ce->args.e[0], + error_node(ce->args[0], "`%s` has no field named `%.*s`", type_str, LIT(arg->string)); gb_string_free(type_str); return false; } if (sel.indirect) { gbString type_str = type_to_string(bt); - error_node(ce->args.e[0], + error_node(ce->args[0], "Field `%.*s` is embedded via a pointer in `%s`", LIT(arg->string), type_str); gb_string_free(type_str); return false; @@ -3962,7 +3962,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_offset_of_val: { // offset_of_val :: proc(val: expression) -> untyped int - AstNode *arg = unparen_expr(ce->args.e[0]); + AstNode *arg = unparen_expr(ce->args[0]); if (arg->kind != AstNode_SelectorExpr) { gbString str = expr_to_string(arg); error_node(arg, "`%s` is not a selector expression", str); @@ -3997,7 +3997,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (sel.indirect) { gbString type_str = type_to_string(type); - error_node(ce->args.e[0], + error_node(ce->args[0], "Field `%.*s` is embedded via a pointer in `%s`", LIT(i->string), type_str); gb_string_free(type_str); return false; @@ -4031,7 +4031,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // NOTE(bill): The type information may not be setup yet init_preload(c); - AstNode *expr = ce->args.e[0]; + AstNode *expr = ce->args[0]; Type *type = check_type(c, expr); if (type == NULL || type == t_invalid) { error_node(expr, "Invalid argument to `type_info`"); @@ -4052,7 +4052,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // NOTE(bill): The type information may not be setup yet init_preload(c); - AstNode *expr = ce->args.e[0]; + AstNode *expr = ce->args[0]; check_assignment(c, operand, NULL, str_lit("argument of `type_info_of_val`")); if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) return false; @@ -4066,13 +4066,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // compile_assert :: proc(cond: bool) -> bool if (!is_type_boolean(operand->type) && operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args.e[0]); + gbString str = expr_to_string(ce->args[0]); error_node(call, "`%s` is not a constant boolean", str); gb_string_free(str); return false; } if (!operand->value.value_bool) { - gbString str = expr_to_string(ce->args.e[0]); + gbString str = expr_to_string(ce->args[0]); error_node(call, "Compile time assertion: `%s`", str); gb_string_free(str); } @@ -4085,7 +4085,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // assert :: proc(cond: bool) -> bool if (!is_type_boolean(operand->type)) { - gbString str = expr_to_string(ce->args.e[0]); + gbString str = expr_to_string(ce->args[0]); error_node(call, "`%s` is not a boolean", str); gb_string_free(str); return false; @@ -4099,7 +4099,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // panic :: proc(msg: string) if (!is_type_string(operand->type)) { - gbString str = expr_to_string(ce->args.e[0]); + gbString str = expr_to_string(ce->args[0]); error_node(call, "`%s` is not a string", str); gb_string_free(str); return false; @@ -4117,7 +4117,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id dest_type = d->Slice.elem; } Operand op = {}; - check_expr(c, &op, ce->args.e[1]); + check_expr(c, &op, ce->args[1]); if (op.mode == Addressing_Invalid) { return false; } @@ -4132,8 +4132,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (!are_types_identical(dest_type, src_type)) { - gbString d_arg = expr_to_string(ce->args.e[0]); - gbString s_arg = expr_to_string(ce->args.e[1]); + gbString d_arg = expr_to_string(ce->args[0]); + gbString s_arg = expr_to_string(ce->args[1]); gbString d_str = type_to_string(dest_type); gbString s_str = type_to_string(src_type); error_node(call, @@ -4169,7 +4169,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (i == 0) { continue; } - AstNode *arg = ce->args.e[i]; + AstNode *arg = ce->args[i]; Operand op = {}; check_expr(c, &op, arg); if (op.mode == Addressing_Invalid) { @@ -4213,7 +4213,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->type = t_invalid; operand->mode = Addressing_Invalid; - check_expr(c, &y, ce->args.e[1]); + check_expr(c, &y, ce->args[1]); if (y.mode == Addressing_Invalid) { return false; } @@ -4348,7 +4348,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id isize arg_count = ce->args.count; if (arg_count < 2 || 3 < arg_count) { - error_node(ce->args.e[0], "`slice_ptr` expects 2 or 3 arguments, found %td", arg_count); + error_node(ce->args[0], "`slice_ptr` expects 2 or 3 arguments, found %td", arg_count); // NOTE(bill): Return the correct type to reduce errors } else { // If any are constant @@ -4356,7 +4356,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id isize size_count = 0; for (isize i = 1; i < arg_count; i++) { i64 val = 0; - bool ok = check_index_value(c, false, ce->args.e[i], -1, &val); + bool ok = check_index_value(c, false, ce->args[i], -1, &val); if (ok && val >= 0) { GB_ASSERT(size_count < gb_count_of(sizes)); sizes[size_count++] = val; @@ -4364,7 +4364,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (size_count == 2 && sizes[0] > sizes[1]) { - error_node(ce->args.e[1], "`slice_ptr` count and capacity are swapped"); + error_node(ce->args[1], "`slice_ptr` count and capacity are swapped"); // No need quit } } @@ -4396,7 +4396,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - AstNode *other_arg = ce->args.e[1]; + AstNode *other_arg = ce->args[1]; Operand a = *operand; Operand b = {}; check_expr(c, &b, other_arg); @@ -4464,7 +4464,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - AstNode *other_arg = ce->args.e[1]; + AstNode *other_arg = ce->args[1]; Operand a = *operand; Operand b = {}; check_expr(c, &b, other_arg); @@ -4566,8 +4566,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - AstNode *min_arg = ce->args.e[1]; - AstNode *max_arg = ce->args.e[2]; + AstNode *min_arg = ce->args[1]; + AstNode *max_arg = ce->args[2]; Operand x = *operand; Operand y = {}; Operand z = {}; @@ -4646,13 +4646,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_transmute: { Operand op = {}; - check_expr_or_type(c, &op, ce->args.e[0]); + check_expr_or_type(c, &op, ce->args[0]); Type *t = op.type; if ((op.mode != Addressing_Type && t == NULL) || t == t_invalid) { - error_node(ce->args.e[0], "Expected a type for `transmute`"); + error_node(ce->args[0], "Expected a type for `transmute`"); return false; } - AstNode *expr = ce->args.e[1]; + AstNode *expr = ce->args[1]; Operand *o = operand; check_expr(c, o, expr); if (o->mode == Addressing_Invalid) { @@ -4834,13 +4834,11 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { return sj < si ? -1 : sj > si; } -typedef Array(Operand) ArrayOperand; - -bool check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) { +bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, AstNodeArray rhs, bool allow_ok) { bool optional_ok = false; for_array(i, rhs) { Operand o = {}; - check_multi_expr(c, &o, rhs.e[i]); + check_multi_expr(c, &o, rhs[i]); if (o.type == NULL || o.type->kind != Type_Tuple) { if (allow_ok && lhs_count == 2 && rhs.count == 1 && @@ -4877,8 +4875,8 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod ast_node(ce, CallExpr, call); - ArrayOperand operands; - array_init_reserve(&operands, heap_allocator(), 2*ce->args.count); + Array operands; + array_init(&operands, heap_allocator(), 2*ce->args.count); check_unpack_arguments(c, -1, &operands, ce->args, false); if (operand->mode == Addressing_Overload) { @@ -4905,7 +4903,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod Type *proc_type = base_type(p->type); if (proc_type != NULL && is_type_proc(proc_type)) { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, CallArgumentMode_NoErrors, &score); + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_NoErrors, &score); if (err == CallArgumentError_None) { valids[valid_count].index = i; valids[valid_count].score = score; @@ -4950,14 +4948,14 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod add_entity_use(c, expr, e); proc_type = e->type; i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, CallArgumentMode_ShowErrors, &score); + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); } gb_free(heap_allocator(), valids); gb_free(heap_allocator(), procs); } else { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, CallArgumentMode_ShowErrors, &score); + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); array_free(&operands); } return proc_type; @@ -4994,7 +4992,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { if (operand->mode == Addressing_Invalid) { for_array(i, ce->args) { - check_expr_base(c, operand, ce->args.e[i], NULL); + check_expr_base(c, operand, ce->args[i], NULL); } operand->mode = Addressing_Invalid; operand->expr = call; @@ -5010,7 +5008,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { case 0: error_node(call, "Missing argument in convertion to `%s`", str); break; default: error_node(call, "Too many arguments in convertion to `%s`", str); break; case 1: - check_expr(c, operand, ce->args.e[0]); + check_expr(c, operand, ce->args[0]); if (operand->mode != Addressing_Invalid) { check_cast(c, operand, t); } @@ -5388,11 +5386,11 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } { // Checker values isize field_count = t->Record.field_count; - if (cl->elems.e[0]->kind == AstNode_FieldValue) { + if (cl->elems[0]->kind == AstNode_FieldValue) { bool *fields_visited = gb_alloc_array(c->allocator, bool, field_count); for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (elem->kind != AstNode_FieldValue) { error_node(elem, "Mixture of `field = value` and value elements in a structure literal is not allowed"); continue; @@ -5423,15 +5421,15 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t continue; } - Entity *field = t->Record.fields[sel.index.e[0]]; + Entity *field = t->Record.fields[sel.index[0]]; add_entity_use(c, fv->field, field); - if (fields_visited[sel.index.e[0]]) { + if (fields_visited[sel.index[0]]) { error_node(elem, "Duplicate field `%.*s` in structure literal", LIT(name)); continue; } - fields_visited[sel.index.e[0]] = true; + fields_visited[sel.index[0]] = true; check_expr(c, o, fv->value); if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) { @@ -5455,7 +5453,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } for_array(index, cl->elems) { - AstNode *elem = cl->elems.e[index]; + AstNode *elem = cl->elems[index]; if (elem->kind == AstNode_FieldValue) { error_node(elem, "Mixture of `field = value` and value elements in a structure literal is not allowed"); continue; @@ -5533,8 +5531,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } for (; index < elem_count; index++) { - GB_ASSERT(cl->elems.e != NULL); - AstNode *e = cl->elems.e[index]; + GB_ASSERT(cl->elems.data != NULL); + AstNode *e = cl->elems[index]; if (e == NULL) { error_node(node, "Invalid literal element"); continue; @@ -5563,7 +5561,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t if (t->kind == Type_Vector) { if (t->Vector.count > 1 && gb_is_between(index, 2, t->Vector.count-1)) { - error_node(cl->elems.e[0], "Expected either 1 (broadcast) or %td elements in vector literal, got %td", t->Vector.count, index); + error_node(cl->elems[0], "Expected either 1 (broadcast) or %td elements in vector literal, got %td", t->Vector.count, index); } } @@ -5585,11 +5583,11 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t { // Checker values Type *field_types[2] = {t_rawptr, t_type_info_ptr}; isize field_count = 2; - if (cl->elems.e[0]->kind == AstNode_FieldValue) { + if (cl->elems[0]->kind == AstNode_FieldValue) { bool fields_visited[2] = {}; for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (elem->kind != AstNode_FieldValue) { error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed"); continue; @@ -5609,7 +5607,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t continue; } - isize index = sel.index.e[0]; + isize index = sel.index[0]; if (fields_visited[index]) { error_node(elem, "Duplicate field `%.*s` in `any` literal", LIT(name)); @@ -5626,7 +5624,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } } else { for_array(index, cl->elems) { - AstNode *elem = cl->elems.e[index]; + AstNode *elem = cl->elems[index]; if (elem->kind == AstNode_FieldValue) { error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed"); continue; @@ -5658,7 +5656,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t is_constant = false; { // Checker values for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (elem->kind != AstNode_FieldValue) { error_node(elem, "Only `field = value` elements are allowed in a map literal"); continue; @@ -6146,7 +6144,7 @@ gbString write_record_fields_to_string(gbString str, AstNodeArray params) { if (i > 0) { str = gb_string_appendc(str, ", "); } - str = write_expr_to_string(str, params.e[i]); + str = write_expr_to_string(str, params[i]); } return str; } @@ -6200,7 +6198,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (i > 0) { str = gb_string_appendc(str, ", "); } - str = write_expr_to_string(str, cl->elems.e[i]); + str = write_expr_to_string(str, cl->elems[i]); } str = gb_string_appendc(str, "}"); case_end; @@ -6321,7 +6319,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { } for_array(i, f->names) { - AstNode *name = f->names.e[i]; + AstNode *name = f->names[i]; if (i > 0) { str = gb_string_appendc(str, ", "); } @@ -6341,7 +6339,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (i > 0) { str = gb_string_appendc(str, ", "); } - str = write_expr_to_string(str, f->list.e[i]); + str = write_expr_to_string(str, f->list[i]); } case_end; @@ -6357,7 +6355,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "("); for_array(i, ce->args) { - AstNode *arg = ce->args.e[i]; + AstNode *arg = ce->args[i]; if (i > 0) { str = gb_string_appendc(str, ", "); } @@ -6406,7 +6404,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (i > 0) { str = gb_string_appendc(str, ", "); } - str = write_expr_to_string(str, et->fields.e[i]); + str = write_expr_to_string(str, et->fields[i]); } str = gb_string_appendc(str, "}"); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 187dab3b7..9a0f6afa5 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -12,13 +12,13 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { isize max = stmts.count; for (isize i = stmts.count-1; i >= 0; i--) { - if (stmts.e[i]->kind != AstNode_EmptyStmt) { + if (stmts[i]->kind != AstNode_EmptyStmt) { break; } max--; } for (isize i = 0; i < max; i++) { - AstNode *n = stmts.e[i]; + AstNode *n = stmts[i]; if (n->kind == AstNode_EmptyStmt) { continue; } @@ -43,7 +43,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { bool check_is_terminating_list(AstNodeArray stmts) { // Iterate backwards for (isize n = stmts.count-1; n >= 0; n--) { - AstNode *stmt = stmts.e[n]; + AstNode *stmt = stmts[n]; if (stmt->kind != AstNode_EmptyStmt) { return check_is_terminating(stmt); } @@ -54,7 +54,7 @@ bool check_is_terminating_list(AstNodeArray stmts) { bool check_has_break_list(AstNodeArray stmts, bool implicit) { for_array(i, stmts) { - AstNode *stmt = stmts.e[i]; + AstNode *stmt = stmts[i]; if (check_has_break(stmt, implicit)) { return true; } @@ -137,7 +137,7 @@ bool check_is_terminating(AstNode *node) { case_ast_node(ms, MatchStmt, node); bool has_default = false; for_array(i, ms->body->BlockStmt.stmts) { - AstNode *clause = ms->body->BlockStmt.stmts.e[i]; + AstNode *clause = ms->body->BlockStmt.stmts[i]; ast_node(cc, CaseClause, clause); if (cc->list.count == 0) { has_default = true; @@ -153,7 +153,7 @@ bool check_is_terminating(AstNode *node) { case_ast_node(ms, TypeMatchStmt, node); bool has_default = false; for_array(i, ms->body->BlockStmt.stmts) { - AstNode *clause = ms->body->BlockStmt.stmts.e[i]; + AstNode *clause = ms->body->BlockStmt.stmts[i]; ast_node(cc, CaseClause, clause); if (cc->list.count == 0) { has_default = true; @@ -448,7 +448,7 @@ void check_label(Checker *c, AstNode *label) { bool ok = true; for_array(i, c->context.decl->labels) { - BlockLabel bl = c->context.decl->labels.e[i]; + BlockLabel bl = c->context.decl->labels[i]; if (bl.name == name) { error_node(label, "Duplicate label with the name `%.*s`", LIT(name)); ok = false; @@ -513,7 +513,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo case Entity_ImportName: { Scope *scope = e->ImportName.scope; for_array(i, scope->elements.entries) { - Entity *decl = scope->elements.entries.e[i].value; + Entity *decl = scope->elements.entries[i].value; Entity *found = scope_insert_entity(c->context.scope, decl); if (found != NULL) { gbString expr_str = expr_to_string(expr); @@ -539,7 +539,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo GB_ASSERT(found_ != NULL); Scope *found = *found_; for_array(i, found->elements.entries) { - Entity *f = found->elements.entries.e[i].value; + Entity *f = found->elements.entries[i].value; if (f->kind == Entity_Variable) { Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); // if (is_selector) { @@ -693,23 +693,23 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - ArrayOperand operands = {}; - array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count); + Array operands = {}; + array_init(&operands, c->tmp_allocator, 2 * lhs_count); check_unpack_arguments(c, lhs_count, &operands, as->rhs, true); isize rhs_count = operands.count; for_array(i, operands) { - if (operands.e[i].mode == Addressing_Invalid) { + if (operands[i].mode == Addressing_Invalid) { rhs_count--; } } isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { - check_assignment_variable(c, &operands.e[i], as->lhs.e[i]); + check_assignment_variable(c, &operands[i], as->lhs[i]); } if (lhs_count != rhs_count) { - error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); + error_node(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); } gb_temp_arena_memory_end(tmp); @@ -732,15 +732,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { be->op = op; be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add)); // NOTE(bill): Only use the first one will be used - be->left = as->lhs.e[0]; - be->right = as->rhs.e[0]; + be->left = as->lhs[0]; + be->right = as->rhs[0]; check_binary_expr(c, &operand, &binary_expr); if (operand.mode == Addressing_Invalid) { return; } // NOTE(bill): Only use the first one will be used - check_assignment_variable(c, &operand, as->lhs.e[0]); + check_assignment_variable(c, &operand, as->lhs[0]); } break; } case_end; @@ -794,7 +794,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } - Type *proc_type = c->proc_stack.e[c->proc_stack.count-1]; + Type *proc_type = c->proc_stack[c->proc_stack.count-1]; isize result_count = 0; if (proc_type->Proc.results) { result_count = proc_type->Proc.results->Tuple.variable_count; @@ -816,13 +816,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_init_variables(c, variables, result_count, rs->results, str_lit("return statement")); // if (pos.line == 10) { - // AstNode *x = rs->results.e[0]; + // AstNode *x = rs->results[0]; // gb_printf_err("%s\n", expr_to_string(x)); // gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x))); // } } } else if (rs->results.count > 0) { - error_node(rs->results.e[0], "No return values expected"); + error_node(rs->results[0], "No return values expected"); } case_end; @@ -1106,7 +1106,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { AstNode *first_default = NULL; ast_node(bs, BlockStmt, ms->body); for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts.e[i]; + AstNode *stmt = bs->stmts[i]; AstNode *default_stmt = NULL; if (stmt->kind == AstNode_CaseClause) { ast_node(cc, CaseClause, stmt); @@ -1134,7 +1134,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { map_type_and_token_init(&seen, heap_allocator()); for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts.e[i]; + AstNode *stmt = bs->stmts[i]; if (stmt->kind != AstNode_CaseClause) { // NOTE(bill): error handled by above multiple default checker continue; @@ -1142,7 +1142,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { ast_node(cc, CaseClause, stmt); for_array(j, cc->list) { - AstNode *expr = unparen_expr(cc->list.e[j]); + AstNode *expr = unparen_expr(cc->list[j]); if (is_ast_node_a_range(expr)) { ast_node(ie, BinaryExpr, expr); @@ -1297,8 +1297,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { syntax_error(as_token, "Expected 1 expression after `in`"); break; } - AstNode *lhs = as->lhs.e[0]; - AstNode *rhs = as->rhs.e[0]; + AstNode *lhs = as->lhs[0]; + AstNode *rhs = as->rhs[0]; check_expr(c, &x, rhs); check_assignment(c, &x, NULL, str_lit("type match expression")); @@ -1316,7 +1316,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { AstNode *first_default = NULL; ast_node(bs, BlockStmt, ms->body); for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts.e[i]; + AstNode *stmt = bs->stmts[i]; AstNode *default_stmt = NULL; if (stmt->kind == AstNode_CaseClause) { ast_node(cc, CaseClause, stmt); @@ -1350,7 +1350,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { map_bool_init(&seen, heap_allocator()); for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts.e[i]; + AstNode *stmt = bs->stmts[i]; if (stmt->kind != AstNode_CaseClause) { // NOTE(bill): error handled by above multiple default checker continue; @@ -1362,7 +1362,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { Type *case_type = NULL; for_array(type_index, cc->list) { - AstNode *type_expr = cc->list.e[type_index]; + AstNode *type_expr = cc->list[type_index]; if (type_expr != NULL) { // Otherwise it's a default expression Operand y = {}; check_expr_or_type(c, &y, type_expr); @@ -1502,7 +1502,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { return; } for_array(i, us->list) { - AstNode *expr = unparen_expr(us->list.e[0]); + AstNode *expr = unparen_expr(us->list[0]); Entity *e = NULL; bool is_selector = false; @@ -1555,7 +1555,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; Entity *entity = NULL; if (name->kind != AstNode_Ident) { error_node(name, "A variable declaration must be an identifier"); @@ -1638,7 +1638,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); for_array(i, (*found)->elements.entries) { - Entity *f = (*found)->elements.entries.e[i].value; + Entity *f = (*found)->elements.entries[i].value; if (f->kind == Entity_Variable) { Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); uvar->Variable.is_immutable = is_immutable; diff --git a/src/checker.cpp b/src/checker.cpp index 4922dd548..6a9011df1 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -197,7 +197,7 @@ struct DeclInfo { AstNode * proc_lit; // AstNode_ProcLit MapBool deps; // Key: Entity * - Array(BlockLabel) labels; + Array labels; }; // ProcedureInfo stores the information needed for checking a procedure @@ -240,8 +240,8 @@ typedef struct Scope { MapEntity elements; // Key: String MapBool implicit; // Key: Entity * - Array(Scope *) shared; - Array(Scope *) imported; + Array shared; + Array imported; bool is_proc; bool is_global; bool is_file; @@ -286,10 +286,10 @@ typedef struct DelayedDecl { } DelayedDecl; typedef struct CheckerFileNode { - i32 id; - Array_i32 wheres; - Array_i32 whats; - i32 score; // Higher the score, the better + i32 id; + Array wheres; + Array whats; + i32 score; // Higher the score, the better } CheckerFileNode; typedef struct CheckerContext { @@ -324,10 +324,10 @@ typedef struct Checker { AstFile * curr_ast_file; Scope * global_scope; - Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check - Array(DelayedDecl) delayed_imports; - Array(DelayedDecl) delayed_foreign_libraries; - Array(CheckerFileNode) file_nodes; + Array procs; // NOTE(bill): Procedures to check + Array delayed_imports; + Array delayed_foreign_libraries; + Array file_nodes; gbArena arena; gbArena tmp_arena; @@ -336,7 +336,7 @@ typedef struct Checker { CheckerContext context; - Array(Type *) proc_stack; + Array proc_stack; bool done_preload; } Checker; @@ -347,8 +347,6 @@ typedef struct DelayedEntity { DeclInfo * decl; } DelayedEntity; -typedef Array(DelayedEntity) DelayedEntities; - @@ -406,7 +404,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) { void destroy_scope(Scope *scope) { for_array(i, scope->elements.entries) { - Entity *e =scope->elements.entries.e[i].value; + Entity *e =scope->elements.entries[i].value; if (e->kind == Entity_Variable) { if (!(e->flags & EntityFlag_Used)) { #if 0 @@ -462,7 +460,7 @@ Entity *current_scope_lookup_entity(Scope *s, String name) { return *found; } for_array(i, s->shared) { - Scope *shared = s->shared.e[i]; + Scope *shared = s->shared[i]; Entity **found = map_entity_get(&shared->elements, key); if (found) { Entity *e = *found; @@ -512,7 +510,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit } else { // Check shared scopes - i.e. other files @ global scope for_array(i, s->shared) { - Scope *shared = s->shared.e[i]; + Scope *shared = s->shared[i]; Entity **found = map_entity_get(&shared->elements, key); if (found) { Entity *e = *found; @@ -753,7 +751,7 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) { array_init(&c->file_nodes, a); for_array(i, parser->files) { - AstFile *file = &parser->files.e[i]; + AstFile *file = &parser->files[i]; CheckerFileNode node = {}; node.id = file->id; array_init(&node.whats, a); @@ -765,7 +763,7 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) { isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope)); isize total_token_count = 0; for_array(i, c->parser->files) { - AstFile *f = &c->parser->files.e[i]; + AstFile *f = &c->parser->files[i]; total_token_count += f->tokens.count; } isize arena_size = 2 * item_size * total_token_count; @@ -961,7 +959,7 @@ void add_type_info_type(Checker *c, Type *t) { isize ti_index = -1; for_array(i, c->info.type_info_map.entries) { - MapIsizeEntry *e = &c->info.type_info_map.entries.e[i]; + MapIsizeEntry *e = &c->info.type_info_map.entries[i]; Type *prev_type = cast(Type *)e->key.ptr; if (are_types_identical(t, prev_type)) { // Duplicate entry @@ -1107,7 +1105,7 @@ void pop_procedure(Checker *c) { Type *const curr_procedure_type(Checker *c) { isize count = c->proc_stack.count; if (count > 0) { - return c->proc_stack.e[count-1]; + return c->proc_stack[count-1]; } return NULL; } @@ -1143,7 +1141,7 @@ void add_dependency_to_map(MapEntity *map, CheckerInfo *info, Entity *node) { DeclInfo *decl = *found; for_array(i, decl->deps.entries) { - Entity *e = cast(Entity *)decl->deps.entries.e[i].key.ptr; + Entity *e = cast(Entity *)decl->deps.entries[i].key.ptr; add_dependency_to_map(map, info, e); } } @@ -1153,7 +1151,7 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { map_entity_init(&map, heap_allocator()); for_array(i, info->definitions.entries) { - Entity *e = info->definitions.entries.e[i].value; + Entity *e = info->definitions.entries[i].value; if (e->scope->is_global) { // NOTE(bill): Require runtime stuff add_dependency_to_map(&map, info, e); @@ -1401,21 +1399,21 @@ bool check_arity_match(Checker *c, AstNodeValueDecl *d) { if (rhs == 0) { if (d->type == NULL) { - error_node(d->names.e[0], "Missing type or initial expression"); + error_node(d->names[0], "Missing type or initial expression"); return false; } } else if (lhs < rhs) { if (lhs < d->values.count) { - AstNode *n = d->values.e[lhs]; + AstNode *n = d->values[lhs]; gbString str = expr_to_string(n); error_node(n, "Extra initial expression `%s`", str); gb_string_free(str); } else { - error_node(d->names.e[0], "Extra initial expression"); + error_node(d->names[0], "Extra initial expression"); } return false; } else if (lhs > rhs && rhs != 1) { - AstNode *n = d->names.e[rhs]; + AstNode *n = d->names[rhs]; gbString str = expr_to_string(n); error_node(n, "Missing expression for `%s`", str); gb_string_free(str); @@ -1466,7 +1464,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) } for_array(decl_index, nodes) { - AstNode *decl = nodes.e[decl_index]; + AstNode *decl = nodes[decl_index]; if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) { continue; } @@ -1498,7 +1496,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) di = make_declaration_info(heap_allocator(), c->context.scope, c->context.decl); di->entities = entities; di->type_expr = vd->type; - di->init_expr = vd->values.e[0]; + di->init_expr = vd->values[0]; if (vd->flags & VarDeclFlag_thread_local) { @@ -1508,10 +1506,10 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; AstNode *value = NULL; if (i < vd->values.count) { - value = vd->values.e[i]; + value = vd->values[i]; } if (name->kind != AstNode_Ident) { error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); @@ -1545,7 +1543,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) check_arity_match(c, vd); } else { for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; if (name->kind != AstNode_Ident) { error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); continue; @@ -1553,7 +1551,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) AstNode *init = NULL; if (i < vd->values.count) { - init = vd->values.e[i]; + init = vd->values[i]; } DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl); @@ -1648,7 +1646,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) // NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source for_array(i, nodes) { - AstNode *node = nodes.e[i]; + AstNode *node = nodes[i]; switch (node->kind) { case_ast_node(ws, WhenStmt, node); check_collect_entities_from_when_stmt(c, ws, is_file_scope); @@ -1663,7 +1661,7 @@ void check_all_global_entities(Checker *c) { Scope *prev_file = {}; for_array(i, c->info.entities.entries) { - MapDeclInfoEntry *entry = &c->info.entities.entries.e[i]; + MapDeclInfoEntry *entry = &c->info.entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; DeclInfo *d = entry->value; @@ -1701,7 +1699,7 @@ void check_all_global_entities(Checker *c) { } for_array(i, c->info.entities.entries) { - MapDeclInfoEntry *entry = &c->info.entities.entries.e[i]; + MapDeclInfoEntry *entry = &c->info.entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; if (e->kind != Entity_Procedure) { continue; @@ -1779,8 +1777,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { Array_i32 shared_global_file_ids = {}; array_init_reserve(&shared_global_file_ids, heap_allocator(), c->file_nodes.count); for_array(i, c->file_nodes) { - CheckerFileNode *node = &c->file_nodes.e[i]; - AstFile *f = &c->parser->files.e[node->id]; + CheckerFileNode *node = &c->file_nodes[i]; + AstFile *f = &c->parser->files[node->id]; GB_ASSERT(f->id == node->id); if (f->scope->is_global) { array_add(&shared_global_file_ids, f->id); @@ -1788,11 +1786,11 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } for_array(i, c->file_nodes) { - CheckerFileNode *node = &c->file_nodes.e[i]; - AstFile *f = &c->parser->files.e[node->id]; + CheckerFileNode *node = &c->file_nodes[i]; + AstFile *f = &c->parser->files[node->id]; if (!f->scope->is_global) { for_array(j, shared_global_file_ids) { - array_add(&node->whats, shared_global_file_ids.e[j]); + array_add(&node->whats, shared_global_file_ids[j]); } } } @@ -1801,8 +1799,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } for_array(i, c->delayed_imports) { - Scope *parent_scope = c->delayed_imports.e[i].parent; - AstNode *decl = c->delayed_imports.e[i].decl; + Scope *parent_scope = c->delayed_imports[i].parent; + AstNode *decl = c->delayed_imports[i].decl; ast_node(id, ImportDecl, decl); Token token = id->relpath; @@ -1816,7 +1814,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { Scope **found = map_scope_get(file_scopes, key); if (found == NULL) { for_array(scope_index, file_scopes->entries) { - Scope *scope = file_scopes->entries.e[scope_index].value; + Scope *scope = file_scopes->entries[scope_index].value; gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath)); } gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column); @@ -1832,10 +1830,10 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { i32 child_id = scope->file->id; // TODO(bill): Very slow - CheckerFileNode *parent_node = &c->file_nodes.e[parent_id]; + CheckerFileNode *parent_node = &c->file_nodes[parent_id]; bool add_child = true; for_array(j, parent_node->whats) { - if (parent_node->whats.e[j] == child_id) { + if (parent_node->whats[j] == child_id) { add_child = false; break; } @@ -1844,10 +1842,10 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { array_add(&parent_node->whats, child_id); } - CheckerFileNode *child_node = &c->file_nodes.e[child_id]; + CheckerFileNode *child_node = &c->file_nodes[child_id]; bool add_parent = true; for_array(j, parent_node->wheres) { - if (parent_node->wheres.e[j] == parent_id) { + if (parent_node->wheres[j] == parent_id) { add_parent = false; break; } @@ -1858,24 +1856,24 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } for_array(i, c->file_nodes) { - CheckerFileNode *node = &c->file_nodes.e[i]; - AstFile *f = &c->parser->files.e[node->id]; + CheckerFileNode *node = &c->file_nodes[i]; + AstFile *f = &c->parser->files[node->id]; gb_printf_err("File %d %.*s", node->id, LIT(f->tokenizer.fullpath)); gb_printf_err("\n wheres:"); for_array(j, node->wheres) { - gb_printf_err(" %d", node->wheres.e[j]); + gb_printf_err(" %d", node->wheres[j]); } gb_printf_err("\n whats:"); for_array(j, node->whats) { - gb_printf_err(" %d", node->whats.e[j]); + gb_printf_err(" %d", node->whats[j]); } gb_printf_err("\n"); } #endif for_array(i, c->delayed_imports) { - Scope *parent_scope = c->delayed_imports.e[i].parent; - AstNode *decl = c->delayed_imports.e[i].decl; + Scope *parent_scope = c->delayed_imports[i].parent; + AstNode *decl = c->delayed_imports[i].decl; ast_node(id, ImportDecl, decl); Token token = id->relpath; @@ -1889,7 +1887,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { Scope **found = map_scope_get(file_scopes, key); if (found == NULL) { for_array(scope_index, file_scopes->entries) { - Scope *scope = file_scopes->entries.e[scope_index].value; + Scope *scope = file_scopes->entries[scope_index].value; gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath)); } gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column); @@ -1917,7 +1915,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { bool previously_added = false; for_array(import_index, parent_scope->imported) { - Scope *prev = parent_scope->imported.e[import_index]; + Scope *prev = parent_scope->imported[import_index]; if (prev == scope) { previously_added = true; break; @@ -1935,7 +1933,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { if (id->import_name.string == ".") { // NOTE(bill): Add imported entities to this file's scope for_array(elem_index, scope->elements.entries) { - Entity *e = scope->elements.entries.e[elem_index].value; + Entity *e = scope->elements.entries[elem_index].value; if (e->scope == parent_scope) { continue; } @@ -1974,8 +1972,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } for_array(i, c->delayed_foreign_libraries) { - Scope *parent_scope = c->delayed_foreign_libraries.e[i].parent; - AstNode *decl = c->delayed_foreign_libraries.e[i].decl; + Scope *parent_scope = c->delayed_foreign_libraries[i].parent; + AstNode *decl = c->delayed_foreign_libraries[i].decl; ast_node(fl, ForeignLibrary, decl); String file_str = fl->filepath.string; @@ -2029,7 +2027,7 @@ void check_parsed_files(Checker *c) { // Map full filepaths to Scopes for_array(i, c->parser->files) { - AstFile *f = &c->parser->files.e[i]; + AstFile *f = &c->parser->files[i]; Scope *scope = NULL; scope = make_scope(c->global_scope, c->allocator); scope->is_global = f->is_global_scope; @@ -2056,7 +2054,7 @@ void check_parsed_files(Checker *c) { // Collect Entities for_array(i, c->parser->files) { - AstFile *f = &c->parser->files.e[i]; + AstFile *f = &c->parser->files[i]; CheckerContext prev_context = c->context; add_curr_ast_file(c, f); check_collect_entities(c, f->decls, true); @@ -2071,7 +2069,7 @@ void check_parsed_files(Checker *c) { // Check procedure bodies // NOTE(bill): Nested procedures bodies will be added to this "queue" for_array(i, c->procs) { - ProcedureInfo *pi = &c->procs.e[i]; + ProcedureInfo *pi = &c->procs[i]; CheckerContext prev_context = c->context; add_curr_ast_file(c, pi->file); @@ -2094,7 +2092,7 @@ void check_parsed_files(Checker *c) { // Add untyped expression values for_array(i, c->info.untyped.entries) { - MapExprInfoEntry *entry = &c->info.untyped.entries.e[i]; + MapExprInfoEntry *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; AstNode *expr = cast(AstNode *)cast(uintptr)key.key; ExprInfo *info = &entry->value; @@ -2132,7 +2130,7 @@ void check_parsed_files(Checker *c) { // NOTE(bill): Check for illegal cyclic type declarations for_array(i, c->info.definitions.entries) { - Entity *e = c->info.definitions.entries.e[i].value; + Entity *e = c->info.definitions.entries[i].value; if (e->kind == Entity_TypeName) { if (e->type != NULL) { // i64 size = type_size_of(c->sizes, c->allocator, e->type); @@ -2148,13 +2146,13 @@ void check_parsed_files(Checker *c) { if (!build_context.is_dll) { for_array(i, file_scopes.entries) { - Scope *s = file_scopes.entries.e[i].value; + Scope *s = file_scopes.entries[i].value; if (s->is_init) { Entity *e = current_scope_lookup_entity(s, str_lit("main")); if (e == NULL) { Token token = {}; if (s->file->tokens.count > 0) { - token = s->file->tokens.e[0]; + token = s->file->tokens[0]; } else { token.pos.file = s->file->tokenizer.fullpath; token.pos.line = 1; diff --git a/src/common.cpp b/src/common.cpp index 1155429d1..0aa37a001 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -242,10 +242,6 @@ f64 gb_sqrt(f64 x) { // //////////////////////////////////////////////////////////////// -typedef Array(i32) Array_i32; -typedef Array(isize) Array_isize; - - #define MAP_TYPE String #define MAP_PROC map_string_ #define MAP_NAME MapString diff --git a/src/ir.cpp b/src/ir.cpp index bab4027ef..c9afb05ba 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3,7 +3,7 @@ typedef struct irBlock irBlock; typedef struct irValue irValue; typedef struct irDebugInfo irDebugInfo; -typedef Array(irValue *) irValueArray; +typedef Array irValueArray; #define MAP_TYPE irValue * #define MAP_PROC map_ir_value_ @@ -41,16 +41,16 @@ typedef struct irModule { Entity * entry_point_entity; - Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies + Array procs; // NOTE(bill): All procedures with bodies irValueArray procs_to_generate; // NOTE(bill): Procedures to generate - Array(String) foreign_library_paths; // Only the ones that were used + Array foreign_library_paths; // Only the ones that were used } irModule; // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory) typedef struct irDomNode { irBlock * idom; // Parent (Immediate Dominator) - Array(irBlock *) children; + Array children; i32 pre, post; // Ordering in tree } irDomNode; @@ -68,8 +68,8 @@ typedef struct irBlock { irValueArray instrs; irValueArray locals; - Array(irBlock *) preds; - Array(irBlock *) succs; + Array preds; + Array succs; } irBlock; typedef struct irTargetList irTargetList; @@ -111,7 +111,7 @@ typedef struct irBranchBlocks { struct irProcedure { irProcedure * parent; - Array(irProcedure *) children; + Array children; Entity * entity; irModule * module; @@ -123,8 +123,8 @@ struct irProcedure { irValue * return_ptr; irValueArray params; - Array(irDefer) defer_stmts; - Array(irBlock *) blocks; + Array defer_stmts; + Array blocks; i32 scope_index; irBlock * decl_block; irBlock * entry_block; @@ -132,7 +132,7 @@ struct irProcedure { irTargetList * target_list; irValueArray referrers; - Array(irBranchBlocks) branch_blocks; + Array branch_blocks; i32 local_count; i32 instr_count; @@ -516,7 +516,7 @@ struct irDebugInfo { TokenPos pos; } Proc; struct { - Array(irDebugInfo *) procs; + Array procs; } AllProcs; @@ -528,7 +528,7 @@ struct irDebugInfo { } BasicType; struct { irDebugInfo * return_type; - Array(irDebugInfo *) param_types; + Array param_types; } ProcType; struct { irDebugInfo * base_type; @@ -542,7 +542,7 @@ struct irDebugInfo { TokenPos pos; i32 size; i32 align; - Array(irDebugInfo *) elements; + Array elements; } CompositeType; struct { String name; @@ -662,7 +662,7 @@ irInstr *ir_get_last_instr(irBlock *block) { if (block != NULL) { isize len = block->instrs.count; if (len > 0) { - irValue *v = block->instrs.e[len-1]; + irValue *v = block->instrs[len-1]; GB_ASSERT(v->kind == irValue_Instr); return &v->Instr; } @@ -1125,7 +1125,7 @@ irValue *ir_value_procedure(gbAllocator a, irModule *m, Entity *entity, Type *ty Type *t = base_type(type); GB_ASSERT(is_type_proc(t)); - array_init_reserve(&v->Proc.params, heap_allocator(), t->Proc.param_count); + array_init(&v->Proc.params, heap_allocator(), t->Proc.param_count); return v; } @@ -1177,7 +1177,7 @@ irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) { void ir_add_block_to_proc(irProcedure *proc, irBlock *b) { for_array(i, proc->blocks) { - if (proc->blocks.e[i] == b) { + if (proc->blocks[i] == b) { return; } } @@ -1535,7 +1535,7 @@ void ir_emit_defer_stmts(irProcedure *proc, irDeferExitKind kind, irBlock *block isize count = proc->defer_stmts.count; isize i = count; while (i --> 0) { - irDefer d = proc->defer_stmts.e[i]; + irDefer d = proc->defer_stmts[i]; if (kind == irDeferExit_Default) { if (proc->scope_index == d.scope_index && d.scope_index > 1) { @@ -2446,7 +2446,7 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { Type *type = type_deref(ir_type(e)); for_array(i, sel.index) { - i32 index = cast(i32)sel.index.e[i]; + i32 index = cast(i32)sel.index[i]; if (is_type_pointer(type)) { type = type_deref(type); e = ir_emit_load(proc, e); @@ -2516,7 +2516,7 @@ irValue *ir_emit_deep_field_ev(irProcedure *proc, irValue *e, Selection sel) { Type *type = ir_type(e); for_array(i, sel.index) { - i32 index = cast(i32)sel.index.e[i]; + i32 index = cast(i32)sel.index[i]; if (is_type_pointer(type)) { type = type_deref(type); e = ir_emit_load(proc, e); @@ -3294,7 +3294,7 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) { // NOTE(bill): Do manual search // TODO(bill): This is O(n) and can be very slow for_array(i, info->type_info_map.entries){ - MapIsizeEntry *e = &info->type_info_map.entries.e[i]; + MapIsizeEntry *e = &info->type_info_map.entries[i]; Type *prev_type = cast(Type *)e->key.ptr; if (are_types_identical(prev_type, type)) { entry_index = e->value; @@ -3388,7 +3388,7 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { } irValueArray edges = {}; - array_init_reserve(&edges, proc->module->allocator, done->preds.count+1); + array_init(&edges, proc->module->allocator, done->preds.count+1); for_array(i, done->preds) { array_add(&edges, short_circuit); } @@ -3514,7 +3514,7 @@ irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) { Entity *e = *found; GB_ASSERT(e->kind == Entity_Label); for_array(i, proc->branch_blocks) { - irBranchBlocks *b = &proc->branch_blocks.e[i]; + irBranchBlocks *b = &proc->branch_blocks[i]; if (b->label == e->Label.node) { return *b; } @@ -3537,7 +3537,7 @@ void ir_push_target_list(irProcedure *proc, AstNode *label, irBlock *break_, irB GB_ASSERT(label->kind == AstNode_Label); for_array(i, proc->branch_blocks) { - irBranchBlocks *b = &proc->branch_blocks.e[i]; + irBranchBlocks *b = &proc->branch_blocks[i]; GB_ASSERT(b->label != NULL && label != NULL); GB_ASSERT(b->label->kind == AstNode_Label); if (b->label == label) { @@ -3713,7 +3713,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_emit_comment(proc, str_lit("TernaryExpr")); irValueArray edges = {}; - array_init_reserve(&edges, proc->module->allocator, 2); + array_init(&edges, proc->module->allocator, 2); GB_ASSERT(te->y != NULL); irBlock *then = ir_new_block(proc, NULL, "if.then"); @@ -3753,7 +3753,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } irValueArray edges = {}; - array_init_reserve(&edges, proc->module->allocator, 2); + array_init(&edges, proc->module->allocator, 2); GB_ASSERT(ie->else_expr != NULL); irBlock *then = ir_new_block(proc, expr, "if.then"); @@ -3881,7 +3881,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case_ast_node(ce, CallExpr, expr); if (map_tav_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { GB_ASSERT(ce->args.count == 1); - irValue *x = ir_build_expr(proc, ce->args.e[0]); + irValue *x = ir_build_expr(proc, ce->args[0]); irValue *y = ir_emit_conv(proc, x, tv.type); return y; } @@ -3893,21 +3893,21 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { Entity *e = *found; switch (e->Builtin.id) { case BuiltinProc_type_info: { - Type *t = default_type(type_of_expr(proc->module->info, ce->args.e[0])); + Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ir_type_info(proc, t); } break; case BuiltinProc_type_info_of_val: { - Type *t = default_type(type_of_expr(proc->module->info, ce->args.e[0])); + Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ir_type_info(proc, t); } break; case BuiltinProc_transmute: { - irValue *x = ir_build_expr(proc, ce->args.e[1]); + irValue *x = ir_build_expr(proc, ce->args[1]); return ir_emit_transmute(proc, x, tv.type); } case BuiltinProc_len: { - irValue *v = ir_build_expr(proc, ce->args.e[0]); + irValue *v = ir_build_expr(proc, ce->args[0]); Type *t = base_type(ir_type(v)); if (is_type_pointer(t)) { // IMPORTANT TODO(bill): Should there be a nil pointer check? @@ -3934,7 +3934,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } break; case BuiltinProc_cap: { - irValue *v = ir_build_expr(proc, ce->args.e[0]); + irValue *v = ir_build_expr(proc, ce->args[0]); Type *t = base_type(ir_type(v)); if (is_type_pointer(t)) { // IMPORTANT TODO(bill): Should there be a nil pointer check? @@ -3965,7 +3965,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { // new :: proc(Type) -> ^Type gbAllocator allocator = proc->module->allocator; - Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + Type *type = type_of_expr(proc->module->info, ce->args[0]); Type *ptr_type = make_type_pointer(allocator, type); i64 s = type_size_of(allocator, type); @@ -3986,7 +3986,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { // new_slice :: proc(Type, len, cap: int) -> []Type gbAllocator allocator = proc->module->allocator; - Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + Type *type = type_of_expr(proc->module->info, ce->args[0]); Type *ptr_type = make_type_pointer(allocator, type); Type *slice_type = make_type_slice(allocator, type); @@ -3996,14 +3996,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *elem_size = ir_const_int(allocator, s); irValue *elem_align = ir_const_int(allocator, a); - irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); irValue *capacity = count; if (ce->args.count == 3) { - capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int); } - ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, count, capacity, false); irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); @@ -4022,7 +4022,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_make: { ir_emit_comment(proc, str_lit("make")); gbAllocator a = proc->module->allocator; - Type *type = type_of_expr(proc->module->info, ce->args.e[0]); + Type *type = type_of_expr(proc->module->info, ce->args[0]); if (is_type_slice(type)) { Type *elem_type = core_type(type)->Slice.elem; @@ -4031,14 +4031,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type)); irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type)); - irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); irValue *capacity = count; if (ce->args.count == 3) { - capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int); } - ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, count, capacity, false); irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); @@ -4056,7 +4056,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *int_16 = ir_const_int(a, 16); irValue *cap = int_16; if (ce->args.count == 2) { - cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); } irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero); @@ -4074,14 +4074,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { Type *elem_type = base_type(type)->DynamicArray.elem; irValue *len = v_zero; if (ce->args.count > 1) { - len = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + len = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); } irValue *cap = len; if (ce->args.count > 2) { - cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int); } - ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[0]), v_zero, len, cap, false); + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false); irValue *array = ir_add_local_generated(proc, type); irValue **args = gb_alloc_array(a, irValue *, 5); @@ -4101,7 +4101,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { gbAllocator a = proc->module->allocator; - AstNode *node = ce->args.e[0]; + AstNode *node = ce->args[0]; TypeAndValue tav = type_and_value_of_expr(proc->module->info, node); Type *type = base_type(tav.type); @@ -4174,12 +4174,12 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_emit_comment(proc, str_lit("reserve")); gbAllocator a = proc->module->allocator; - irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr; + irValue *ptr = ir_build_addr(proc, ce->args[0]).addr; Type *type = ir_type(ptr); GB_ASSERT(is_type_pointer(type)); type = base_type(type_deref(type)); - irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); if (is_type_dynamic_array(type)) { Type *elem = type->DynamicArray.elem; @@ -4207,8 +4207,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_clear: { ir_emit_comment(proc, str_lit("clear")); - Type *original_type = type_of_expr(proc->module->info, ce->args.e[0]); - irAddr addr = ir_build_addr(proc, ce->args.e[0]); + Type *original_type = type_of_expr(proc->module->info, ce->args[0]); + irAddr addr = ir_build_addr(proc, ce->args[0]); irValue *ptr = addr.addr; if (is_double_pointer(ir_type(ptr))) { ptr = ir_addr_load(proc, addr); @@ -4235,15 +4235,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_emit_comment(proc, str_lit("append")); gbAllocator a = proc->module->allocator; - Type *value_type = type_of_expr(proc->module->info, ce->args.e[0]); - irAddr array_addr = ir_build_addr(proc, ce->args.e[0]); + Type *value_type = type_of_expr(proc->module->info, ce->args[0]); + irAddr array_addr = ir_build_addr(proc, ce->args[0]); irValue *array_ptr = array_addr.addr; if (is_double_pointer(ir_type(array_ptr))) { array_ptr = ir_addr_load(proc, array_addr); } Type *type = ir_type(array_ptr); { - TokenPos pos = ast_node_token(ce->args.e[0]).pos; + TokenPos pos = ast_node_token(ce->args[0]).pos; GB_ASSERT_MSG(is_type_pointer(type), "%.*s(%td) %s", LIT(pos.file), pos.line, type_to_string(type)); @@ -4268,7 +4268,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { isize arg_index = 0; isize arg_count = 0; for_array(i, ce->args) { - AstNode *a = ce->args.e[i]; + AstNode *a = ce->args[i]; Type *at = base_type(type_of_expr(proc->module->info, a)); if (at->kind == Type_Tuple) { arg_count += at->Tuple.variable_count; @@ -4281,7 +4281,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { bool vari_expand = ce->ellipsis.pos.line != 0; for_array(i, ce->args) { - irValue *a = ir_build_expr(proc, ce->args.e[i]); + irValue *a = ir_build_expr(proc, ce->args[i]); Type *at = ir_type(a); if (at->kind == Type_Tuple) { for (isize i = 0; i < at->Tuple.variable_count; i++) { @@ -4342,8 +4342,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_delete: { ir_emit_comment(proc, str_lit("delete")); - irValue *map = ir_build_expr(proc, ce->args.e[0]); - irValue *key = ir_build_expr(proc, ce->args.e[1]); + irValue *map = ir_build_expr(proc, ce->args[0]); + irValue *key = ir_build_expr(proc, ce->args[1]); Type *map_type = ir_type(map); GB_ASSERT(is_type_dynamic_map(map_type)); Type *key_type = base_type(map_type)->Map.key; @@ -4360,7 +4360,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_assert: { ir_emit_comment(proc, str_lit("assert")); - irValue *cond = ir_build_expr(proc, ce->args.e[0]); + irValue *cond = ir_build_expr(proc, ce->args[0]); GB_ASSERT(is_type_boolean(ir_type(cond))); cond = ir_emit_comp(proc, Token_CmpEq, cond, v_false); @@ -4371,9 +4371,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_start_block(proc, err); // TODO(bill): Cleanup allocations here - Token token = ast_node_token(ce->args.e[0]); + Token token = ast_node_token(ce->args[0]); TokenPos pos = token.pos; - gbString expr = expr_to_string(ce->args.e[0]); + gbString expr = expr_to_string(ce->args[0]); isize expr_len = gb_string_length(expr); String expr_str = {}; expr_str.text = cast(u8 *)gb_alloc_copy_align(proc->module->allocator, expr, expr_len, 1); @@ -4396,10 +4396,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_panic: { ir_emit_comment(proc, str_lit("panic")); - irValue *msg = ir_build_expr(proc, ce->args.e[0]); + irValue *msg = ir_build_expr(proc, ce->args[0]); GB_ASSERT(is_type_string(ir_type(msg))); - Token token = ast_node_token(ce->args.e[0]); + Token token = ast_node_token(ce->args[0]); TokenPos pos = token.pos; irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4); @@ -4416,8 +4416,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_copy: { ir_emit_comment(proc, str_lit("copy")); // copy :: proc(dst, src: []Type) -> int - AstNode *dst_node = ce->args.e[0]; - AstNode *src_node = ce->args.e[1]; + AstNode *dst_node = ce->args[0]; + AstNode *src_node = ce->args[1]; irValue *dst_slice = ir_build_expr(proc, dst_node); irValue *src_slice = ir_build_expr(proc, src_node); Type *slice_type = base_type(ir_type(dst_slice)); @@ -4448,7 +4448,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } break; case BuiltinProc_swizzle: { ir_emit_comment(proc, str_lit("swizzle.begin")); - irAddr vector_addr = ir_build_addr(proc, ce->args.e[0]); + irAddr vector_addr = ir_build_addr(proc, ce->args[0]); isize index_count = ce->args.count-1; if (index_count == 0) { return ir_addr_load(proc, vector_addr); @@ -4457,7 +4457,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *dst = ir_add_local_generated(proc, tv.type); for (i32 i = 1; i < ce->args.count; i++) { - TypeAndValue tv = type_and_value_of_expr(proc->module->info, ce->args.e[i]); + TypeAndValue tv = type_and_value_of_expr(proc->module->info, ce->args[i]); GB_ASSERT(is_type_integer(tv.type)); GB_ASSERT(tv.value.kind == ExactValue_Integer); @@ -4476,8 +4476,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_complex: { ir_emit_comment(proc, str_lit("complex")); - irValue *real = ir_build_expr(proc, ce->args.e[0]); - irValue *imag = ir_build_expr(proc, ce->args.e[1]); + irValue *real = ir_build_expr(proc, ce->args[0]); + irValue *imag = ir_build_expr(proc, ce->args[1]); irValue *dst = ir_add_local_generated(proc, tv.type); Type *ft = base_complex_elem_type(tv.type); @@ -4491,20 +4491,20 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_real: { ir_emit_comment(proc, str_lit("real")); - irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *val = ir_build_expr(proc, ce->args[0]); irValue *real = ir_emit_struct_ev(proc, val, 0); return ir_emit_conv(proc, real, tv.type); } break; case BuiltinProc_imag: { ir_emit_comment(proc, str_lit("imag")); - irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *val = ir_build_expr(proc, ce->args[0]); irValue *imag = ir_emit_struct_ev(proc, val, 1); return ir_emit_conv(proc, imag, tv.type); } break; case BuiltinProc_conj: { ir_emit_comment(proc, str_lit("conj")); - irValue *val = ir_build_expr(proc, ce->args.e[0]); + irValue *val = ir_build_expr(proc, ce->args[0]); irValue *res = NULL; Type *t = ir_type(val); if (is_type_complex(t)) { @@ -4520,12 +4520,12 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_slice_ptr: { ir_emit_comment(proc, str_lit("slice_ptr")); - irValue *ptr = ir_build_expr(proc, ce->args.e[0]); - irValue *count = ir_build_expr(proc, ce->args.e[1]); + irValue *ptr = ir_build_expr(proc, ce->args[0]); + irValue *count = ir_build_expr(proc, ce->args[1]); count = ir_emit_conv(proc, count, t_int); irValue *capacity = count; if (ce->args.count > 2) { - capacity = ir_build_expr(proc, ce->args.e[2]); + capacity = ir_build_expr(proc, ce->args[2]); capacity = ir_emit_conv(proc, capacity, t_int); } @@ -4537,7 +4537,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_slice_to_bytes: { ir_emit_comment(proc, str_lit("slice_to_bytes")); - irValue *s = ir_build_expr(proc, ce->args.e[0]); + irValue *s = ir_build_expr(proc, ce->args[0]); Type *t = base_type(ir_type(s)); if (is_type_u8_slice(t)) { return ir_emit_conv(proc, s, tv.type); @@ -4557,8 +4557,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_min: { ir_emit_comment(proc, str_lit("min")); Type *t = type_of_expr(proc->module->info, expr); - irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[0]), t); - irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t); + irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t); + irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t); irValue *cond = ir_emit_comp(proc, Token_Lt, x, y); return ir_emit_select(proc, cond, x, y); } break; @@ -4566,15 +4566,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case BuiltinProc_max: { ir_emit_comment(proc, str_lit("max")); Type *t = type_of_expr(proc->module->info, expr); - irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[0]), t); - irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t); + irValue *x = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t); + irValue *y = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t); irValue *cond = ir_emit_comp(proc, Token_Gt, x, y); return ir_emit_select(proc, cond, x, y); } break; case BuiltinProc_abs: { ir_emit_comment(proc, str_lit("abs")); - irValue *x = ir_build_expr(proc, ce->args.e[0]); + irValue *x = ir_build_expr(proc, ce->args[0]); Type *t = ir_type(x); if (is_type_complex(t)) { gbAllocator a = proc->module->allocator; @@ -4597,9 +4597,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_emit_comment(proc, str_lit("clamp")); Type *t = type_of_expr(proc->module->info, expr); return ir_emit_clamp(proc, t, - ir_build_expr(proc, ce->args.e[0]), - ir_build_expr(proc, ce->args.e[1]), - ir_build_expr(proc, ce->args.e[2])); + ir_build_expr(proc, ce->args[0]), + ir_build_expr(proc, ce->args[1]), + ir_build_expr(proc, ce->args[2])); } break; } } @@ -4616,7 +4616,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { isize arg_count = 0; for_array(i, ce->args) { - AstNode *a = ce->args.e[i]; + AstNode *a = ce->args[i]; Type *at = base_type(type_of_expr(proc->module->info, a)); if (at->kind == Type_Tuple) { arg_count += at->Tuple.variable_count; @@ -4629,7 +4629,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { bool vari_expand = ce->ellipsis.pos.line != 0; for_array(i, ce->args) { - irValue *a = ir_build_expr(proc, ce->args.e[i]); + irValue *a = ir_build_expr(proc, ce->args[i]); Type *at = ir_type(a); if (at->kind == Type_Tuple) { for (isize i = 0; i < at->Tuple.variable_count; i++) { @@ -4840,12 +4840,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *bft = type_deref(ir_addr_type(addr)); if (sel.index.count == 1) { GB_ASSERT(is_type_bit_field(bft)); - i32 index = sel.index.e[0]; + i32 index = sel.index[0]; return ir_addr_bit_field(addr.addr, index); } else { Selection s = sel; s.index.count--; - i32 index = s.index.e[s.index.count-1]; + i32 index = s.index[s.index.count-1]; irValue *a = addr.addr; a = ir_emit_deep_field_gep(proc, a, s); return ir_addr_bit_field(a, index); @@ -5171,14 +5171,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { case Type_Vector: { if (cl->elems.count == 1 && bt->Vector.count > 1) { isize index_count = bt->Vector.count; - irValue *elem_val = ir_build_expr(proc, cl->elems.e[0]); + irValue *elem_val = ir_build_expr(proc, cl->elems[0]); for (isize i = 0; i < index_count; i++) { ir_emit_store(proc, ir_emit_array_epi(proc, v, i), elem_val); } } else if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (ir_is_elem_const(proc->module, elem, et)) { continue; } @@ -5201,7 +5201,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); for_array(field_index, cl->elems) { - AstNode *elem = cl->elems.e[field_index]; + AstNode *elem = cl->elems[field_index]; irValue *field_expr = NULL; Entity *field = NULL; @@ -5211,12 +5211,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ast_node(fv, FieldValue, elem); String name = fv->field->Ident.string; Selection sel = lookup_field(proc->module->allocator, bt, name, false); - index = sel.index.e[0]; + index = sel.index[0]; elem = fv->value; } else { TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem); Selection sel = lookup_field_from_index(proc->module->allocator, bt, st->fields_in_src_order[field_index]->Variable.field_index); - index = sel.index.e[0]; + index = sel.index[0]; } field = st->fields[index]; @@ -5258,7 +5258,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("__dacl$"), cast(i64)cast(intptr)expr); for_array(field_index, cl->elems) { - AstNode *f = cl->elems.e[field_index]; + AstNode *f = cl->elems[field_index]; irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem); irValue *ep = ir_emit_array_epi(proc, items, field_index); ir_emit_store(proc, ep, value); @@ -5287,7 +5287,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); } for_array(field_index, cl->elems) { - AstNode *elem = cl->elems.e[field_index]; + AstNode *elem = cl->elems[field_index]; ast_node(fv, FieldValue, elem); irValue *key = ir_build_expr(proc, fv->field); @@ -5300,7 +5300,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (ir_is_elem_const(proc->module, elem, et)) { continue; } @@ -5324,7 +5324,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irValue *data = ir_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32); for_array(i, cl->elems) { - AstNode *elem = cl->elems.e[i]; + AstNode *elem = cl->elems[i]; if (ir_is_elem_const(proc->module, elem, et)) { continue; } @@ -5356,7 +5356,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { }; for_array(field_index, cl->elems) { - AstNode *elem = cl->elems.e[field_index]; + AstNode *elem = cl->elems[field_index]; irValue *field_expr = NULL; isize index = field_index; @@ -5364,12 +5364,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { if (elem->kind == AstNode_FieldValue) { ast_node(fv, FieldValue, elem); Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false); - index = sel.index.e[0]; + index = sel.index[0]; elem = fv->value; } else { TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem); Selection sel = lookup_field(proc->module->allocator, bt, field_names[field_index], false); - index = sel.index.e[0]; + index = sel.index[0]; } field_expr = ir_build_expr(proc, elem); @@ -5452,7 +5452,7 @@ irValue *ir_build_cond(irProcedure *proc, AstNode *cond, irBlock *true_block, ir void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts) { for_array(i, stmts) { - ir_build_stmt(proc, stmts.e[i]); + ir_build_stmt(proc, stmts[i]); } } @@ -5753,7 +5753,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { case_ast_node(us, UsingStmt, node); for_array(i, us->list) { - AstNode *decl = unparen_expr(us->list.e[i]); + AstNode *decl = unparen_expr(us->list[i]); if (decl->kind == AstNode_ValueDecl) { ir_build_stmt(proc, decl); } @@ -5780,19 +5780,19 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (vd->values.count == 0) { // declared and zero-initialized for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; if (!ir_is_blank_ident(name)) { ir_add_local_for_identifier(proc, name, true); } } } else { // Tuple(s) - Array(irAddr) lvals = {}; + Array lvals = {}; irValueArray inits = {}; - array_init_reserve(&lvals, m->tmp_allocator, vd->names.count); - array_init_reserve(&inits, m->tmp_allocator, vd->names.count); + array_init(&lvals, m->tmp_allocator, vd->names.count); + array_init(&inits, m->tmp_allocator, vd->names.count); for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; irAddr lval = ir_addr(NULL); if (!ir_is_blank_ident(name)) { ir_add_local_for_identifier(proc, name, false); @@ -5803,7 +5803,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } for_array(i, vd->values) { - irValue *init = ir_build_expr(proc, vd->values.e[i]); + irValue *init = ir_build_expr(proc, vd->values[i]); Type *t = ir_type(init); if (t->kind == Type_Tuple) { for (isize i = 0; i < t->Tuple.variable_count; i++) { @@ -5818,14 +5818,14 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { for_array(i, inits) { - ir_addr_store(proc, lvals.e[i], inits.e[i]); + ir_addr_store(proc, lvals[i], inits[i]); } } gb_temp_arena_memory_end(tmp); } else { for_array(i, vd->names) { - AstNode *ident = vd->names.e[i]; + AstNode *ident = vd->names[i]; GB_ASSERT(ident->kind == AstNode_Ident); Entity *e = entity_of_ident(proc->module->info, ident); GB_ASSERT(e != NULL); @@ -5925,11 +5925,11 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { switch (as->op.kind) { case Token_Eq: { - Array(irAddr) lvals; + Array lvals; array_init(&lvals, m->tmp_allocator); for_array(i, as->lhs) { - AstNode *lhs = as->lhs.e[i]; + AstNode *lhs = as->lhs[i]; irAddr lval = {}; if (!ir_is_blank_ident(lhs)) { lval = ir_build_addr(proc, lhs); @@ -5939,28 +5939,28 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (as->lhs.count == as->rhs.count) { if (as->lhs.count == 1) { - AstNode *rhs = as->rhs.e[0]; + AstNode *rhs = as->rhs[0]; irValue *init = ir_build_expr(proc, rhs); - ir_addr_store(proc, lvals.e[0], init); + ir_addr_store(proc, lvals[0], init); } else { irValueArray inits; - array_init_reserve(&inits, m->tmp_allocator, lvals.count); + array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { - irValue *init = ir_build_expr(proc, as->rhs.e[i]); + irValue *init = ir_build_expr(proc, as->rhs[i]); array_add(&inits, init); } for_array(i, inits) { - ir_addr_store(proc, lvals.e[i], inits.e[i]); + ir_addr_store(proc, lvals[i], inits[i]); } } } else { irValueArray inits; - array_init_reserve(&inits, m->tmp_allocator, lvals.count); + array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { - irValue *init = ir_build_expr(proc, as->rhs.e[i]); + irValue *init = ir_build_expr(proc, as->rhs[i]); Type *t = ir_type(init); // TODO(bill): refactor for code reuse as this is repeated a bit if (t->kind == Type_Tuple) { @@ -5975,7 +5975,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } for_array(i, inits) { - ir_addr_store(proc, lvals.e[i], inits.e[i]); + ir_addr_store(proc, lvals[i], inits[i]); } } @@ -5986,8 +5986,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { // +=, -=, etc i32 op = cast(i32)as->op.kind; op += Token_Add - Token_AddEq; // Convert += to + - irAddr lhs = ir_build_addr(proc, as->lhs.e[0]); - irValue *value = ir_build_expr(proc, as->rhs.e[0]); + irAddr lhs = ir_build_addr(proc, as->lhs[0]); + irValue *value = ir_build_expr(proc, as->rhs[0]); ir_build_assign_op(proc, lhs, value, cast(TokenKind)op); } break; } @@ -6024,16 +6024,16 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { // No return values } else if (return_count == 1) { Entity *e = return_type_tuple->variables[0]; - v = ir_build_expr(proc, rs->results.e[0]); + v = ir_build_expr(proc, rs->results[0]); v = ir_emit_conv(proc, v, e->type); } else { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); irValueArray results; - array_init_reserve(&results, proc->module->tmp_allocator, return_count); + array_init(&results, proc->module->tmp_allocator, return_count); for_array(res_index, rs->results) { - irValue *res = ir_build_expr(proc, rs->results.e[res_index]); + irValue *res = ir_build_expr(proc, rs->results[res_index]); Type *t = ir_type(res); if (t->kind == Type_Tuple) { for (isize i = 0; i < t->Tuple.variable_count; i++) { @@ -6050,7 +6050,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { v = ir_add_local_generated(proc, ret_type); for_array(i, results) { Entity *e = return_type_tuple->variables[i]; - irValue *res = ir_emit_conv(proc, results.e[i], e->type); + irValue *res = ir_emit_conv(proc, results[i], e->type); irValue *field = ir_emit_struct_ep(proc, v, i); ir_emit_store(proc, field, res); } @@ -6347,7 +6347,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { isize case_count = body->stmts.count; for_array(i, body->stmts) { - AstNode *clause = body->stmts.e[i]; + AstNode *clause = body->stmts[i]; irBlock *body = fall; ast_node(cc, CaseClause, clause); @@ -6379,7 +6379,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irBlock *next_cond = NULL; for_array(j, cc->list) { - AstNode *expr = unparen_expr(cc->list.e[j]); + AstNode *expr = unparen_expr(cc->list[j]); next_cond = ir_new_block(proc, clause, "match.case.next"); irValue *cond = v_false; if (is_ast_node_a_range(expr)) { @@ -6439,7 +6439,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { GB_ASSERT(as->lhs.count == 1); GB_ASSERT(as->rhs.count == 1); - irValue *parent = ir_build_expr(proc, as->rhs.e[0]); + irValue *parent = ir_build_expr(proc, as->rhs[0]); Type *parent_type = ir_type(parent); bool is_parent_ptr = is_type_pointer(ir_type(parent)); @@ -6474,7 +6474,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { gb_local_persist i32 weird_count = 0; for_array(i, body->stmts) { - AstNode *clause = body->stmts.e[i]; + AstNode *clause = body->stmts[i]; ast_node(cc, CaseClause, clause); if (cc->list.count == 0) { default_ = clause; @@ -6486,7 +6486,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *case_type = NULL; for_array(type_index, cc->list) { next = ir_new_block(proc, NULL, "typematch.next"); - case_type = type_of_expr(proc->module->info, cc->list.e[type_index]); + case_type = type_of_expr(proc->module->info, cc->list[type_index]); irValue *cond = NULL; if (match_type_kind == MatchType_Union) { Type *bt = type_deref(case_type); @@ -6660,10 +6660,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { void ir_number_proc_registers(irProcedure *proc) { i32 reg_index = 0; for_array(i, proc->blocks) { - irBlock *b = proc->blocks.e[i]; + irBlock *b = proc->blocks[i]; b->index = i; for_array(j, b->instrs) { - irValue *value = b->instrs.e[j]; + irValue *value = b->instrs[j]; GB_ASSERT(value->kind == irValue_Instr); irInstr *instr = &value->Instr; if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions @@ -6689,7 +6689,7 @@ void ir_begin_procedure_body(irProcedure *proc) { if (found != NULL) { DeclInfo *decl = *found; for_array(i, decl->labels) { - BlockLabel bl = decl->labels.e[i]; + BlockLabel bl = decl->labels[i]; irBranchBlocks bb = {bl.label, NULL, NULL}; array_add(&proc->branch_blocks, bb); } @@ -6723,13 +6723,13 @@ void ir_begin_procedure_body(irProcedure *proc) { for (isize i = 0; i < params->variable_count; i++) { ast_node(fl, FieldList, pt->params); GB_ASSERT(fl->list.count > 0); - GB_ASSERT(fl->list.e[0]->kind == AstNode_Field); - if (q_index == fl->list.e[param_index]->Field.names.count) { + GB_ASSERT(fl->list[0]->kind == AstNode_Field); + if (q_index == fl->list[param_index]->Field.names.count) { q_index = 0; param_index++; } - ast_node(field, Field, fl->list.e[param_index]); - AstNode *name = field->names.e[q_index++]; + ast_node(field, Field, fl->list[param_index]); + AstNode *name = field->names[q_index++]; Entity *e = params->variables[i]; Type *abi_type = proc->type->Proc.abi_compat_params[i]; @@ -6867,7 +6867,7 @@ void ir_init_module(irModule *m, Checker *c) { { isize max_index = -1; for_array(type_info_map_index, m->info->type_info_map.entries) { - MapIsizeEntry *entry = &m->info->type_info_map.entries.e[type_info_map_index]; + MapIsizeEntry *entry = &m->info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = ir_type_info_index(m->info, t); @@ -6892,7 +6892,7 @@ void ir_init_module(irModule *m, Checker *c) { isize count = 0; for_array(entry_index, m->info->type_info_map.entries) { - MapIsizeEntry *entry = &m->info->type_info_map.entries.e[entry_index]; + MapIsizeEntry *entry = &m->info->type_info_map.entries[entry_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; switch (t->kind) { @@ -6956,7 +6956,7 @@ void ir_init_module(irModule *m, Checker *c) { { irDebugInfo *di = ir_alloc_debug_info(m->allocator, irDebugInfo_CompileUnit); - di->CompileUnit.file = m->info->files.entries.e[0].value; // Zeroth is the init file + di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file di->CompileUnit.producer = str_lit("odin"); map_ir_debug_info_set(&m->debug_info, hash_pointer(m), di); @@ -7060,7 +7060,7 @@ void ir_add_foreign_library_path(irModule *m, Entity *e) { } for_array(path_index, m->foreign_library_paths) { - String path = m->foreign_library_paths.e[path_index]; + String path = m->foreign_library_paths[path_index]; #if defined(GB_SYSTEM_WINDOWS) if (str_eq_ignore_case(path, library_path)) { #else @@ -7095,7 +7095,7 @@ void ir_gen_tree(irGen *s) { bool has_win_main = false; for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + MapDeclInfoEntry *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; String name = e->token.string; if (e->kind == Entity_Variable) { @@ -7120,14 +7120,14 @@ void ir_gen_tree(irGen *s) { irValue *var, *init; DeclInfo *decl; } irGlobalVariable; - Array(irGlobalVariable) global_variables; - array_init_reserve(&global_variables, m->tmp_allocator, global_variable_max_count); + Array global_variables; + array_init(&global_variables, m->tmp_allocator, global_variable_max_count); m->entry_point_entity = entry_point; m->min_dep_map = generate_minimum_dependency_map(info, entry_point); for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + MapDeclInfoEntry *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; DeclInfo *decl = entry->value; @@ -7221,20 +7221,20 @@ void ir_gen_tree(irGen *s) { } for_array(i, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries.e[i]; + MapIrValueEntry *entry = &m->members.entries[i]; irValue *v = entry->value; if (v->kind == irValue_Proc) { ir_build_proc(v, NULL); } } - irDebugInfo *compile_unit = m->debug_info.entries.e[0].value; + irDebugInfo *compile_unit = m->debug_info.entries[0].value; GB_ASSERT(compile_unit->kind == irDebugInfo_CompileUnit); irDebugInfo *all_procs = ir_alloc_debug_info(m->allocator, irDebugInfo_AllProcs); isize all_proc_max_count = 0; for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; di->id = i; if (di->kind == irDebugInfo_Proc) { @@ -7242,13 +7242,13 @@ void ir_gen_tree(irGen *s) { } } - array_init_reserve(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count); + array_init(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count); map_ir_debug_info_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped compile_unit->CompileUnit.all_procs = all_procs; for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; if (di->kind == irDebugInfo_Proc) { array_add(&all_procs->AllProcs.procs, di); @@ -7390,7 +7390,7 @@ void ir_gen_tree(irGen *s) { // TODO(bill): Should do a dependency graph do check which order to initialize them in? for_array(i, global_variables) { - irGlobalVariable *var = &global_variables.e[i]; + irGlobalVariable *var = &global_variables[i]; if (var->decl->init_expr != NULL) { var->init = ir_build_expr(proc, var->decl->init_expr); } @@ -7398,7 +7398,7 @@ void ir_gen_tree(irGen *s) { // NOTE(bill): Initialize constants first for_array(i, global_variables) { - irGlobalVariable *var = &global_variables.e[i]; + irGlobalVariable *var = &global_variables[i]; if (var->init != NULL && var->init->kind == irValue_Constant) { Type *t = type_deref(ir_type(var->var)); if (is_type_any(t)) { @@ -7416,7 +7416,7 @@ void ir_gen_tree(irGen *s) { } for_array(i, global_variables) { - irGlobalVariable *var = &global_variables.e[i]; + irGlobalVariable *var = &global_variables[i]; if (var->init != NULL && var->init->kind != irValue_Constant) { Type *t = type_deref(ir_type(var->var)); if (is_type_any(t)) { @@ -7458,7 +7458,7 @@ void ir_gen_tree(irGen *s) { i32 type_info_member_offsets_index = 0; for_array(type_info_map_index, info->type_info_map.entries) { - MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index]; + MapIsizeEntry *entry = &info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = ir_type_info_index(info, t); @@ -7921,7 +7921,7 @@ void ir_gen_tree(irGen *s) { } for_array(type_info_map_index, info->type_info_map.entries) { - MapIsizeEntry *entry = &info->type_info_map.entries.e[type_info_map_index]; + MapIsizeEntry *entry = &info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = entry->value; @@ -7935,12 +7935,12 @@ void ir_gen_tree(irGen *s) { for_array(i, m->procs_to_generate) { - ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent); + ir_build_proc(m->procs_to_generate[i], m->procs_to_generate[i]->Proc.parent); } // Number debug info for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i]; + MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; di->id = i; } diff --git a/src/ir_opt.cpp b/src/ir_opt.cpp index e9d83941d..856d8aaf0 100644 --- a/src/ir_opt.cpp +++ b/src/ir_opt.cpp @@ -48,7 +48,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) { break; case irInstr_Phi: for_array(j, i->Phi.edges) { - array_add(ops, i->Phi.edges.e[j]); + array_add(ops, i->Phi.edges[j]); } break; case irInstr_Unreachable: @@ -97,24 +97,24 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) { void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) { for_array(i, b->preds) { - irBlock *pred = b->preds.e[i]; + irBlock *pred = b->preds[i]; if (pred == from) { - b->preds.e[i] = to; + b->preds[i] = to; } } } void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) { for_array(i, b->succs) { - irBlock *succ = b->succs.e[i]; + irBlock *succ = b->succs[i]; if (succ == from) { - b->succs.e[i] = to; + b->succs[i] = to; } } } bool ir_opt_block_has_phi(irBlock *b) { - return b->instrs.e[0]->Instr.kind == irInstr_Phi; + return b->instrs[0]->Instr.kind == irInstr_Phi; } @@ -129,7 +129,7 @@ bool ir_opt_block_has_phi(irBlock *b) { irValueArray ir_get_block_phi_nodes(irBlock *b) { irValueArray phis = {0}; for_array(i, b->instrs) { - irInstr *instr = &b->instrs.e[i]->Instr; + irInstr *instr = &b->instrs[i]->Instr; if (instr->kind != irInstr_Phi) { phis = b->instrs; phis.count = i; @@ -143,19 +143,19 @@ void ir_remove_pred(irBlock *b, irBlock *p) { irValueArray phis = ir_get_block_phi_nodes(b); isize i = 0; for_array(j, b->preds) { - irBlock *pred = b->preds.e[j]; + irBlock *pred = b->preds[j]; if (pred != p) { - b->preds.e[i] = b->preds.e[j]; + b->preds[i] = b->preds[j]; for_array(k, phis) { - irInstrPhi *phi = &phis.e[k]->Instr.Phi; - phi->edges.e[i] = phi->edges.e[j]; + irInstrPhi *phi = &phis[k]->Instr.Phi; + phi->edges[i] = phi->edges[j]; } i++; } } b->preds.count = i; for_array(k, phis) { - irInstrPhi *phi = &phis.e[k]->Instr.Phi; + irInstrPhi *phi = &phis[k]->Instr.Phi; phi->edges.count = i; } @@ -164,13 +164,13 @@ void ir_remove_pred(irBlock *b, irBlock *p) { void ir_remove_dead_blocks(irProcedure *proc) { isize j = 0; for_array(i, proc->blocks) { - irBlock *b = proc->blocks.e[i]; + irBlock *b = proc->blocks[i]; if (b == NULL) { continue; } // NOTE(bill): Swap order b->index = j; - proc->blocks.e[j++] = b; + proc->blocks[j++] = b; } proc->blocks.count = j; } @@ -180,7 +180,7 @@ void ir_mark_reachable(irBlock *b) { isize const BLACK = -1; b->index = BLACK; for_array(i, b->succs) { - irBlock *succ = b->succs.e[i]; + irBlock *succ = b->succs[i]; if (succ->index == WHITE) { ir_mark_reachable(succ); } @@ -191,23 +191,23 @@ void ir_remove_unreachable_blocks(irProcedure *proc) { isize const WHITE = 0; isize const BLACK = -1; for_array(i, proc->blocks) { - proc->blocks.e[i]->index = WHITE; + proc->blocks[i]->index = WHITE; } - ir_mark_reachable(proc->blocks.e[0]); + ir_mark_reachable(proc->blocks[0]); for_array(i, proc->blocks) { - irBlock *b = proc->blocks.e[i]; + irBlock *b = proc->blocks[i]; if (b->index == WHITE) { for_array(j, b->succs) { - irBlock *c = b->succs.e[j]; + irBlock *c = b->succs[j]; if (c->index == BLACK) { ir_remove_pred(c, b); } } // NOTE(bill): Mark as empty but don't actually free it // As it's been allocated with an arena - proc->blocks.e[i] = NULL; + proc->blocks[i] = NULL; } } ir_remove_dead_blocks(proc); @@ -217,7 +217,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) { if (a->succs.count != 1) { return false; } - irBlock *b = a->succs.e[0]; + irBlock *b = a->succs[0]; if (b->preds.count != 1) { return false; } @@ -228,21 +228,21 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) { array_pop(&a->instrs); // Remove branch at end for_array(i, b->instrs) { - array_add(&a->instrs, b->instrs.e[i]); - ir_set_instr_parent(b->instrs.e[i], a); + array_add(&a->instrs, b->instrs[i]); + ir_set_instr_parent(b->instrs[i], a); } array_clear(&a->succs); for_array(i, b->succs) { - array_add(&a->succs, b->succs.e[i]); + array_add(&a->succs, b->succs[i]); } // Fix preds links for_array(i, b->succs) { - ir_opt_block_replace_pred(b->succs.e[i], b, a); + ir_opt_block_replace_pred(b->succs[i], b, a); } - proc->blocks.e[b->index] = NULL; + proc->blocks[b->index] = NULL; return true; } @@ -254,7 +254,7 @@ void ir_opt_blocks(irProcedure *proc) { while (changed) { changed = false; for_array(i, proc->blocks) { - irBlock *b = proc->blocks.e[i]; + irBlock *b = proc->blocks[i]; if (b == NULL) { continue; } @@ -274,15 +274,15 @@ void ir_opt_build_referrers(irProcedure *proc) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); irValueArray ops = {0}; // NOTE(bill): Act as a buffer - array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena + array_init(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena for_array(i, proc->blocks) { - irBlock *b = proc->blocks.e[i]; + irBlock *b = proc->blocks[i]; for_array(j, b->instrs) { - irValue *instr = b->instrs.e[j]; + irValue *instr = b->instrs[j]; array_clear(&ops); ir_opt_add_operands(&ops, &instr->Instr); for_array(k, ops) { - irValue *op = ops.e[k]; + irValue *op = ops[k]; if (op == NULL) { continue; } @@ -324,7 +324,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde lt->sdom[p->index] = p; ir_lt_link(lt, NULL, p); for_array(index, p->succs) { - irBlock *q = p->succs.e[index]; + irBlock *q = p->succs[index]; if (lt->sdom[q->index] == NULL) { lt->parent[q->index] = p; i = ir_lt_depth_first_search(lt, q, i, preorder); @@ -354,7 +354,7 @@ irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) { v->dom.pre = pre++; for_array(i, v->dom.children) { - result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post); + result = ir_opt_number_dom_tree(v->dom.children[i], result.pre, result.post); } v->dom.post = post++; @@ -381,7 +381,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) { irBlock **preorder = &buf[3*n]; irBlock **buckets = &buf[4*n]; - irBlock *root = proc->blocks.e[0]; + irBlock *root = proc->blocks[0]; // Step 1 - number vertices i32 pre_num = ir_lt_depth_first_search(<, root, 0, preorder); @@ -403,7 +403,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) { // Step 2 - Compute all sdoms lt.sdom[w->index] = lt.parent[w->index]; for_array(pred_index, w->preds) { - irBlock *v = w->preds.e[pred_index]; + irBlock *v = w->preds[pred_index]; irBlock *u = ir_lt_eval(<, v); if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) { lt.sdom[w->index] = lt.sdom[u->index]; @@ -438,7 +438,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) { } // Calculate children relation as inverse of idom - if (w->dom.idom->dom.children.e == NULL) { + if (w->dom.idom->dom.children.data == NULL) { // TODO(bill): Is this good enough for memory allocations? array_init(&w->dom.idom->dom.children, heap_allocator()); } @@ -461,7 +461,7 @@ void ir_opt_tree(irGen *s) { s->opt_called = true; for_array(member_index, s->module.procs) { - irProcedure *proc = s->module.procs.e[member_index]; + irProcedure *proc = s->module.procs[member_index]; if (proc->blocks.count == 0) { // Prototype/external procedure continue; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 5bbe83e05..81809fa0a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -497,7 +497,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * if (i > 0) { ir_fprintf(f, ", "); } - TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]); + TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]); GB_ASSERT(tav.mode != Addressing_Invalid); ir_print_compound_element(f, m, tav.value, elem_type); } @@ -527,7 +527,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_fprintf(f, "]["); if (elem_count == 1 && type->Vector.count > 1) { - TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[0]); + TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[0]); GB_ASSERT(tav.mode != Addressing_Invalid); for (isize i = 0; i < type->Vector.count; i++) { @@ -541,7 +541,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * if (i > 0) { ir_fprintf(f, ", "); } - TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]); + TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]); GB_ASSERT(tav.mode != Addressing_Invalid); ir_print_compound_element(f, m, tav.value, elem_type); } @@ -563,24 +563,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count); - if (cl->elems.e[0]->kind == AstNode_FieldValue) { + if (cl->elems[0]->kind == AstNode_FieldValue) { isize elem_count = cl->elems.count; for (isize i = 0; i < elem_count; i++) { - ast_node(fv, FieldValue, cl->elems.e[i]); + ast_node(fv, FieldValue, cl->elems[i]); String name = fv->field->Ident.string; TypeAndValue tav = type_and_value_of_expr(m->info, fv->value); GB_ASSERT(tav.mode != Addressing_Invalid); Selection sel = lookup_field(m->allocator, type, name, false); - Entity *f = type->Record.fields[sel.index.e[0]]; + Entity *f = type->Record.fields[sel.index[0]]; values[f->Variable.field_index] = tav.value; } } else { for (isize i = 0; i < value_count; i++) { Entity *f = type->Record.fields_in_src_order[i]; - TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]); + TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]); ExactValue val = {}; if (tav.mode != Addressing_Invalid) { val = tav.value; @@ -891,11 +891,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, ", "); } - irValue *edge = instr->Phi.edges.e[i]; + irValue *edge = instr->Phi.edges[i]; irBlock *block = NULL; if (instr->parent != NULL && i < instr->parent->preds.count) { - block = instr->parent->preds.e[i]; + block = instr->parent->preds[i]; } ir_fprintf(f, "[ "); @@ -1538,14 +1538,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_fprintf(f, "{\n"); for_array(i, proc->blocks) { - irBlock *block = proc->blocks.e[i]; + irBlock *block = proc->blocks[i]; if (i > 0) ir_fprintf(f, "\n"); ir_print_block_name(f, block); ir_fprintf(f, ":\n"); for_array(j, block->instrs) { - irValue *value = block->instrs.e[j]; + irValue *value = block->instrs[j]; ir_print_instr(f, m, value); } } @@ -1555,7 +1555,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { } for_array(i, proc->children) { - ir_print_proc(f, m, proc->children.e[i]); + ir_print_proc(f, m, proc->children[i]); } } @@ -1606,7 +1606,7 @@ void print_llvm_ir(irGen *ir) { for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries.e[member_index]; + MapIrValueEntry *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_TypeName) { continue; @@ -1619,7 +1619,7 @@ void print_llvm_ir(irGen *ir) { bool dll_main_found = false; for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries.e[member_index]; + MapIrValueEntry *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Proc) { continue; @@ -1631,7 +1631,7 @@ void print_llvm_ir(irGen *ir) { } for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries.e[member_index]; + MapIrValueEntry *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Proc) { continue; @@ -1643,7 +1643,7 @@ void print_llvm_ir(irGen *ir) { } for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries.e[member_index]; + MapIrValueEntry *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Global) { continue; @@ -1707,7 +1707,7 @@ void print_llvm_ir(irGen *ir) { ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3); for_array(di_index, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index]; + MapIrDebugInfoEntry *entry = &m->debug_info.entries[di_index]; irDebugInfo *di = entry->value; ir_fprintf(f, "!%d = ", di->id); @@ -1752,7 +1752,7 @@ void print_llvm_ir(irGen *ir) { case irDebugInfo_AllProcs: ir_fprintf(f, "!{"); for_array(proc_index, di->AllProcs.procs) { - irDebugInfo *p = di->AllProcs.procs.e[proc_index]; + irDebugInfo *p = di->AllProcs.procs[proc_index]; if (proc_index > 0) {ir_fprintf(f, ",");} ir_fprintf(f, "!%d", p->id); } diff --git a/src/main.cpp b/src/main.cpp index 296a9e921..e4c6e6606 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -309,7 +309,7 @@ int main(int argc, char **argv) { // defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {0}; for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths.e[i]; + String lib = ir_gen.module.foreign_library_paths[i]; // gb_printf_err("Linking lib: %.*s\n", LIT(lib)); isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " \"%.*s\"", LIT(lib)); @@ -371,7 +371,7 @@ int main(int argc, char **argv) { // defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {0}; for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths.e[i]; + String lib = ir_gen.module.foreign_library_paths[i]; // NOTE(zangent): Sometimes, you have to use -framework on MacOS. // This allows you to specify '-f' in a #foreign_system_library, diff --git a/src/map.cpp b/src/map.cpp index 49ca604d0..f03e83424 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -92,8 +92,8 @@ typedef struct MAP_ENTRY { } MAP_ENTRY; typedef struct MAP_NAME { - Array(isize) hashes; - Array(MAP_ENTRY) entries; + Array hashes; + Array entries; } MAP_NAME; void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a); @@ -124,8 +124,8 @@ gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) { } gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) { - array_init_reserve(&h->hashes, a, capacity); - array_init_reserve(&h->entries, a, capacity); + array_init(&h->hashes, a, capacity); + array_init(&h->entries, a, capacity); } gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) { @@ -145,13 +145,13 @@ gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = key.key % h->hashes.count; - fr.entry_index = h->hashes.e[fr.hash_index]; + fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index >= 0) { - if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) { + if (hash_key_equal(h->entries[fr.entry_index].key, key)) { return fr; } fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.e[fr.entry_index].next; + fr.entry_index = h->entries[fr.entry_index].next; } } return fr; @@ -161,13 +161,13 @@ gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = e->key.key % h->hashes.count; - fr.entry_index = h->hashes.e[fr.hash_index]; + fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index >= 0) { - if (&h->entries.e[fr.entry_index] == e) { + if (&h->entries[fr.entry_index] == e) { return fr; } fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.e[fr.entry_index].next; + fr.entry_index = h->entries[fr.entry_index].next; } } return fr; @@ -190,10 +190,10 @@ void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { array_resize(&nh.hashes, new_count); array_reserve(&nh.entries, h->entries.count); for (i = 0; i < new_count; i++) { - nh.hashes.e[i] = -1; + nh.hashes[i] = -1; } for (i = 0; i < h->entries.count; i++) { - MAP_ENTRY *e = &h->entries.e[i]; + MAP_ENTRY *e = &h->entries[i]; MapFindResult fr; if (nh.hashes.count == 0) { _J2(MAP_PROC,grow)(&nh); @@ -201,12 +201,12 @@ void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { fr = _J2(MAP_PROC,_find)(&nh, e->key); j = _J2(MAP_PROC,_add_entry)(&nh, e->key); if (fr.entry_prev < 0) { - nh.hashes.e[fr.hash_index] = j; + nh.hashes[fr.hash_index] = j; } else { - nh.entries.e[fr.entry_prev].next = j; + nh.entries[fr.entry_prev].next = j; } - nh.entries.e[j].next = fr.entry_index; - nh.entries.e[j].value = e->value; + nh.entries[j].next = fr.entry_index; + nh.entries[j].value = e->value; if (_J2(MAP_PROC,_full)(&nh)) { _J2(MAP_PROC,grow)(&nh); } @@ -218,7 +218,7 @@ void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) { isize index = _J2(MAP_PROC,_find)(h, key).entry_index; if (index >= 0) { - return &h->entries.e[index].value; + return &h->entries[index].value; } return NULL; } @@ -234,12 +234,12 @@ void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { } else { index = _J2(MAP_PROC,_add_entry)(h, key); if (fr.entry_prev >= 0) { - h->entries.e[fr.entry_prev].next = index; + h->entries[fr.entry_prev].next = index; } else { - h->hashes.e[fr.hash_index] = index; + h->hashes[fr.hash_index] = index; } } - h->entries.e[index].value = value; + h->entries[index].value = value; if (_J2(MAP_PROC,_full)(h)) { _J2(MAP_PROC,grow)(h); @@ -251,20 +251,20 @@ void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { MapFindResult last; if (fr.entry_prev < 0) { - h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next; + h->hashes[fr.hash_index] = h->entries[fr.entry_index].next; } else { - h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next; + h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; } if (fr.entry_index == h->entries.count-1) { array_pop(&h->entries); return; } - h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1]; - last = _J2(MAP_PROC,_find)(h, h->entries.e[fr.entry_index].key); + h->entries[fr.entry_index] = h->entries[h->entries.count-1]; + last = _J2(MAP_PROC,_find)(h, h->entries[fr.entry_index].key); if (last.entry_prev >= 0) { - h->entries.e[last.entry_prev].next = fr.entry_index; + h->entries[last.entry_prev].next = fr.entry_index; } else { - h->hashes.e[last.hash_index] = fr.entry_index; + h->hashes[last.hash_index] = fr.entry_index; } } @@ -287,16 +287,16 @@ MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) { if (i < 0) { return NULL; } - return &h->entries.e[i]; + return &h->entries[i]; } MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) { isize i = e->next; while (i >= 0) { - if (hash_key_equal(h->entries.e[i].key, e->key)) { - return &h->entries.e[i]; + if (hash_key_equal(h->entries[i].key, e->key)) { + return &h->entries[i]; } - i = h->entries.e[i].next; + i = h->entries[i].next; } return NULL; } @@ -330,12 +330,12 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) { fr = _J2(MAP_PROC,_find)(h, key); i = _J2(MAP_PROC,_add_entry)(h, key); if (fr.entry_prev < 0) { - h->hashes.e[fr.hash_index] = i; + h->hashes[fr.hash_index] = i; } else { - h->entries.e[fr.entry_prev].next = i; + h->entries[fr.entry_prev].next = i; } - h->entries.e[i].next = fr.entry_index; - h->entries.e[i].value = value; + h->entries[i].next = fr.entry_index; + h->entries[i].value = value; // Grow if needed if (_J2(MAP_PROC,_full)(h)) { _J2(MAP_PROC,grow)(h); diff --git a/src/parser.cpp b/src/parser.cpp index 01510343e..2fc9f124d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -15,13 +15,13 @@ typedef enum ParseFileError { ParseFile_Count, } ParseFileError; -typedef Array(AstNode *) AstNodeArray; +typedef Array AstNodeArray; typedef struct AstFile { i32 id; gbArena arena; Tokenizer tokenizer; - Array(Token) tokens; + Array tokens; isize curr_token_index; Token curr_token; Token prev_token; // previous non-comment @@ -54,8 +54,8 @@ typedef struct ImportedFile { typedef struct Parser { String init_fullpath; - Array(AstFile) files; - Array(ImportedFile) imports; + Array files; + Array imports; gbAtomic32 import_index; isize total_token_count; isize total_line_count; @@ -525,7 +525,7 @@ Token ast_node_token(AstNode *node) { case AstNode_PushContext: return node->PushContext.token; case AstNode_BadDecl: return node->BadDecl.begin; - case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names.e[0]); + case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names[0]); case AstNode_ImportDecl: return node->ImportDecl.token; case AstNode_ForeignLibrary: return node->ForeignLibrary.token; case AstNode_Label: return node->Label.token; @@ -533,7 +533,7 @@ Token ast_node_token(AstNode *node) { case AstNode_Field: if (node->Field.names.count > 0) { - return ast_node_token(node->Field.names.e[0]); + return ast_node_token(node->Field.names[0]); } return ast_node_token(node->Field.type); case AstNode_FieldList: @@ -565,7 +565,7 @@ AstNodeArray clone_ast_node_array(gbAllocator a, AstNodeArray array) { if (array.count > 0) { array_init_count(&result, a, array.count); for_array(i, array) { - result.e[i] = clone_ast_node(a, array.e[i]); + result[i] = clone_ast_node(a, array[i]); } } return result; @@ -1457,7 +1457,7 @@ bool next_token(AstFile *f) { } f->curr_token_index++; - f->curr_token = f->tokens.e[f->curr_token_index]; + f->curr_token = f->tokens[f->curr_token_index]; if (f->curr_token.kind == Token_Comment) { return next_token(f); } @@ -1474,7 +1474,7 @@ TokenKind look_ahead_token_kind(AstFile *f, isize amount) { isize index = f->curr_token_index; while (amount > 0) { index++; - kind = f->tokens.e[index].kind; + kind = f->tokens[index].kind; if (kind != Token_Comment) { amount--; } @@ -1647,7 +1647,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_ValueDecl: if (!s->ValueDecl.is_var) { if (s->ValueDecl.values.count > 0) { - AstNode *last = s->ValueDecl.values.e[s->ValueDecl.values.count-1]; + AstNode *last = s->ValueDecl.values[s->ValueDecl.values.count-1]; return is_semicolon_optional_for_node(f, last); } } @@ -1961,7 +1961,7 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { } syntax_error(f->curr_token, "Expected `%.*s`, found a simple statement.", LIT(kind)); - return ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); + return ast_bad_expr(f, f->curr_token, f->tokens[f->curr_token_index+1]); } @@ -1990,20 +1990,20 @@ AstNode *parse_operand(AstFile *f, bool lhs) { // NOTE(bill): Allow neighbouring string literals to be merge together to // become one big string String s = f->curr_token.string; - Array(u8) data; - array_init_reserve(&data, heap_allocator(), token.string.len+s.len); - gb_memmove(data.e, token.string.text, token.string.len); + Array data; + array_init(&data, heap_allocator(), token.string.len+s.len); + gb_memmove(data.data, token.string.text, token.string.len); data.count += token.string.len; while (f->curr_token.kind == Token_String) { String s = f->curr_token.string; isize old_count = data.count; array_resize(&data, data.count + s.len); - gb_memmove(data.e+old_count, s.text, s.len); + gb_memmove(data.data+old_count, s.text, s.len); next_token(f); } - token.string = make_string(data.e, data.count); + token.string = make_string(data.data, data.count); array_add(&f->tokenizer.allocated_strings, token.string); } @@ -2512,12 +2512,12 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { } } - if (values.e == NULL) { + if (values.data == NULL) { values = make_ast_node_array(f); } AstNodeArray specs = {}; - array_init_reserve(&specs, heap_allocator(), 1); + array_init(&specs, heap_allocator(), 1); return ast_value_decl(f, is_mutable, lhs, type, values); } @@ -2566,7 +2566,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { AstNodeArray rhs = {}; array_init_count(&rhs, heap_allocator(), 1); - rhs.e[0] = expr; + rhs[0] = expr; return ast_assign_stmt(f, token, lhs, rhs); } @@ -2579,7 +2579,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { case Token_for: case Token_match: { next_token(f); - AstNode *name = lhs.e[0]; + AstNode *name = lhs[0]; AstNode *label = ast_label_decl(f, ast_node_token(name), name); AstNode *stmt = parse_stmt(f); #define _SET_LABEL(Kind_, label_) case GB_JOIN2(AstNode_, Kind_): (stmt->Kind_).label = label_; break @@ -2612,10 +2612,10 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { case Token_Inc: case Token_Dec: next_token(f); - return ast_inc_dec_stmt(f, token, lhs.e[0]); + return ast_inc_dec_stmt(f, token, lhs[0]); } - return ast_expr_stmt(f, lhs.e[0]); + return ast_expr_stmt(f, lhs[0]); } @@ -2786,14 +2786,12 @@ typedef struct AstNodeAndFlags { u32 flags; } AstNodeAndFlags; -typedef Array(AstNodeAndFlags) AstNodeAndFlagsArray; - -AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool ignore_flags) { +AstNodeArray convert_to_ident_list(AstFile *f, Array list, bool ignore_flags) { AstNodeArray idents = {}; - array_init_reserve(&idents, heap_allocator(), list.count); + array_init(&idents, heap_allocator(), list.count); // Convert to ident list for_array(i, list) { - AstNode *ident = list.e[i].node; + AstNode *ident = list[i].node; if (!ignore_flags) { if (i != 0) { @@ -2834,7 +2832,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok Token start_token = f->curr_token; AstNodeArray params = make_ast_node_array(f); - AstNodeAndFlagsArray list = {}; array_init(&list, heap_allocator()); // LEAK(bill): + Array list = {}; array_init(&list, heap_allocator()); // LEAK(bill): isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; @@ -2858,7 +2856,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok } u32 set_flags = 0; if (list.count > 0) { - set_flags = list.e[0].flags; + set_flags = list[0].flags; } set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); total_name_count += names.count; @@ -2897,15 +2895,15 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok for_array(i, list) { AstNodeArray names = {}; - AstNode *type = list.e[i].node; + AstNode *type = list[i].node; Token token = blank_token; array_init_count(&names, heap_allocator(), 1); token.pos = ast_node_token(type).pos; - names.e[0] = ast_ident(f, token); - u32 flags = check_field_prefixes(f, list.count, allowed_flags, list.e[i].flags); + names[0] = ast_ident(f, token); + u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags); - AstNode *param = ast_field(f, names, list.e[i].node, flags); + AstNode *param = ast_field(f, names, list[i].node, flags); array_add(¶ms, param); } @@ -3095,7 +3093,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *type = parse_var_type(f, false); array_add(&decls, ast_field(f, names, type, set_flags)); } else { - AstNode *name = names.e[0]; + AstNode *name = names[0]; Token open = expect_token(f, Token_OpenBrace); isize decl_count = 0; AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union")); @@ -3273,7 +3271,7 @@ AstNode *parse_if_stmt(AstFile *f) { break; default: syntax_error(f->curr_token, "Expected if statement block statement"); - else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); + else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]); break; } } @@ -3310,7 +3308,7 @@ AstNode *parse_when_stmt(AstFile *f) { break; default: syntax_error(f->curr_token, "Expected when statement block statement"); - else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); + else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]); break; } } @@ -3337,7 +3335,11 @@ AstNode *parse_return_stmt(AstFile *f) { results = make_ast_node_array(f); } - expect_semicolon(f, results.e[0]); + AstNode *end = NULL; + if (results.count > 0) { + end = results[results.count-1]; + } + expect_semicolon(f, end); return ast_return_stmt(f, token, results); } @@ -3413,11 +3415,11 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *index = NULL; switch (cond->AssignStmt.lhs.count) { case 1: - value = cond->AssignStmt.lhs.e[0]; + value = cond->AssignStmt.lhs[0]; break; case 2: - value = cond->AssignStmt.lhs.e[0]; - index = cond->AssignStmt.lhs.e[1]; + value = cond->AssignStmt.lhs[0]; + index = cond->AssignStmt.lhs[1]; break; default: error_node(cond, "Expected at 1 or 2 identifiers"); @@ -3426,7 +3428,7 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *rhs = NULL; if (cond->AssignStmt.rhs.count > 0) { - rhs = cond->AssignStmt.rhs.e[0]; + rhs = cond->AssignStmt.rhs[0]; } return ast_range_stmt(f, token, value, index, in_token, rhs, body); } @@ -3613,7 +3615,7 @@ AstNode *parse_stmt(AstFile *f) { } if (f->curr_token.kind != Token_Colon) { - expect_semicolon(f, list.e[list.count-1]); + expect_semicolon(f, list[list.count-1]); return ast_using_stmt(f, token, list); } @@ -3920,8 +3922,8 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) { } f->curr_token_index = 0; - f->prev_token = f->tokens.e[f->curr_token_index]; - f->curr_token = f->tokens.e[f->curr_token_index]; + f->prev_token = f->tokens[f->curr_token_index]; + f->curr_token = f->tokens[f->curr_token_index]; // NOTE(bill): Is this big enough or too small? isize arena_size = gb_size_of(AstNode); @@ -3962,7 +3964,7 @@ bool init_parser(Parser *p) { void destroy_parser(Parser *p) { // TODO(bill): Fix memory leak for_array(i, p->files) { - destroy_ast_file(&p->files.e[i]); + destroy_ast_file(&p->files[i]); } #if 0 for_array(i, p->imports) { @@ -3982,7 +3984,7 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) rel_path = string_trim_whitespace(rel_path); for_array(i, p->imports) { - String import = p->imports.e[i].path; + String import = p->imports[i].path; if (import == path) { return false; } @@ -4042,7 +4044,7 @@ bool is_import_path_valid(String path) { void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls) { for_array(i, decls) { - AstNode *node = decls.e[i]; + AstNode *node = decls[i]; if (!is_ast_node_decl(node) && node->kind != AstNode_BadStmt && node->kind != AstNode_EmptyStmt) { @@ -4072,7 +4074,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray if (collection_name.len == 0) { syntax_error_node(node, "Missing import collection for path: `%.*s`", LIT(oirignal_string)); - decls.e[i] = ast_bad_decl(f, id->relpath, id->relpath); + decls[i] = ast_bad_decl(f, id->relpath, id->relpath); continue; } @@ -4089,7 +4091,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray } } else { syntax_error_node(node, "Unknown import collection: `%.*s`", LIT(collection_name)); - decls.e[i] = ast_bad_decl(f, id->relpath, id->relpath); + decls[i] = ast_bad_decl(f, id->relpath, id->relpath); continue; } @@ -4100,7 +4102,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray syntax_error_node(node, "Invalid include path: `%.*s`", LIT(file_str)); } // NOTE(bill): It's a naughty name - decls.e[i] = ast_bad_decl(f, id->relpath, id->relpath); + decls[i] = ast_bad_decl(f, id->relpath, id->relpath); continue; } @@ -4112,7 +4114,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray syntax_error_node(node, "Invalid include path: `%.*s`", LIT(file_str)); } // NOTE(bill): It's a naughty name - decls.e[i] = ast_bad_decl(f, id->relpath, id->relpath); + decls[i] = ast_bad_decl(f, id->relpath, id->relpath); continue; } @@ -4140,7 +4142,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray syntax_error_node(node, "Invalid `foreign_library` path"); } // NOTE(bill): It's a naughty name - f->decls.e[i] = ast_bad_decl(f, fl->token, fl->token); + f->decls[i] = ast_bad_decl(f, fl->token, fl->token); continue; } @@ -4192,7 +4194,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { p->init_fullpath = init_fullpath; for_array(i, p->imports) { - ImportedFile imported_file = p->imports.e[i]; + ImportedFile imported_file = p->imports[i]; String import_path = imported_file.path; String import_rel_path = imported_file.rel_path; TokenPos pos = imported_file.pos; @@ -4245,7 +4247,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { } for_array(i, p->files) { - p->total_token_count += p->files.e[i].tokens.count; + p->total_token_count += p->files[i].tokens.count; } diff --git a/src/ssa.cpp b/src/ssa.cpp index b6bdb290a..ebda96c31 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -19,7 +19,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e); #define MAP_NAME MapSsaValue #include "map.cpp" -typedef Array(ssaValue *) ssaValueArray; +typedef Array ssaValueArray; #include "ssa_op.cpp" @@ -30,6 +30,15 @@ struct ssaValueArgs { isize capacity; ssaValue * backing[SSA_DEFAULT_VALUE_ARG_CAPACITY]; gbAllocator allocator; + + ssaValue *&operator[](isize i) { + GB_ASSERT(0 <= i && i <= count); + return e[i]; + } + ssaValue * const &operator[](isize i) const { + GB_ASSERT(0 <= i && i <= count); + return e[i]; + } }; struct ssaValue { @@ -97,7 +106,7 @@ struct ssaEdge { isize index; }; -typedef Array(ssaEdge) ssaEdgeArray; +typedef Array ssaEdgeArray; struct ssaBlock { i32 id; // Unique identifier but the pointer could be used too @@ -134,7 +143,7 @@ struct ssaProc { Entity * entity; DeclInfo * decl_info; - Array(ssaBlock *) blocks; + Array blocks; ssaBlock * entry; // Entry block ssaBlock * exit; // Exit block ssaBlock * curr_block; @@ -145,7 +154,7 @@ struct ssaProc { i32 value_id; MapSsaValue values; // Key: Entity * - Array(ssaDefer) defer_stmts; + Array defer_stmts; i32 scope_level; }; @@ -164,7 +173,7 @@ struct ssaModule { MapEntity min_dep_map; // Key: Entity * MapSsaValue values; // Key: Entity * // List of registers for the specific architecture - Array(ssaRegister) registers; + Array registers; ssaProc *proc; // current procedure @@ -172,7 +181,7 @@ struct ssaModule { u32 stmt_state_flags; - Array(ssaProc *) procs; + Array procs; ssaValueArray procs_to_generate; }; @@ -406,7 +415,7 @@ ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel); void ssa_reset_value_args(ssaValue *v) { for_array(i, v->args) { - v->args.e[i]->uses--; + v->args[i]->uses--; } v->args.count = 0; } @@ -425,7 +434,7 @@ ssaValue *ssa_get_last_value(ssaBlock *b) { if (len <= 0) { return 0; } - ssaValue *v = b->values.e[len-1]; + ssaValue *v = b->values[len-1]; return v; } @@ -451,7 +460,7 @@ void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) { void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) { isize count = p->defer_stmts.count; for (isize i = count-1; i >= 0; i--) { - ssaDefer d = p->defer_stmts.e[i]; + ssaDefer d = p->defer_stmts[i]; if (kind == ssaDeferExit_Default) { gb_printf_err("scope_level %d %d\n", p->scope_level, d.scope_level); if (p->scope_level == d.scope_level && @@ -782,7 +791,7 @@ ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) { // NOTE(bill): Returns NULL if not possible ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) { if (v->op == ssaOp_Load) { - return v->args.e[0]; + return v->args[0]; } ssaAddr addr = ssa_add_local_generated(p, v->type); ssa_new_value2(p, ssaOp_Store, addr.addr->type, addr.addr, v); @@ -863,7 +872,7 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) { ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) { if (s->op == ssaOp_Load) { if (!can_ssa_type(s->type)) { - ssaValue *e = ssa_emit_ptr_index(p, s->args.e[0], index); + ssaValue *e = ssa_emit_ptr_index(p, s->args[0], index); return ssa_emit_load(p, e); } } @@ -930,7 +939,7 @@ ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel) Type *type = type_deref(e->type); for_array(i, sel.index) { - i32 index = cast(i32)sel.index.e[i]; + i32 index = cast(i32)sel.index[i]; if (is_type_pointer(type)) { type = type_deref(type); e = ssa_emit_load(p, e); @@ -994,14 +1003,14 @@ ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel Type *type = e->type; if (e->op == ssaOp_Load) { if (!can_ssa_type(e->type)) { - ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args.e[0], sel); + ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args[0], sel); return ssa_emit_load(p, ptr); } } GB_ASSERT(can_ssa_type(e->type)); for_array(i, sel.index) { - i32 index = cast(i32)sel.index.e[i]; + i32 index = cast(i32)sel.index[i]; if (is_type_pointer(type)) { e = ssa_emit_load(p, e); } @@ -1837,7 +1846,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { case_ast_node(ce, CallExpr, expr); if (map_tav_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { GB_ASSERT(ce->args.count == 1); - ssaValue *x = ssa_build_expr(p, ce->args.e[0]); + ssaValue *x = ssa_build_expr(p, ce->args[0]); return ssa_emit_conv(p, x, tv.type); } @@ -1863,7 +1872,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) { for_array(i, nodes) { - ssa_build_stmt(p, nodes.e[i]); + ssa_build_stmt(p, nodes[i]); } } @@ -1946,7 +1955,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { case_ast_node(us, UsingStmt, node); for_array(i, us->list) { - AstNode *decl = unparen_expr(us->list.e[i]); + AstNode *decl = unparen_expr(us->list[i]); if (decl->kind == AstNode_ValueDecl) { ssa_build_stmt(p, decl); } @@ -1973,19 +1982,19 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); if (vd->values.count == 0) { for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; if (!ssa_is_blank_ident(name)) { ssa_add_local_for_ident(p, name); } } } else { - Array(ssaAddr) lvals = {0}; + Array 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); + array_init(&lvals, m->tmp_allocator, vd->names.count); + array_init(&inits, m->tmp_allocator, vd->names.count); for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; + AstNode *name = vd->names[i]; ssaAddr lval = ssa_addr(NULL); if (!ssa_is_blank_ident(name)) { lval = ssa_add_local_for_ident(p, name); @@ -1995,7 +2004,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { } for_array(i, vd->values) { - ssaValue *init = ssa_build_expr(p, vd->values.e[i]); + ssaValue *init = ssa_build_expr(p, vd->values[i]); if (init == NULL) { // TODO(bill): remove this continue; } @@ -2012,7 +2021,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { } for_array(i, inits) { - ssa_addr_store(p, lvals.e[i], inits.e[i]); + ssa_addr_store(p, lvals[i], inits[i]); } } @@ -2030,11 +2039,11 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { switch (as->op.kind) { case Token_Eq: { - Array(ssaAddr) lvals = {0}; + Array lvals = {0}; array_init(&lvals, m->tmp_allocator); for_array(i, as->lhs) { - AstNode *lhs = as->lhs.e[i]; + AstNode *lhs = as->lhs[i]; ssaAddr lval = {0}; if (!ssa_is_blank_ident(lhs)) { lval = ssa_build_addr(p, lhs); @@ -2044,28 +2053,28 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { if (as->lhs.count == as->rhs.count) { if (as->lhs.count == 1) { - AstNode *rhs = as->rhs.e[0]; + AstNode *rhs = as->rhs[0]; ssaValue *init = ssa_build_expr(p, rhs); - ssa_addr_store(p, lvals.e[0], init); + ssa_addr_store(p, lvals[0], init); } else { ssaValueArray inits; - array_init_reserve(&inits, m->tmp_allocator, lvals.count); + array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { - ssaValue *init = ssa_build_expr(p, as->rhs.e[i]); + ssaValue *init = ssa_build_expr(p, as->rhs[i]); array_add(&inits, init); } for_array(i, inits) { - ssa_addr_store(p, lvals.e[i], inits.e[i]); + ssa_addr_store(p, lvals[i], inits[i]); } } } else { ssaValueArray inits; - array_init_reserve(&inits, m->tmp_allocator, lvals.count); + array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { - ssaValue *init = ssa_build_expr(p, as->rhs.e[i]); + ssaValue *init = ssa_build_expr(p, as->rhs[i]); Type *t = base_type(init->type); // TODO(bill): refactor for code reuse as this is repeated a bit if (t->kind == Type_Tuple) { @@ -2080,7 +2089,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { } for_array(i, inits) { - ssa_addr_store(p, lvals.e[i], inits.e[i]); + ssa_addr_store(p, lvals[i], inits[i]); } } } break; @@ -2091,8 +2100,8 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { // +=, -=, 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]); + ssaAddr lhs = ssa_build_addr(p, as->lhs[0]); + ssaValue *value = ssa_build_expr(p, as->rhs[0]); ssa_build_assign_op(p, lhs, value, cast(TokenKind)op); } break; } @@ -2316,7 +2325,7 @@ void ssa_print_reg_value(gbFile *f, ssaValue *v) { for_array(i, v->args) { gb_fprintf(f, " "); - ssa_print_value(f, v->args.e[i]); + ssa_print_value(f, v->args[i]); } if (v->comment_string.len > 0) { @@ -2335,12 +2344,12 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1); for_array(i, p->blocks) { - ssaBlock *b = p->blocks.e[i]; + ssaBlock *b = p->blocks[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; + ssaBlock *pred = b->preds[j].block; gb_fprintf(f, " b%d", pred->id); } } @@ -2351,7 +2360,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { isize n = 0; for_array(j, b->values) { - ssaValue *v = b->values.e[j]; + ssaValue *v = b->values[j]; if (v->op != ssaOp_Phi) { continue; } @@ -2363,13 +2372,13 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { while (n < b->values.count) { isize m = 0; for_array(j, b->values) { - ssaValue *v = b->values.e[j]; + ssaValue *v = b->values[j]; if (printed[v->id]) { continue; } bool skip = false; for_array(k, v->args) { - ssaValue *w = v->args.e[k]; + ssaValue *w = v->args[k]; if (w != NULL && w->block == b && !printed[w->id]) { skip = true; break; @@ -2387,7 +2396,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { if (m == n) { gb_fprintf(f, "!!!!DepCycle!!!!\n"); for_array(k, b->values) { - ssaValue *v = b->values.e[k]; + ssaValue *v = b->values[k]; if (printed[v->id]) { continue; } @@ -2401,14 +2410,14 @@ void ssa_print_proc(gbFile *f, ssaProc *p) { if (b->kind == ssaBlock_Plain) { GB_ASSERT(b->succs.count == 1); - ssaBlock *next = b->succs.e[0].block; + ssaBlock *next = b->succs[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; + ssaBlock *yes = b->succs[0].block; + ssaBlock *no = b->succs[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"); @@ -2491,7 +2500,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { bool has_win_main = false; for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + MapDeclInfoEntry *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; String name = e->token.string; if (e->kind == Entity_Variable) { @@ -2517,7 +2526,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { m.min_dep_map = generate_minimum_dependency_map(info, entry_point); for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries.e[i]; + MapDeclInfoEntry *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; DeclInfo *decl = entry->value; diff --git a/src/timings.cpp b/src/timings.cpp index 046f476fe..04c1667f4 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -6,7 +6,7 @@ typedef struct TimeStamp { typedef struct Timings { TimeStamp total; - Array(TimeStamp) sections; + Array sections; u64 freq; } Timings; @@ -83,7 +83,7 @@ TimeStamp make_time_stamp(String label) { } void timings_init(Timings *t, String label, isize buffer_size) { - array_init_reserve(&t->sections, heap_allocator(), buffer_size); + array_init(&t->sections, heap_allocator(), buffer_size); t->total = make_time_stamp(label); t->freq = time_stamp__freq(); } @@ -94,7 +94,7 @@ void timings_destroy(Timings *t) { void timings__stop_current_section(Timings *t) { if (t->sections.count > 0) { - t->sections.e[t->sections.count-1].finish = time_stamp_time_now(); + t->sections[t->sections.count-1].finish = time_stamp_time_now(); } } @@ -117,7 +117,7 @@ void timings_print_all(Timings *t) { max_len = t->total.label.len; for_array(i, t->sections) { - TimeStamp ts = t->sections.e[i]; + TimeStamp ts = t->sections[i]; max_len = gb_max(max_len, ts.label.len); } @@ -129,7 +129,7 @@ void timings_print_all(Timings *t) { time_stamp_as_ms(t->total, t->freq)); for_array(i, t->sections) { - TimeStamp ts = t->sections.e[i]; + TimeStamp ts = t->sections[i]; gb_printf("%.*s%.*s - %.3f ms\n", LIT(ts.label), cast(int)(max_len-ts.label.len), SPACES, diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 5c9809bd1..9e4151c50 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -338,7 +338,7 @@ typedef struct Tokenizer { isize line_count; isize error_count; - Array(String) allocated_strings; + Array allocated_strings; } Tokenizer; @@ -460,7 +460,7 @@ gb_inline void destroy_tokenizer(Tokenizer *t) { gb_free(heap_allocator(), t->start); } for_array(i, t->allocated_strings) { - gb_free(heap_allocator(), t->allocated_strings.e[i].text); + gb_free(heap_allocator(), t->allocated_strings[i].text); } array_free(&t->allocated_strings); } diff --git a/src/types.cpp b/src/types.cpp index 41fc1f901..5ec5a40e9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -197,13 +197,13 @@ typedef struct Type { // TODO(bill): Should I add extra information here specifying the kind of selection? // e.g. field, constant, vector field, type field, etc. typedef struct Selection { - Entity * entity; - Array_i32 index; - bool indirect; // Set if there was a pointer deref anywhere down the line + Entity * entity; + Array index; + bool indirect; // Set if there was a pointer deref anywhere down the line } Selection; Selection empty_selection = {0}; -Selection make_selection(Entity *entity, Array_i32 index, bool indirect) { +Selection make_selection(Entity *entity, Array index, bool indirect) { Selection s = {entity, index, indirect}; return s; } @@ -212,10 +212,10 @@ void selection_add_index(Selection *s, isize index) { // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form // of heap allocation // TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3 - if (s->index.e == NULL) { + if (s->index.data == NULL) { array_init(&s->index, heap_allocator()); } - array_add(&s->index, index); + array_add(&s->index, cast(i32)index); } @@ -1297,9 +1297,9 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { Entity *f = type->Record.fields[i]; if (f->kind == Entity_Variable) { if (f->Variable.field_src_index == index) { - Array_i32 sel_array = {0}; + Array sel_array = {0}; array_init_count(&sel_array, a, 1); - sel_array.e[0] = i; + sel_array[0] = i; return make_selection(f, sel_array, false); } } @@ -1309,18 +1309,18 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { for (isize i = 0; i < max_count; i++) { Entity *f = type->Tuple.variables[i]; if (i == index) { - Array_i32 sel_array = {0}; + Array sel_array = {0}; array_init_count(&sel_array, a, 1); - sel_array.e[0] = i; + sel_array[0] = i; return make_selection(f, sel_array, false); } } break; case Type_BitField: { - Array_i32 sel_array = {0}; + Array sel_array = {0}; array_init_count(&sel_array, a, 1); - sel_array.e[0] = cast(i32)index; + sel_array[0] = cast(i32)index; return make_selection(type->BitField.fields[index], sel_array, false); } break; @@ -1509,7 +1509,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n typedef struct TypePath { - Array(Type *) path; // Entity_TypeName; + Array path; // Entity_TypeName; bool failure; } TypePath; @@ -1526,7 +1526,7 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) { GB_ASSERT(tp != NULL); GB_ASSERT(start_index < tp->path.count); - Type *t = tp->path.e[start_index]; + Type *t = tp->path[start_index]; GB_ASSERT(t != NULL); GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t)); @@ -1534,7 +1534,7 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) { error(e->token, "Illegal declaration cycle of `%.*s`", LIT(t->Named.name)); // NOTE(bill): Print cycle, if it's deep enough for (isize j = start_index; j < tp->path.count; j++) { - Type *t = tp->path.e[j]; + Type *t = tp->path[j]; GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t)); Entity *e = t->Named.type_name; error(e->token, "\t%.*s refers to", LIT(t->Named.name)); @@ -1549,7 +1549,7 @@ TypePath *type_path_push(TypePath *tp, Type *t) { GB_ASSERT(tp != NULL); for (isize i = 0; i < tp->path.count; i++) { - if (tp->path.e[i] == t) { + if (tp->path[i] == t) { type_path_print_illegal_cycle(tp, i); } } @@ -2082,7 +2082,7 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s Type *t = type; i64 offset = 0; for_array(i, sel.index) { - isize index = sel.index.e[i]; + isize index = sel.index[i]; t = base_type(t); offset += type_offset_of(allocator, t, index); if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) { -- cgit v1.2.3 From 2b96be0ae8b74e6081a00d740dfcbe205f76fb22 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 13:08:39 +0100 Subject: Remove unnecessary `typedef` usage --- src/build_settings.cpp | 4 +- src/check_decl.cpp | 4 +- src/check_expr.cpp | 28 +++--- src/check_stmt.cpp | 14 +-- src/checker.cpp | 73 ++++++++------- src/common.cpp | 2 - src/entity.cpp | 25 +++--- src/exact_value.cpp | 14 +-- src/ir.cpp | 152 +++++++++++++++---------------- src/ir_opt.cpp | 12 +-- src/ir_print.cpp | 4 +- src/parser.cpp | 237 ++++++++++++++++++++++++------------------------- src/ssa.cpp | 58 ++++++------ src/ssa_op.cpp | 1 - src/string.cpp | 8 +- src/timings.cpp | 8 +- src/tokenizer.cpp | 28 +++--- src/types.cpp | 42 ++++----- 18 files changed, 349 insertions(+), 365 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index dac763010..eb8a50c6a 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1,5 +1,5 @@ // This stores the information for the specify architecture of this build -typedef struct BuildContext { +struct BuildContext { // Constants String ODIN_OS; // target operating system String ODIN_ARCH; // target architecture @@ -15,7 +15,7 @@ typedef struct BuildContext { String llc_flags; String link_flags; bool is_dll; -} BuildContext; +}; gb_global BuildContext build_context = {0}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1e7e23398..356cd488b 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -58,7 +58,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex return e->type; } -void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) { +void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array inits, String context_name) { if ((lhs == NULL || lhs_count == 0) && inits.count == 0) { return; } @@ -431,7 +431,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } } - AstNodeArray inits; + Array inits; array_init(&inits, c->allocator, 1); array_add(&inits, init_expr); check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration")); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 55670f7e5..2af676831 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -16,7 +16,7 @@ void update_expr_type (Checker *c, AstNode *e, Type *type, boo bool check_is_terminating (AstNode *node); bool check_has_break (AstNode *stmt, bool implicit); void check_stmt (Checker *c, AstNode *node, u32 flags); -void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags); +void check_stmt_list (Checker *c, Array stmts, u32 flags); void check_init_constant (Checker *c, Entity *e, Operand *operand); bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call); @@ -46,7 +46,7 @@ void error_operand_no_value(Operand *o) { } -void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) { +void check_scope_decls(Checker *c, Array nodes, isize reserve_size) { Scope *s = c->context.scope; GB_ASSERT(!s->is_file); @@ -385,7 +385,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en // Returns filled field_count -isize check_fields(Checker *c, AstNode *node, AstNodeArray decls, +isize check_fields(Checker *c, AstNode *node, Array decls, Entity **fields, isize field_count, String context) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); @@ -692,7 +692,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { ast_node(fl, FieldList, f->list); // NOTE(bill): Copy the contents for the common fields for now - AstNodeArray list = {}; + Array list = {}; array_init_count(&list, c->allocator, ut->fields.count+fl->list.count); gb_memmove_array(list.data, ut->fields.data, ut->fields.count); gb_memmove_array(list.data+ut->fields.count, fl->list.data, fl->list.count); @@ -1033,7 +1033,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari return NULL; } ast_node(field_list, FieldList, _params); - AstNodeArray params = field_list->list; + Array params = field_list->list; if (params.count == 0) { return NULL; @@ -1118,7 +1118,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { return NULL; } ast_node(field_list, FieldList, _results); - AstNodeArray results = field_list->list; + Array results = field_list->list; if (results.count == 0) { return NULL; @@ -4698,7 +4698,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return true; } -typedef enum CallArgumentError { +enum CallArgumentError { CallArgumentError_None, CallArgumentError_WrongTypes, CallArgumentError_NonVariadicExpand, @@ -4707,12 +4707,12 @@ typedef enum CallArgumentError { CallArgumentError_ArgumentCount, CallArgumentError_TooFewArguments, CallArgumentError_TooManyArguments, -} CallArgumentError; +}; -typedef enum CallArgumentErrorMode { +enum CallArgumentErrorMode { CallArgumentMode_NoErrors, CallArgumentMode_ShowErrors, -} CallArgumentErrorMode; +}; CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, CallArgumentErrorMode show_error_mode, i64 *score_) { @@ -4823,10 +4823,10 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type return err; } -typedef struct ValidProcAndScore { +struct ValidProcAndScore { isize index; i64 score; -} ValidProcAndScore; +}; int valid_proc_and_score_cmp(void const *a, void const *b) { i64 si = (cast(ValidProcAndScore const *)a)->score; @@ -4834,7 +4834,7 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { return sj < si ? -1 : sj > si; } -bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, AstNodeArray rhs, bool allow_ok) { +bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, Array rhs, bool allow_ok) { bool optional_ok = false; for_array(i, rhs) { Operand o = {}; @@ -6139,7 +6139,7 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { gbString write_expr_to_string(gbString str, AstNode *node); -gbString write_record_fields_to_string(gbString str, AstNodeArray params) { +gbString write_record_fields_to_string(gbString str, Array params) { for_array(i, params) { if (i > 0) { str = gb_string_appendc(str, ", "); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 9a0f6afa5..859aa593d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1,4 +1,4 @@ -void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { +void check_stmt_list(Checker *c, Array stmts, u32 flags) { if (stmts.count == 0) { return; } @@ -40,7 +40,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { } -bool check_is_terminating_list(AstNodeArray stmts) { +bool check_is_terminating_list(Array stmts) { // Iterate backwards for (isize n = stmts.count-1; n >= 0; n--) { AstNode *stmt = stmts[n]; @@ -52,7 +52,7 @@ bool check_is_terminating_list(AstNodeArray stmts) { return false; } -bool check_has_break_list(AstNodeArray stmts, bool implicit) { +bool check_has_break_list(Array stmts, bool implicit) { for_array(i, stmts) { AstNode *stmt = stmts[i]; if (check_has_break(stmt, implicit)) { @@ -340,11 +340,11 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { return rhs->type; } -typedef enum MatchTypeKind { +enum MatchTypeKind { MatchType_Invalid, MatchType_Union, MatchType_Any, -} MatchTypeKind; +}; MatchTypeKind check_valid_type_match_type(Type *type) { type = type_deref(type); @@ -384,10 +384,10 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { -typedef struct TypeAndToken { +struct TypeAndToken { Type *type; Token token; -} TypeAndToken; +}; #define MAP_TYPE TypeAndToken #define MAP_PROC map_type_and_token_ diff --git a/src/checker.cpp b/src/checker.cpp index 6a9011df1..389740694 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1,27 +1,27 @@ #include "exact_value.cpp" #include "entity.cpp" -typedef enum ExprKind { +enum ExprKind { Expr_Expr, Expr_Stmt, -} ExprKind; +}; // Statements and Declarations -typedef enum StmtFlag { +enum StmtFlag { Stmt_BreakAllowed = 1<<0, Stmt_ContinueAllowed = 1<<1, Stmt_FallthroughAllowed = 1<<2, Stmt_CheckScopeDecls = 1<<5, -} StmtFlag; +}; -typedef struct BuiltinProc { +struct BuiltinProc { String name; isize arg_count; bool variadic; ExprKind kind; -} BuiltinProc; -typedef enum BuiltinProcId { +}; +enum BuiltinProcId { BuiltinProc_Invalid, BuiltinProc_len, @@ -71,7 +71,7 @@ typedef enum BuiltinProcId { BuiltinProc_transmute, BuiltinProc_Count, -} BuiltinProcId; +}; gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT(""), 0, false, Expr_Stmt}, @@ -125,7 +125,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { #include "types.cpp" -typedef enum AddressingMode { +enum AddressingMode { Addressing_Invalid, // invalid addressing mode Addressing_NoValue, // no value (void in C) Addressing_Value, // computed value (rvalue) @@ -139,14 +139,14 @@ typedef enum AddressingMode { // lhs: acts like a Variable // rhs: acts like OptionalOk Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check) -} AddressingMode; +}; // Operand is used as an intermediate value whilst checking // Operands store an addressing mode, the expression being evaluated, // its type and node, and other specific information for certain // addressing modes // Its zero-value is a valid "invalid operand" -typedef struct Operand { +struct Operand { AddressingMode mode; Type * type; ExactValue value; @@ -154,13 +154,13 @@ typedef struct Operand { BuiltinProcId builtin_id; isize overload_count; Entity ** overload_entities; -} Operand; +}; -typedef struct TypeAndValue { +struct TypeAndValue { AddressingMode mode; Type * type; ExactValue value; -} TypeAndValue; +}; bool is_operand_value(Operand o) { switch (o.mode) { @@ -178,13 +178,12 @@ bool is_operand_nil(Operand o) { } -typedef struct BlockLabel { +struct BlockLabel { String name; AstNode *label; // AstNode_Label; -} BlockLabel; +}; // DeclInfo is used to store information of certain declarations to allow for "any order" usage -typedef struct DeclInfo DeclInfo; struct DeclInfo { DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment Scope * scope; @@ -203,22 +202,22 @@ struct DeclInfo { // ProcedureInfo stores the information needed for checking a procedure -typedef struct ProcedureInfo { +struct ProcedureInfo { AstFile * file; Token token; DeclInfo * decl; Type * type; // Type_Procedure AstNode * body; // AstNode_BlockStmt u32 tags; -} ProcedureInfo; +}; // ExprInfo stores information used for "untyped" expressions -typedef struct ExprInfo { +struct ExprInfo { bool is_lhs; // Debug info AddressingMode mode; Type * type; // Type_Basic ExactValue value; -} ExprInfo; +}; ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue value) { ExprInfo ei = {is_lhs, mode, type, value}; @@ -232,7 +231,7 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue #define MAP_NAME MapEntity #include "map.cpp" -typedef struct Scope { +struct Scope { Scope * parent; Scope * prev, *next; Scope * first_child; @@ -248,7 +247,7 @@ typedef struct Scope { bool is_init; bool has_been_imported; // This is only applicable to file scopes AstFile * file; -} Scope; +}; gb_global Scope *universal_scope = NULL; @@ -280,19 +279,19 @@ gb_global Scope *universal_scope = NULL; #define MAP_NAME MapExprInfo #include "map.cpp" -typedef struct DelayedDecl { +struct DelayedDecl { Scope * parent; AstNode *decl; -} DelayedDecl; +}; -typedef struct CheckerFileNode { +struct CheckerFileNode { i32 id; Array wheres; Array whats; i32 score; // Higher the score, the better -} CheckerFileNode; +}; -typedef struct CheckerContext { +struct CheckerContext { Scope * file_scope; Scope * scope; DeclInfo * decl; @@ -301,10 +300,10 @@ typedef struct CheckerContext { String proc_name; Type * type_hint; DeclInfo * curr_proc_decl; -} CheckerContext; +}; // CheckerInfo stores all the symbol information for a type-checked program -typedef struct CheckerInfo { +struct CheckerInfo { MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value) MapEntity definitions; // Key: AstNode * | Identifier -> Entity MapEntity uses; // Key: AstNode * | Identifier -> Entity @@ -316,9 +315,9 @@ typedef struct CheckerInfo { MapAstFile files; // Key: String (full path) MapIsize type_info_map; // Key: Type * isize type_info_count; -} CheckerInfo; +}; -typedef struct Checker { +struct Checker { Parser * parser; CheckerInfo info; @@ -338,14 +337,14 @@ typedef struct Checker { Array proc_stack; bool done_preload; -} Checker; +}; -typedef struct DelayedEntity { +struct DelayedEntity { AstNode * ident; Entity * entity; DeclInfo * decl; -} DelayedEntity; +}; @@ -1281,7 +1280,7 @@ void init_preload(Checker *c) { bool check_arity_match(Checker *c, AstNodeValueDecl *d); -void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope); +void check_collect_entities(Checker *c, Array nodes, bool is_file_scope); void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, bool is_file_scope); bool check_is_entity_overloaded(Entity *e) { @@ -1455,7 +1454,7 @@ void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, bool } // NOTE(bill): If file_scopes == NULL, this will act like a local scope -void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) { +void check_collect_entities(Checker *c, Array nodes, bool is_file_scope) { // NOTE(bill): File scope and local scope are different kinds of scopes if (is_file_scope) { GB_ASSERT(c->context.scope->is_file); diff --git a/src/common.cpp b/src/common.cpp index 0aa37a001..c61f22a62 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -43,8 +43,6 @@ gbAllocator scratch_allocator(void) { return gb_scratch_allocator(&scratch_memory); } -typedef struct DynamicArenaBlock DynamicArenaBlock; -typedef struct DynamicArena DynamicArena; struct DynamicArenaBlock { DynamicArenaBlock *prev; diff --git a/src/entity.cpp b/src/entity.cpp index 042f6f39f..d8159d449 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -1,7 +1,7 @@ -typedef struct Scope Scope; -typedef struct Checker Checker; -typedef struct Type Type; -typedef struct DeclInfo DeclInfo; +struct Scope; +struct Checker; +struct Type; +struct DeclInfo; // typedef enum BuiltinProcId BuiltinProcId; @@ -19,12 +19,12 @@ typedef struct DeclInfo DeclInfo; ENTITY_KIND(Nil) \ ENTITY_KIND(Label) -typedef enum EntityKind { +enum EntityKind { #define ENTITY_KIND(k) GB_JOIN2(Entity_, k), ENTITY_KINDS #undef ENTITY_KIND Entity_Count, -} EntityKind; +}; String const entity_strings[] = { #define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1}, @@ -32,7 +32,7 @@ String const entity_strings[] = { #undef ENTITY_KIND }; -typedef enum EntityFlag { +enum EntityFlag { EntityFlag_Visited = 1<<0, EntityFlag_Used = 1<<1, EntityFlag_Using = 1<<2, @@ -45,24 +45,23 @@ typedef enum EntityFlag { EntityFlag_Value = 1<<9, EntityFlag_Sret = 1<<10, EntityFlag_BitFieldValue = 1<<11, -} EntityFlag; +}; // Zero value means the overloading process is not yet done -typedef enum OverloadKind { +enum OverloadKind { Overload_Unknown, Overload_No, Overload_Yes, -} OverloadKind; +}; -typedef enum EntityAliasKind { +enum EntityAliasKind { EntityAlias_Invalid, EntityAlias_Type, EntityAlias_Entity, -} EntityAliasKind; +}; // An Entity is a named "thing" in the language -typedef struct Entity Entity; struct Entity { EntityKind kind; u64 id; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 2bdf3fdf5..62ab326ea 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -3,13 +3,13 @@ // TODO(bill): Big numbers // IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!! -typedef struct AstNode AstNode; +struct AstNode; -typedef struct Complex128 { +struct Complex128 { f64 real, imag; -} Complex128; +}; -typedef enum ExactValueKind { +enum ExactValueKind { ExactValue_Invalid, ExactValue_Bool, @@ -21,9 +21,9 @@ typedef enum ExactValueKind { ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Count, -} ExactValueKind; +}; -typedef struct ExactValue { +struct ExactValue { ExactValueKind kind; union { bool value_bool; @@ -34,7 +34,7 @@ typedef struct ExactValue { Complex128 value_complex; AstNode * value_compound; }; -} ExactValue; +}; gb_global ExactValue const empty_exact_value = {}; diff --git a/src/ir.cpp b/src/ir.cpp index c9afb05ba..4cd1734aa 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1,9 +1,7 @@ -typedef struct irProcedure irProcedure; -typedef struct irBlock irBlock; -typedef struct irValue irValue; -typedef struct irDebugInfo irDebugInfo; - -typedef Array irValueArray; +struct irProcedure; +struct irBlock; +struct irValue; +struct irDebugInfo; #define MAP_TYPE irValue * #define MAP_PROC map_ir_value_ @@ -16,7 +14,7 @@ typedef Array irValueArray; #include "map.cpp" -typedef struct irModule { +struct irModule { CheckerInfo * info; gbArena arena; gbArena tmp_arena; @@ -42,20 +40,20 @@ typedef struct irModule { Entity * entry_point_entity; Array procs; // NOTE(bill): All procedures with bodies - irValueArray procs_to_generate; // NOTE(bill): Procedures to generate + Array procs_to_generate; // NOTE(bill): Procedures to generate Array foreign_library_paths; // Only the ones that were used -} irModule; +}; // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory) -typedef struct irDomNode { +struct irDomNode { irBlock * idom; // Parent (Immediate Dominator) Array children; i32 pre, post; // Ordering in tree -} irDomNode; +}; -typedef struct irBlock { +struct irBlock { i32 index; String label; irProcedure *parent; @@ -65,14 +63,13 @@ typedef struct irBlock { irDomNode dom; i32 gaps; - irValueArray instrs; - irValueArray locals; + Array instrs; + Array locals; Array preds; Array succs; -} irBlock; +}; -typedef struct irTargetList irTargetList; struct irTargetList { irTargetList *prev; irBlock * break_; @@ -80,17 +77,17 @@ struct irTargetList { irBlock * fallthrough_; }; -typedef enum irDeferExitKind { +enum irDeferExitKind { irDeferExit_Default, irDeferExit_Return, irDeferExit_Branch, -} irDeferExitKind; -typedef enum irDeferKind { +}; +enum irDeferKind { irDefer_Node, irDefer_Instr, -} irDeferKind; +}; -typedef struct irDefer { +struct irDefer { irDeferKind kind; isize scope_index; irBlock * block; @@ -99,14 +96,14 @@ typedef struct irDefer { // NOTE(bill): `instr` will be copied every time to create a new one irValue *instr; }; -} irDefer; +}; -typedef struct irBranchBlocks { +struct irBranchBlocks { AstNode *label; irBlock *break_; irBlock *continue_; -} irBranchBlocks; +}; struct irProcedure { @@ -122,7 +119,7 @@ struct irProcedure { u64 tags; irValue * return_ptr; - irValueArray params; + Array params; Array defer_stmts; Array blocks; i32 scope_index; @@ -130,7 +127,7 @@ struct irProcedure { irBlock * entry_block; irBlock * curr_block; irTargetList * target_list; - irValueArray referrers; + Array referrers; Array branch_blocks; @@ -153,7 +150,7 @@ struct irProcedure { Entity * entity; \ Type * type; \ bool zero_initialized; \ - irValueArray referrers; \ + Array referrers; \ i64 alignment; \ }) \ IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \ @@ -205,7 +202,7 @@ struct irProcedure { irValue *true_value; \ irValue *false_value; \ }) \ - IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \ + IR_INSTR_KIND(Phi, struct { Array edges; Type *type; }) \ IR_INSTR_KIND(Unreachable, i32) \ IR_INSTR_KIND(UnaryOp, struct { \ Type * type; \ @@ -261,12 +258,12 @@ struct irProcedure { IR_CONV_KIND(inttoptr) \ IR_CONV_KIND(bitcast) -typedef enum irInstrKind { +enum irInstrKind { irInstr_Invalid, #define IR_INSTR_KIND(x, ...) GB_JOIN2(irInstr_, x), IR_INSTR_KINDS #undef IR_INSTR_KIND -} irInstrKind; +}; String const ir_instr_strings[] = { {cast(u8 *)"Invalid", gb_size_of("Invalid")-1}, @@ -275,12 +272,12 @@ String const ir_instr_strings[] = { #undef IR_INSTR_KIND }; -typedef enum irConvKind { +enum irConvKind { irConv_Invalid, #define IR_CONV_KIND(x) GB_JOIN2(irConv_, x), IR_CONV_KINDS #undef IR_CONV_KIND -} irConvKind; +}; String const ir_conv_strings[] = { {cast(u8 *)"Invalid", gb_size_of("Invalid")-1}, @@ -293,7 +290,6 @@ String const ir_conv_strings[] = { IR_INSTR_KINDS #undef IR_INSTR_KIND -typedef struct irInstr irInstr; struct irInstr { irInstrKind kind; @@ -308,7 +304,7 @@ struct irInstr { }; -typedef enum irValueKind { +enum irValueKind { irValue_Invalid, irValue_Constant, @@ -323,58 +319,58 @@ typedef enum irValueKind { irValue_Instr, irValue_Count, -} irValueKind; +}; -typedef struct irValueConstant { +struct irValueConstant { Type * type; ExactValue value; -} irValueConstant; +}; -typedef struct irValueConstantSlice { +struct irValueConstantSlice { Type * type; irValue *backing_array; i64 count; -} irValueConstantSlice; +}; -typedef struct irValueNil { +struct irValueNil { Type *type; -} irValueNil; +}; -typedef struct irValueTypeName { +struct irValueTypeName { Type * type; String name; -} irValueTypeName; +}; -typedef struct irValueGlobal { +struct irValueGlobal { String name; Entity * entity; Type * type; irValue * value; - irValueArray referrers; + Array referrers; bool is_constant; bool is_private; bool is_thread_local; bool is_foreign; bool is_unnamed_addr; -} irValueGlobal; +}; -typedef enum irParamPasskind { +enum irParamPasskind { irParamPass_Value, // Pass by value irParamPass_Pointer, // Pass as a pointer rather than by value irParamPass_Integer, // Pass as an integer of the same size -} irParamPasskind; +}; -typedef struct irValueParam { +struct irValueParam { irParamPasskind kind; irProcedure * parent; Entity * entity; Type * type; Type * original_type; - irValueArray referrers; -} irValueParam; + Array referrers; +}; -typedef struct irValue { +struct irValue { irValueKind kind; i32 index; bool index_set; @@ -389,7 +385,7 @@ typedef struct irValue { irBlock Block; irInstr Instr; }; -} irValue; +}; gb_global irValue *v_zero = NULL; gb_global irValue *v_one = NULL; @@ -400,14 +396,14 @@ gb_global irValue *v_false = NULL; gb_global irValue *v_true = NULL; gb_global irValue *v_raw_nil = NULL; -typedef enum irAddrKind { +enum irAddrKind { irAddr_Default, // irAddr_Vector, irAddr_Map, irAddr_BitField, -} irAddrKind; +}; -typedef struct irAddr { +struct irAddr { irAddrKind kind; irValue * addr; union { @@ -423,7 +419,7 @@ typedef struct irAddr { // union { // struct { irValue *index; } Vector; // }; -} irAddr; +}; irAddr ir_addr(irValue *addr) { irAddr v = {irAddr_Default, addr}; @@ -444,7 +440,7 @@ irAddr ir_addr_bit_field(irValue *addr, isize bit_field_value_index) { return v; } -typedef enum irDebugEncoding { +enum irDebugEncoding { irDebugBasicEncoding_Invalid = 0, irDebugBasicEncoding_address = 1, @@ -464,9 +460,9 @@ typedef enum irDebugEncoding { irDebugBasicEncoding_structure_type = 19, irDebugBasicEncoding_union_type = 23, -} irDebugEncoding; +}; -typedef enum irDebugInfoKind { +enum irDebugInfoKind { irDebugInfo_Invalid, irDebugInfo_CompileUnit, @@ -485,9 +481,8 @@ typedef enum irDebugInfoKind { irDebugInfo_Count, -} irDebugInfoKind; +}; -typedef struct irDebugInfo irDebugInfo; struct irDebugInfo { irDebugInfoKind kind; i32 id; @@ -569,14 +564,13 @@ struct irDebugInfo { }; - -typedef struct irGen { +struct irGen { irModule module; gbFile output_file; bool opt_called; String output_base; String output_name; -} irGen; +}; @@ -698,7 +692,7 @@ void ir_set_instr_parent(irValue *instr, irBlock *parent) { } } -irValueArray *ir_value_referrers(irValue *v) { +Array *ir_value_referrers(irValue *v) { switch (v->kind) { case irValue_Global: return &v->Global.referrers; @@ -969,7 +963,7 @@ irValue *ir_instr_if(irProcedure *p, irValue *cond, irBlock *true_block, irBlock } -irValue *ir_instr_phi(irProcedure *p, irValueArray edges, Type *type) { +irValue *ir_instr_phi(irProcedure *p, Array edges, Type *type) { irValue *v = ir_alloc_instr(p, irInstr_Phi); irInstr *i = &v->Instr; i->Phi.edges = edges; @@ -3387,7 +3381,7 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) { return ir_build_expr(proc, be->right); } - irValueArray edges = {}; + Array edges = {}; array_init(&edges, proc->module->allocator, done->preds.count+1); for_array(i, done->preds) { array_add(&edges, short_circuit); @@ -3613,7 +3607,7 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) { return *value; } -void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts); +void ir_build_stmt_list(irProcedure *proc, Array stmts); bool is_double_pointer(Type *t) { @@ -3712,7 +3706,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case_ast_node(te, TernaryExpr, expr); ir_emit_comment(proc, str_lit("TernaryExpr")); - irValueArray edges = {}; + Array edges = {}; array_init(&edges, proc->module->allocator, 2); GB_ASSERT(te->y != NULL); @@ -3752,7 +3746,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ir_build_stmt(proc, ie->init); } - irValueArray edges = {}; + Array edges = {}; array_init(&edges, proc->module->allocator, 2); GB_ASSERT(ie->else_expr != NULL); @@ -5450,7 +5444,7 @@ irValue *ir_build_cond(irProcedure *proc, AstNode *cond, irBlock *true_block, ir -void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts) { +void ir_build_stmt_list(irProcedure *proc, Array stmts) { for_array(i, stmts) { ir_build_stmt(proc, stmts[i]); } @@ -5787,7 +5781,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } } else { // Tuple(s) Array lvals = {}; - irValueArray inits = {}; + Array inits = {}; array_init(&lvals, m->tmp_allocator, vd->names.count); array_init(&inits, m->tmp_allocator, vd->names.count); @@ -5943,7 +5937,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *init = ir_build_expr(proc, rhs); ir_addr_store(proc, lvals[0], init); } else { - irValueArray inits; + Array inits; array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { @@ -5956,7 +5950,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } } } else { - irValueArray inits; + Array inits; array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { @@ -6029,7 +6023,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } else { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); - irValueArray results; + Array results; array_init(&results, proc->module->tmp_allocator, return_count); for_array(res_index, rs->results) { @@ -6338,7 +6332,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ast_node(body, BlockStmt, ms->body); - AstNodeArray default_stmts = {}; + Array default_stmts = {}; irBlock *default_fall = NULL; irBlock *default_block = NULL; @@ -7116,10 +7110,10 @@ void ir_gen_tree(irGen *s) { } } - typedef struct irGlobalVariable { + struct irGlobalVariable { irValue *var, *init; DeclInfo *decl; - } irGlobalVariable; + }; Array global_variables; array_init(&global_variables, m->tmp_allocator, global_variable_max_count); diff --git a/src/ir_opt.cpp b/src/ir_opt.cpp index 856d8aaf0..c2c952b87 100644 --- a/src/ir_opt.cpp +++ b/src/ir_opt.cpp @@ -1,6 +1,6 @@ // Optimizations for the IR code -void ir_opt_add_operands(irValueArray *ops, irInstr *i) { +void ir_opt_add_operands(Array *ops, irInstr *i) { switch (i->kind) { case irInstr_Comment: break; @@ -126,8 +126,8 @@ bool ir_opt_block_has_phi(irBlock *b) { -irValueArray ir_get_block_phi_nodes(irBlock *b) { - irValueArray phis = {0}; +Array ir_get_block_phi_nodes(irBlock *b) { + Array phis = {0}; for_array(i, b->instrs) { irInstr *instr = &b->instrs[i]->Instr; if (instr->kind != irInstr_Phi) { @@ -140,7 +140,7 @@ irValueArray ir_get_block_phi_nodes(irBlock *b) { } void ir_remove_pred(irBlock *b, irBlock *p) { - irValueArray phis = ir_get_block_phi_nodes(b); + Array phis = ir_get_block_phi_nodes(b); isize i = 0; for_array(j, b->preds) { irBlock *pred = b->preds[j]; @@ -273,7 +273,7 @@ void ir_opt_blocks(irProcedure *proc) { void ir_opt_build_referrers(irProcedure *proc) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); - irValueArray ops = {0}; // NOTE(bill): Act as a buffer + Array ops = {0}; // NOTE(bill): Act as a buffer array_init(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena for_array(i, proc->blocks) { irBlock *b = proc->blocks[i]; @@ -286,7 +286,7 @@ void ir_opt_build_referrers(irProcedure *proc) { if (op == NULL) { continue; } - irValueArray *refs = ir_value_referrers(op); + Array *refs = ir_value_referrers(op); if (refs != NULL) { array_add(refs, instr); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 81809fa0a..823960352 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1,8 +1,8 @@ -typedef struct irFileBuffer { +struct irFileBuffer { gbVirtualMemory vm; isize offset; gbFile * output; -} irFileBuffer; +}; void ir_file_buffer_init(irFileBuffer *f, gbFile *output) { isize size = 8*gb_virtual_memory_page_size(NULL); diff --git a/src/parser.cpp b/src/parser.cpp index 2fc9f124d..120bb63cc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,8 +1,8 @@ -typedef struct AstNode AstNode; -typedef struct Scope Scope; -typedef struct DeclInfo DeclInfo; +struct AstNode; +struct Scope; +struct DeclInfo; -typedef enum ParseFileError { +enum ParseFileError { ParseFile_None, ParseFile_WrongExtension, @@ -13,11 +13,10 @@ typedef enum ParseFileError { ParseFile_InvalidToken, ParseFile_Count, -} ParseFileError; +}; -typedef Array AstNodeArray; -typedef struct AstFile { +struct AstFile { i32 id; gbArena arena; Tokenizer tokenizer; @@ -32,8 +31,8 @@ typedef struct AstFile { isize expr_level; bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases - AstNodeArray decls; - bool is_global_scope; + Array decls; + bool is_global_scope; AstNode * curr_proc; isize scope_level; @@ -44,15 +43,15 @@ typedef struct AstFile { #define PARSER_MAX_FIX_COUNT 6 isize fix_count; TokenPos fix_prev_pos; -} AstFile; +}; -typedef struct ImportedFile { +struct ImportedFile { String path; String rel_path; TokenPos pos; // #import -} ImportedFile; +}; -typedef struct Parser { +struct Parser { String init_fullpath; Array files; Array imports; @@ -60,9 +59,9 @@ typedef struct Parser { isize total_token_count; isize total_line_count; gbMutex mutex; -} Parser; +}; -typedef enum ProcTag { +enum ProcTag { ProcTag_bounds_check = 1<<0, ProcTag_no_bounds_check = 1<<1, @@ -75,47 +74,47 @@ typedef enum ProcTag { ProcTag_no_inline = 1<<14, // ProcTag_dll_import = 1<<15, // ProcTag_dll_export = 1<<16, -} ProcTag; +}; -typedef enum ProcCallingConvention { +enum ProcCallingConvention { ProcCC_Odin = 0, ProcCC_C = 1, ProcCC_Std = 2, ProcCC_Fast = 3, ProcCC_Invalid, -} ProcCallingConvention; +}; -typedef enum VarDeclFlag { +enum VarDeclFlag { VarDeclFlag_using = 1<<0, VarDeclFlag_immutable = 1<<1, VarDeclFlag_thread_local = 1<<2, -} VarDeclFlag; +}; -typedef enum StmtStateFlag { +enum StmtStateFlag { StmtStateFlag_bounds_check = 1<<0, StmtStateFlag_no_bounds_check = 1<<1, -} StmtStateFlag; +}; -typedef enum FieldFlag { +enum FieldFlag { FieldFlag_ellipsis = 1<<0, FieldFlag_using = 1<<1, FieldFlag_no_alias = 1<<2, FieldFlag_immutable = 1<<3, FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_immutable, -} FieldListTag; +}; -typedef enum StmtAllowFlag { +enum StmtAllowFlag { StmtAllowFlag_None = 0, StmtAllowFlag_In = 1<<0, StmtAllowFlag_Label = 1<<1, -} StmtAllowFlag; +}; -AstNodeArray make_ast_node_array(AstFile *f) { - AstNodeArray a; +Array make_ast_node_array(AstFile *f) { + Array a; // array_init(&a, gb_arena_allocator(&f->arena)); array_init(&a, heap_allocator()); return a; @@ -147,7 +146,7 @@ AstNodeArray make_ast_node_array(AstFile *f) { }) \ AST_NODE_KIND(CompoundLit, "compound literal", struct { \ AstNode *type; \ - AstNodeArray elems; \ + Array elems; \ Token open, close; \ }) \ AST_NODE_KIND(Alias, "alias", struct { \ @@ -174,7 +173,7 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ }) \ AST_NODE_KIND(CallExpr, "call expression", struct { \ AstNode * proc; \ - AstNodeArray args; \ + Array args; \ Token open; \ Token close; \ Token ellipsis; \ @@ -182,7 +181,7 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ AST_NODE_KIND(MacroCallExpr, "macro call expression", struct { \ AstNode * macro; \ Token bang; \ - AstNodeArray args; \ + Array args; \ Token open; \ Token close; \ }) \ @@ -201,7 +200,7 @@ AST_NODE_KIND(_StmtBegin, "", i32) \ }) \ AST_NODE_KIND(AssignStmt, "assign statement", struct { \ Token op; \ - AstNodeArray lhs, rhs; \ + Array lhs, rhs; \ }) \ AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \ Token op; \ @@ -209,7 +208,7 @@ AST_NODE_KIND(_StmtBegin, "", i32) \ }) \ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AST_NODE_KIND(BlockStmt, "block statement", struct { \ - AstNodeArray stmts; \ + Array stmts; \ Token open, close; \ }) \ AST_NODE_KIND(IfStmt, "if statement", struct { \ @@ -227,7 +226,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ }) \ AST_NODE_KIND(ReturnStmt, "return statement", struct { \ Token token; \ - AstNodeArray results; \ + Array results; \ }) \ AST_NODE_KIND(ForStmt, "for statement", struct { \ Token token; \ @@ -248,8 +247,8 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ }) \ AST_NODE_KIND(CaseClause, "case clause", struct { \ Token token; \ - AstNodeArray list; \ - AstNodeArray stmts; \ + Array list; \ + Array stmts; \ }) \ AST_NODE_KIND(MatchStmt, "match statement", struct { \ Token token; \ @@ -268,7 +267,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \ AST_NODE_KIND(UsingStmt, "using statement", struct { \ Token token; \ - AstNodeArray list; \ + Array list; \ }) \ AST_NODE_KIND(AsmOperand, "assembly operand", struct { \ Token string; \ @@ -300,9 +299,9 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ AST_NODE_KIND(BadDecl, "bad declaration", struct { Token begin, end; }) \ AST_NODE_KIND(ValueDecl, "value declaration", struct { \ bool is_var; \ - AstNodeArray names; \ + Array names; \ AstNode * type; \ - AstNodeArray values; \ + Array values; \ u32 flags; \ }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ @@ -327,13 +326,13 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ }) \ AST_NODE_KIND(_DeclEnd, "", i32) \ AST_NODE_KIND(Field, "field", struct { \ - AstNodeArray names; \ + Array names; \ AstNode * type; \ u32 flags; \ }) \ AST_NODE_KIND(FieldList, "field list", struct { \ Token token; \ - AstNodeArray list; \ + Array list; \ }) \ AST_NODE_KIND(UnionField, "union field", struct { \ AstNode *name; \ @@ -375,7 +374,7 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ }) \ AST_NODE_KIND(StructType, "struct type", struct { \ Token token; \ - AstNodeArray fields; \ + Array fields; \ isize field_count; \ bool is_packed; \ bool is_ordered; \ @@ -383,23 +382,23 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ }) \ AST_NODE_KIND(UnionType, "union type", struct { \ Token token; \ - AstNodeArray fields; \ + Array fields; \ isize field_count; \ - AstNodeArray variants; \ + Array variants; \ }) \ AST_NODE_KIND(RawUnionType, "raw union type", struct { \ Token token; \ - AstNodeArray fields; \ + Array fields; \ isize field_count; \ }) \ AST_NODE_KIND(EnumType, "enum type", struct { \ Token token; \ AstNode *base_type; \ - AstNodeArray fields; /* FieldValue */ \ + Array fields; /* FieldValue */ \ }) \ AST_NODE_KIND(BitFieldType, "bit field type", struct { \ Token token; \ - AstNodeArray fields; /* FieldValue with : */ \ + Array fields; /* FieldValue with : */ \ AstNode *align; \ }) \ AST_NODE_KIND(MapType, "map type", struct { \ @@ -410,13 +409,13 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ }) \ AST_NODE_KIND(_TypeEnd, "", i32) -typedef enum AstNodeKind { +enum AstNodeKind { AstNode_Invalid, #define AST_NODE_KIND(_kind_name_, ...) GB_JOIN2(AstNode_, _kind_name_), AST_NODE_KINDS #undef AST_NODE_KIND AstNode_Count, -} AstNodeKind; +}; String const ast_node_strings[] = { {cast(u8 *)"invalid node", gb_size_of("invalid node")}, @@ -429,7 +428,7 @@ String const ast_node_strings[] = { AST_NODE_KINDS #undef AST_NODE_KIND -typedef struct AstNode { +struct AstNode { AstNodeKind kind; u32 stmt_state_flags; union { @@ -437,7 +436,7 @@ typedef struct AstNode { AST_NODE_KINDS #undef AST_NODE_KIND }; -} AstNode; +}; #define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_)) @@ -560,8 +559,8 @@ Token ast_node_token(AstNode *node) { } AstNode *clone_ast_node(gbAllocator a, AstNode *node); -AstNodeArray clone_ast_node_array(gbAllocator a, AstNodeArray array) { - AstNodeArray result = {}; +Array clone_ast_node_array(gbAllocator a, Array array) { + Array result = {}; if (array.count > 0) { array_init_count(&result, a, array.count); for_array(i, array) { @@ -933,7 +932,7 @@ AstNode *ast_paren_expr(AstFile *f, AstNode *expr, Token open, Token close) { return result; } -AstNode *ast_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) { +AstNode *ast_call_expr(AstFile *f, AstNode *proc, Array args, Token open, Token close, Token ellipsis) { AstNode *result = make_ast_node(f, AstNode_CallExpr); result->CallExpr.proc = proc; result->CallExpr.args = args; @@ -943,7 +942,7 @@ AstNode *ast_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, return result; } -AstNode *ast_macro_call_expr(AstFile *f, AstNode *macro, Token bang, AstNodeArray args, Token open, Token close) { +AstNode *ast_macro_call_expr(AstFile *f, AstNode *macro, Token bang, Array args, Token open, Token close) { AstNode *result = make_ast_node(f, AstNode_MacroCallExpr); result->MacroCallExpr.macro = macro; result->MacroCallExpr.bang = bang; @@ -1048,7 +1047,7 @@ AstNode *ast_field_value(AstFile *f, AstNode *field, AstNode *value, Token eq) { return result; } -AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) { +AstNode *ast_compound_lit(AstFile *f, AstNode *type, Array elems, Token open, Token close) { AstNode *result = make_ast_node(f, AstNode_CompoundLit); result->CompoundLit.type = type; result->CompoundLit.elems = elems; @@ -1101,7 +1100,7 @@ AstNode *ast_expr_stmt(AstFile *f, AstNode *expr) { return result; } -AstNode *ast_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rhs) { +AstNode *ast_assign_stmt(AstFile *f, Token op, Array lhs, Array rhs) { AstNode *result = make_ast_node(f, AstNode_AssignStmt); result->AssignStmt.op = op; result->AssignStmt.lhs = lhs; @@ -1119,7 +1118,7 @@ AstNode *ast_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) { -AstNode *ast_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) { +AstNode *ast_block_stmt(AstFile *f, Array stmts, Token open, Token close) { AstNode *result = make_ast_node(f, AstNode_BlockStmt); result->BlockStmt.stmts = stmts; result->BlockStmt.open = open; @@ -1147,7 +1146,7 @@ AstNode *ast_when_stmt(AstFile *f, Token token, AstNode *cond, AstNode *body, As } -AstNode *ast_return_stmt(AstFile *f, Token token, AstNodeArray results) { +AstNode *ast_return_stmt(AstFile *f, Token token, Array results) { AstNode *result = make_ast_node(f, AstNode_ReturnStmt); result->ReturnStmt.token = token; result->ReturnStmt.results = results; @@ -1194,7 +1193,7 @@ AstNode *ast_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *bod return result; } -AstNode *ast_case_clause(AstFile *f, Token token, AstNodeArray list, AstNodeArray stmts) { +AstNode *ast_case_clause(AstFile *f, Token token, Array list, Array stmts) { AstNode *result = make_ast_node(f, AstNode_CaseClause); result->CaseClause.token = token; result->CaseClause.list = list; @@ -1217,7 +1216,7 @@ AstNode *ast_branch_stmt(AstFile *f, Token token, AstNode *label) { return result; } -AstNode *ast_using_stmt(AstFile *f, Token token, AstNodeArray list) { +AstNode *ast_using_stmt(AstFile *f, Token token, Array list) { AstNode *result = make_ast_node(f, AstNode_UsingStmt); result->UsingStmt.token = token; result->UsingStmt.list = list; @@ -1277,7 +1276,7 @@ AstNode *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) { +AstNode *ast_field(AstFile *f, Array names, AstNode *type, u32 flags) { AstNode *result = make_ast_node(f, AstNode_Field); result->Field.names = names; result->Field.type = type; @@ -1285,7 +1284,7 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) { return result; } -AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) { +AstNode *ast_field_list(AstFile *f, Token token, Array list) { AstNode *result = make_ast_node(f, AstNode_FieldList); result->FieldList.token = token; result->FieldList.list = list; @@ -1354,7 +1353,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem) return result; } -AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, +AstNode *ast_struct_type(AstFile *f, Token token, Array fields, isize field_count, bool is_packed, bool is_ordered, AstNode *align) { AstNode *result = make_ast_node(f, AstNode_StructType); result->StructType.token = token; @@ -1367,7 +1366,7 @@ AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize fie } -AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, AstNodeArray variants) { +AstNode *ast_union_type(AstFile *f, Token token, Array fields, isize field_count, Array variants) { AstNode *result = make_ast_node(f, AstNode_UnionType); result->UnionType.token = token; result->UnionType.fields = fields; @@ -1376,7 +1375,7 @@ AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize fiel return result; } -AstNode *ast_raw_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count) { +AstNode *ast_raw_union_type(AstFile *f, Token token, Array fields, isize field_count) { AstNode *result = make_ast_node(f, AstNode_RawUnionType); result->RawUnionType.token = token; result->RawUnionType.fields = fields; @@ -1385,7 +1384,7 @@ AstNode *ast_raw_union_type(AstFile *f, Token token, AstNodeArray fields, isize } -AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArray fields) { +AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, Array fields) { AstNode *result = make_ast_node(f, AstNode_EnumType); result->EnumType.token = token; result->EnumType.base_type = base_type; @@ -1393,7 +1392,7 @@ AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArray return result; } -AstNode *ast_bit_field_type(AstFile *f, Token token, AstNodeArray fields, AstNode *align) { +AstNode *ast_bit_field_type(AstFile *f, Token token, Array fields, AstNode *align) { AstNode *result = make_ast_node(f, AstNode_BitFieldType); result->BitFieldType.token = token; result->BitFieldType.fields = fields; @@ -1411,7 +1410,7 @@ AstNode *ast_map_type(AstFile *f, Token token, AstNode *count, AstNode *key, Ast } -AstNode *ast_value_decl(AstFile *f, bool is_var, AstNodeArray names, AstNode *type, AstNodeArray values) { +AstNode *ast_value_decl(AstFile *f, bool is_var, Array names, AstNode *type, Array values) { AstNode *result = make_ast_node(f, AstNode_ValueDecl); result->ValueDecl.is_var = is_var; result->ValueDecl.names = names; @@ -1693,7 +1692,7 @@ void expect_semicolon(AstFile *f, AstNode *s) { AstNode * parse_expr(AstFile *f, bool lhs); AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *foreign_name, String *link_name); -AstNodeArray parse_stmt_list(AstFile *f); +Array parse_stmt_list(AstFile *f); AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); @@ -1731,8 +1730,8 @@ AstNode *unparen_expr(AstNode *node) { AstNode *parse_value(AstFile *f); -AstNodeArray parse_element_list(AstFile *f) { - AstNodeArray elems = make_ast_node_array(f); +Array parse_element_list(AstFile *f) { + Array elems = make_ast_node_array(f); while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { @@ -1754,7 +1753,7 @@ AstNodeArray parse_element_list(AstFile *f) { } AstNode *parse_literal_value(AstFile *f, AstNode *type) { - AstNodeArray elems = {}; + Array elems = {}; Token open = expect_token(f, Token_OpenBrace); f->expr_level++; if (f->curr_token.kind != Token_CloseBrace) { @@ -1946,8 +1945,8 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str } -AstNodeArray parse_lhs_expr_list(AstFile *f); -AstNodeArray parse_rhs_expr_list(AstFile *f); +Array parse_lhs_expr_list(AstFile *f); +Array parse_rhs_expr_list(AstFile *f); AstNode * parse_simple_stmt (AstFile *f, StmtAllowFlag flags); AstNode * parse_type (AstFile *f); @@ -2109,7 +2108,7 @@ bool is_literal_type(AstNode *node) { } AstNode *parse_call_expr(AstFile *f, AstNode *operand) { - AstNodeArray args = make_ast_node_array(f); + Array args = make_ast_node_array(f); Token open_paren, close_paren; Token ellipsis = {}; @@ -2144,7 +2143,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) { - AstNodeArray args = make_ast_node_array(f); + Array args = make_ast_node_array(f); Token bang, open_paren, close_paren; bang = expect_token(f, Token_Not); @@ -2411,8 +2410,8 @@ AstNode *parse_expr(AstFile *f, bool lhs) { } -AstNodeArray parse_expr_list(AstFile *f, bool lhs) { - AstNodeArray list = make_ast_node_array(f); +Array parse_expr_list(AstFile *f, bool lhs) { + Array list = make_ast_node_array(f); for (;;) { AstNode *e = parse_expr(f, lhs); array_add(&list, e); @@ -2426,16 +2425,16 @@ AstNodeArray parse_expr_list(AstFile *f, bool lhs) { return list; } -AstNodeArray parse_lhs_expr_list(AstFile *f) { +Array parse_lhs_expr_list(AstFile *f) { return parse_expr_list(f, true); } -AstNodeArray parse_rhs_expr_list(AstFile *f) { +Array parse_rhs_expr_list(AstFile *f) { return parse_expr_list(f, false); } -AstNodeArray parse_ident_list(AstFile *f) { - AstNodeArray list = make_ast_node_array(f); +Array parse_ident_list(AstFile *f) { + Array list = make_ast_node_array(f); do { array_add(&list, parse_ident(f)); @@ -2470,9 +2469,9 @@ AstNode *parse_type(AstFile *f) { } -AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { +AstNode *parse_value_decl(AstFile *f, Array lhs) { AstNode *type = NULL; - AstNodeArray values = {}; + Array values = {}; bool is_mutable = true; if (allow_token(f, Token_Colon)) { @@ -2516,7 +2515,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { values = make_ast_node_array(f); } - AstNodeArray specs = {}; + Array specs = {}; array_init(&specs, heap_allocator(), 1); return ast_value_decl(f, is_mutable, lhs, type, values); } @@ -2524,7 +2523,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { - AstNodeArray lhs = parse_lhs_expr_list(f); + Array lhs = parse_lhs_expr_list(f); Token token = f->curr_token; switch (token.kind) { case Token_Eq: @@ -2548,7 +2547,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { return ast_bad_stmt(f, f->curr_token, f->curr_token); } next_token(f); - AstNodeArray rhs = parse_rhs_expr_list(f); + Array rhs = parse_rhs_expr_list(f); if (rhs.count == 0) { syntax_error(token, "No right-hand side in assignment statement."); return ast_bad_stmt(f, token, f->curr_token); @@ -2564,7 +2563,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { AstNode *expr = parse_expr(f, false); f->allow_range = prev_allow_range; - AstNodeArray rhs = {}; + Array rhs = {}; array_init_count(&rhs, heap_allocator(), 1); rhs[0] = expr; @@ -2638,8 +2637,8 @@ AstNode *parse_results(AstFile *f) { if (f->curr_token.kind != Token_OpenParen) { Token begin_token = f->curr_token; - AstNodeArray empty_names = {}; - AstNodeArray list = make_ast_node_array(f); + Array empty_names = {}; + Array list = make_ast_node_array(f); AstNode *type = parse_type(f); array_add(&list, ast_field(f, empty_names, type, 0)); return ast_field_list(f, begin_token, list); @@ -2698,13 +2697,13 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) { } -typedef enum FieldPrefixKind { +enum FieldPrefixKind { FieldPrefix_Invalid, FieldPrefix_Using, FieldPrefix_Immutable, FieldPrefix_NoAlias, -} FieldPrefixKind; +}; FieldPrefixKind is_token_field_prefix(AstFile *f) { switch (f->curr_token.kind) { @@ -2781,13 +2780,13 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se return set_flags; } -typedef struct AstNodeAndFlags { +struct AstNodeAndFlags { AstNode *node; u32 flags; -} AstNodeAndFlags; +}; -AstNodeArray convert_to_ident_list(AstFile *f, Array list, bool ignore_flags) { - AstNodeArray idents = {}; +Array convert_to_ident_list(AstFile *f, Array list, bool ignore_flags) { + Array idents = {}; array_init(&idents, heap_allocator(), list.count); // Convert to ident list for_array(i, list) { @@ -2831,7 +2830,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok TokenKind separator = Token_Comma; Token start_token = f->curr_token; - AstNodeArray params = make_ast_node_array(f); + Array params = make_ast_node_array(f); Array list = {}; array_init(&list, heap_allocator()); // LEAK(bill): isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; @@ -2850,7 +2849,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok } if (f->curr_token.kind == Token_Colon) { - AstNodeArray names = convert_to_ident_list(f, list, true); // Copy for semantic reasons + Array names = convert_to_ident_list(f, list, true); // Copy for semantic reasons if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); } @@ -2871,7 +2870,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok while (f->curr_token.kind != follow && f->curr_token.kind != Token_EOF) { u32 set_flags = parse_field_prefixes(f); - AstNodeArray names = parse_ident_list(f); + Array names = parse_ident_list(f); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); break; @@ -2894,7 +2893,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok } for_array(i, list) { - AstNodeArray names = {}; + Array names = {}; AstNode *type = list[i].node; Token token = blank_token; @@ -3052,7 +3051,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct")); Token close = expect_token(f, Token_CloseBrace); - AstNodeArray decls = {}; + Array decls = {}; if (fields != NULL) { GB_ASSERT(fields->kind == AstNode_FieldList); decls = fields->FieldList.list; @@ -3064,15 +3063,15 @@ AstNode *parse_type_or_ident(AstFile *f) { case Token_union: { Token token = expect_token(f, Token_union); Token open = expect_token_after(f, Token_OpenBrace, "union"); - AstNodeArray decls = make_ast_node_array(f); - AstNodeArray variants = make_ast_node_array(f); + Array decls = make_ast_node_array(f); + Array variants = make_ast_node_array(f); isize total_decl_name_count = 0; while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { u32 decl_flags = parse_field_prefixes(f); if (decl_flags != 0) { - AstNodeArray names = parse_ident_list(f); + Array names = parse_ident_list(f); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); } @@ -3082,7 +3081,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *type = parse_var_type(f, false); array_add(&decls, ast_field(f, names, type, set_flags)); } else { - AstNodeArray names = parse_ident_list(f); + Array names = parse_ident_list(f); if (names.count == 0) { break; } @@ -3121,7 +3120,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union")); Token close = expect_token(f, Token_CloseBrace); - AstNodeArray decls = {}; + Array decls = {}; if (fields != NULL) { GB_ASSERT(fields->kind == AstNode_FieldList); decls = fields->FieldList.list; @@ -3138,7 +3137,7 @@ AstNode *parse_type_or_ident(AstFile *f) { } Token open = expect_token(f, Token_OpenBrace); - AstNodeArray values = parse_element_list(f); + Array values = parse_element_list(f); Token close = expect_token(f, Token_CloseBrace); return ast_enum_type(f, token, base_type, values); @@ -3146,7 +3145,7 @@ AstNode *parse_type_or_ident(AstFile *f) { case Token_bit_field: { Token token = expect_token(f, Token_bit_field); - AstNodeArray fields = make_ast_node_array(f); + Array fields = make_ast_node_array(f); AstNode *align = NULL; Token open, close; @@ -3212,7 +3211,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *parse_body(AstFile *f) { - AstNodeArray stmts = {}; + Array stmts = {}; Token open, close; isize prev_expr_level = f->expr_level; @@ -3328,7 +3327,7 @@ AstNode *parse_return_stmt(AstFile *f) { } Token token = expect_token(f, Token_return); - AstNodeArray results; + Array results; if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { results = parse_rhs_expr_list(f); } else { @@ -3355,7 +3354,7 @@ AstNode *parse_return_stmt(AstFile *f) { // } // Token token = expect_token(f, Token_give); -// AstNodeArray results; +// Array results; // if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { // results = parse_rhs_expr_list(f); // } else { @@ -3440,7 +3439,7 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *parse_case_clause(AstFile *f, bool is_type) { Token token = f->curr_token; - AstNodeArray list = make_ast_node_array(f); + Array list = make_ast_node_array(f); expect_token(f, Token_case); bool prev_allow_range = f->allow_range; f->allow_range = !is_type; @@ -3449,7 +3448,7 @@ AstNode *parse_case_clause(AstFile *f, bool is_type) { } f->allow_range = prev_allow_range; expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax? - AstNodeArray stmts = parse_stmt_list(f); + Array stmts = parse_stmt_list(f); return ast_case_clause(f, token, list, stmts); } @@ -3467,7 +3466,7 @@ AstNode *parse_match_stmt(AstFile *f) { AstNode *body = NULL; Token open, close; bool is_type_match = false; - AstNodeArray list = make_ast_node_array(f); + Array list = make_ast_node_array(f); if (f->curr_token.kind != Token_OpenBrace) { isize prev_level = f->expr_level; @@ -3607,7 +3606,7 @@ AstNode *parse_stmt(AstFile *f) { case Token_using: { // TODO(bill): Make using statements better Token token = expect_token(f, Token_using); - AstNodeArray list = parse_lhs_expr_list(f); + Array list = parse_lhs_expr_list(f); if (list.count == 0) { syntax_error(token, "Illegal use of `using` statement"); expect_semicolon(f, NULL); @@ -3878,8 +3877,8 @@ AstNode *parse_stmt(AstFile *f) { return ast_bad_stmt(f, token, f->curr_token); } -AstNodeArray parse_stmt_list(AstFile *f) { - AstNodeArray list = make_ast_node_array(f); +Array parse_stmt_list(AstFile *f) { + Array list = make_ast_node_array(f); while (f->curr_token.kind != Token_case && f->curr_token.kind != Token_CloseBrace && @@ -4042,7 +4041,7 @@ bool is_import_path_valid(String path) { return false; } -void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls) { +void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array decls) { for_array(i, decls) { AstNode *node = decls[i]; if (!is_ast_node_decl(node) && diff --git a/src/ssa.cpp b/src/ssa.cpp index ebda96c31..010d11e6c 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -1,15 +1,15 @@ -typedef struct ssaModule ssaModule; -typedef struct ssaValue ssaValue; -typedef struct ssaValueArgs ssaValueArgs; -typedef struct ssaDefer ssaDefer; -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; -typedef enum ssaDeferExitKind ssaDeferExitKind; +struct ssaModule; +struct ssaValue; +struct ssaValueArgs; +struct ssaDefer; +struct ssaBlock; +struct ssaProc; +struct ssaEdge; +struct ssaRegister; +struct ssaTargetList; +enum ssaBlockKind; +enum ssaBranchPrediction; +enum ssaDeferExitKind; String ssa_mangle_name(ssaModule *m, String path, Entity *e); @@ -19,8 +19,6 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e); #define MAP_NAME MapSsaValue #include "map.cpp" -typedef Array ssaValueArray; - #include "ssa_op.cpp" #define SSA_DEFAULT_VALUE_ARG_CAPACITY 8 @@ -76,10 +74,10 @@ enum ssaBranchPrediction { ssaBranch_Unlikely = -1, }; -typedef enum ssaDeferKind { +enum ssaDeferKind { ssaDefer_Node, ssaDefer_Instr, -} ssaDeferKind; +}; struct ssaDefer { ssaDeferKind kind; @@ -106,8 +104,6 @@ struct ssaEdge { isize index; }; -typedef Array ssaEdgeArray; - struct ssaBlock { i32 id; // Unique identifier but the pointer could be used too ssaBlockKind kind; @@ -124,9 +120,9 @@ struct ssaBlock { // - BlockExit will be a memory control value ssaValue *control; - ssaValueArray values; - ssaEdgeArray preds; - ssaEdgeArray succs; + Array values; + Array preds; + Array succs; }; struct ssaTargetList { @@ -182,18 +178,18 @@ struct ssaModule { u32 stmt_state_flags; Array procs; - ssaValueArray procs_to_generate; + Array procs_to_generate; }; -typedef enum ssaAddrKind { +enum ssaAddrKind { ssaAddr_Default, ssaAddr_Map, -} ssaAddrKind; +}; -typedef struct ssaAddr { +struct ssaAddr { ssaValue * addr; ssaAddrKind kind; -} ssaAddr; +}; @@ -408,7 +404,7 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) { ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr); ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr); void ssa_build_stmt (ssaProc *p, AstNode *node); -void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes); +void ssa_build_stmt_list(ssaProc *p, Array nodes); ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel); @@ -1870,7 +1866,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { -void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) { +void ssa_build_stmt_list(ssaProc *p, Array nodes) { for_array(i, nodes) { ssa_build_stmt(p, nodes[i]); } @@ -1989,7 +1985,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { } } else { Array lvals = {0}; - ssaValueArray inits = {0}; + Array inits = {0}; array_init(&lvals, m->tmp_allocator, vd->names.count); array_init(&inits, m->tmp_allocator, vd->names.count); @@ -2057,7 +2053,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { ssaValue *init = ssa_build_expr(p, rhs); ssa_addr_store(p, lvals[0], init); } else { - ssaValueArray inits; + Array inits; array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { @@ -2070,7 +2066,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { } } } else { - ssaValueArray inits; + Array inits; array_init(&inits, m->tmp_allocator, lvals.count); for_array(i, as->rhs) { diff --git a/src/ssa_op.cpp b/src/ssa_op.cpp index 4c1921065..c62e7cf77 100644 --- a/src/ssa_op.cpp +++ b/src/ssa_op.cpp @@ -267,7 +267,6 @@ enum ssaOp { SSA_OPS #undef SSA_OP }; -typedef enum ssaOp ssaOp; String const ssa_op_strings[] = { #define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1}, diff --git a/src/string.cpp b/src/string.cpp index 105e9961b..6b6302ede 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -9,7 +9,7 @@ void init_string_buffer_memory(void) { // NOTE(bill): Used for UTF-8 strings -typedef struct String { +struct String { u8 * text; isize len; @@ -21,7 +21,7 @@ typedef struct String { GB_ASSERT(0 <= i && i < len); return text[i]; } -} String; +}; // NOTE(bill): used for printf style arguments #define LIT(x) ((int)(x).len), (x).text #define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1} @@ -29,7 +29,7 @@ typedef struct String { // NOTE(bill): String16 is only used for Windows due to its file directories -typedef struct String16 { +struct String16 { wchar_t *text; isize len; wchar_t &operator[](isize i) { @@ -40,7 +40,7 @@ typedef struct String16 { GB_ASSERT(0 <= i && i < len); return text[i]; } -} String16; +}; gb_inline String make_string(u8 *text, isize len) { diff --git a/src/timings.cpp b/src/timings.cpp index 04c1667f4..d00d5d0ba 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -1,14 +1,14 @@ -typedef struct TimeStamp { +struct TimeStamp { u64 start; u64 finish; String label; -} TimeStamp; +}; -typedef struct Timings { +struct Timings { TimeStamp total; Array sections; u64 freq; -} Timings; +}; #if defined(GB_SYSTEM_WINDOWS) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 9e4151c50..38026deeb 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -117,11 +117,11 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token_Count, "") -typedef enum TokenKind { +enum TokenKind { #define TOKEN_KIND(e, s) e TOKEN_KINDS #undef TOKEN_KIND -} TokenKind; +}; String const token_strings[] = { #define TOKEN_KIND(e, s) {cast(u8 *)s, gb_size_of(s)-1} @@ -130,11 +130,11 @@ String const token_strings[] = { }; -typedef struct TokenPos { +struct TokenPos { String file; isize line; isize column; -} TokenPos; +}; i32 token_pos_cmp(TokenPos a, TokenPos b) { if (a.line == b.line) { @@ -152,11 +152,11 @@ bool token_pos_eq(TokenPos a, TokenPos b) { return token_pos_cmp(a, b) == 0; } -typedef struct Token { +struct Token { TokenKind kind; String string; TokenPos pos; -} Token; +}; Token empty_token = {Token_Invalid}; Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}}; @@ -167,12 +167,12 @@ Token make_token_ident(String s) { } -typedef struct ErrorCollector { +struct ErrorCollector { TokenPos prev; i64 count; i64 warning_count; gbMutex mutex; -} ErrorCollector; +}; gb_global ErrorCollector global_error_collector; @@ -306,7 +306,7 @@ gb_inline bool token_is_shift(TokenKind t) { gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); } -typedef enum TokenizerInitError { +enum TokenizerInitError { TokenizerInit_None, TokenizerInit_Invalid, @@ -315,18 +315,18 @@ typedef enum TokenizerInitError { TokenizerInit_Empty, TokenizerInit_Count, -} TokenizerInitError; +}; -typedef struct TokenizerState { +struct TokenizerState { Rune curr_rune; // current character u8 * curr; // character pos u8 * read_curr; // pos from start u8 * line; // current line pos isize line_count; -} TokenizerState; +}; -typedef struct Tokenizer { +struct Tokenizer { String fullpath; u8 *start; u8 *end; @@ -339,7 +339,7 @@ typedef struct Tokenizer { isize error_count; Array allocated_strings; -} Tokenizer; +}; TokenizerState save_tokenizer_state(Tokenizer *t) { diff --git a/src/types.cpp b/src/types.cpp index 5ec5a40e9..4c02e2283 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,6 +1,6 @@ -typedef struct Scope Scope; +struct Scope; -typedef enum BasicKind { +enum BasicKind { Basic_Invalid, Basic_bool, Basic_i8, @@ -41,9 +41,9 @@ typedef enum BasicKind { Basic_COUNT, Basic_byte = Basic_u8, -} BasicKind; +}; -typedef enum BasicFlag { +enum BasicFlag { BasicFlag_Boolean = GB_BIT(0), BasicFlag_Integer = GB_BIT(1), BasicFlag_Unsigned = GB_BIT(2), @@ -57,16 +57,16 @@ typedef enum BasicFlag { BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, -} BasicFlag; +}; -typedef struct BasicType { +struct BasicType { BasicKind kind; u32 flags; i64 size; // -1 if arch. dep. String name; -} BasicType; +}; -typedef enum TypeRecordKind { +enum TypeRecordKind { TypeRecord_Invalid, TypeRecord_Struct, @@ -75,9 +75,9 @@ typedef enum TypeRecordKind { TypeRecord_Enum, TypeRecord_Count, -} TypeRecordKind; +}; -typedef struct TypeRecord { +struct TypeRecord { TypeRecordKind kind; // All record types @@ -109,7 +109,7 @@ typedef struct TypeRecord { Entity * enum_count; Entity * enum_min_value; Entity * enum_max_value; -} TypeRecord; +}; #define TYPE_KINDS \ TYPE_KIND(Basic, BasicType) \ @@ -164,13 +164,13 @@ typedef struct TypeRecord { -typedef enum TypeKind { +enum TypeKind { Type_Invalid, #define TYPE_KIND(k, ...) GB_JOIN2(Type_, k), TYPE_KINDS #undef TYPE_KIND Type_Count, -} TypeKind; +}; String const type_strings[] = { {cast(u8 *)"Invalid", gb_size_of("Invalid")}, @@ -183,7 +183,7 @@ String const type_strings[] = { TYPE_KINDS #undef TYPE_KIND -typedef struct Type { +struct Type { TypeKind kind; union { #define TYPE_KIND(k, ...) GB_JOIN2(Type, k) k; @@ -191,16 +191,16 @@ typedef struct Type { #undef TYPE_KIND }; bool failure; -} Type; +}; // TODO(bill): Should I add extra information here specifying the kind of selection? // e.g. field, constant, vector field, type field, etc. -typedef struct Selection { +struct Selection { Entity * entity; Array index; bool indirect; // Set if there was a pointer deref anywhere down the line -} Selection; +}; Selection empty_selection = {0}; Selection make_selection(Entity *entity, Array index, bool indirect) { @@ -1199,7 +1199,7 @@ bool is_type_cte_safe(Type *type) { return false; } -typedef enum ProcTypeOverloadKind { +enum ProcTypeOverloadKind { ProcOverload_Identical, // The types are identical ProcOverload_CallingConvention, @@ -1211,7 +1211,7 @@ typedef enum ProcTypeOverloadKind { ProcOverload_NotProcedure, -} ProcTypeOverloadKind; +}; ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { if (x == NULL && y == NULL) return ProcOverload_NotProcedure; @@ -1508,10 +1508,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } -typedef struct TypePath { +struct TypePath { Array path; // Entity_TypeName; bool failure; -} TypePath; +}; void type_path_init(TypePath *tp) { // TODO(bill): Use an allocator that uses a backing array if it can and then use alternative allocator when exhausted -- cgit v1.2.3 From 5cad7d44a6f51afe97b3176a6c55d53d96cc40b7 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 13:26:48 +0100 Subject: Use templated `Map` for extra type safety --- src/check_decl.cpp | 18 ++--- src/check_expr.cpp | 66 +++++++-------- src/check_stmt.cpp | 33 ++++---- src/checker.cpp | 198 +++++++++++++++++++-------------------------- src/common.cpp | 20 +---- src/exact_value.cpp | 1 + src/ir.cpp | 167 ++++++++++++++++++-------------------- src/ir_print.cpp | 14 ++-- src/map.cpp | 229 ++++++++++++++++++++++++++-------------------------- src/ssa.cpp | 42 +++++----- 10 files changed, 361 insertions(+), 427 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 356cd488b..28aa41b8e 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -319,7 +319,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { } if (is_foreign) { - MapEntity *fp = &c->info.foreigns; + auto *fp = &c->info.foreigns; String name = e->token.string; if (pd->foreign_name.len > 0) { name = pd->foreign_name; @@ -352,7 +352,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { e->Procedure.foreign_name = name; HashKey key = hash_string(name); - Entity **found = map_entity_get(fp, key); + Entity **found = map_get(fp, key); if (found) { Entity *f = *found; TokenPos pos = f->token.pos; @@ -365,7 +365,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { LIT(name), LIT(pos.file), pos.line, pos.column); } } else { - map_entity_set(fp, key, e); + map_set(fp, key, e); } } else { String name = e->token.string; @@ -374,12 +374,12 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { } if (is_link_name || is_export) { - MapEntity *fp = &c->info.foreigns; + auto *fp = &c->info.foreigns; e->Procedure.link_name = name; HashKey key = hash_string(name); - Entity **found = map_entity_get(fp, key); + Entity **found = map_get(fp, key); if (found) { Entity *f = *found; TokenPos pos = f->token.pos; @@ -389,7 +389,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { "\tother at %.*s(%td:%td)", LIT(name), LIT(pos.file), pos.line, pos.column); } else { - map_entity_set(fp, key, e); + map_set(fp, key, e); } } } @@ -443,7 +443,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { } if (d == NULL) { - DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); + DeclInfo **found = map_get(&c->info.entities, hash_pointer(e)); if (found) { d = *found; } else { @@ -511,7 +511,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod String name = e->token.string; Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { - Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); for_array(i, (*found)->elements.entries) { Entity *f = (*found)->elements.entries[i].value; @@ -557,7 +557,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod for_array(i, decl->deps.entries) { HashKey key = decl->deps.entries[i].key; Entity *e = cast(Entity *)key.ptr; - map_bool_set(&decl->parent->deps, key, true); + map_set(&decl->parent->deps, key, true); } } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2af676831..5043f9b38 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -62,7 +62,7 @@ void check_scope_decls(Checker *c, Array nodes, isize reserve_size) { default: continue; } - DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); + DeclInfo **found = map_get(&c->info.entities, hash_pointer(e)); if (found != NULL) { DeclInfo *d = *found; check_entity_decl(c, e, d, NULL); @@ -348,7 +348,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } -void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *entity_map) { +void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map *entity_map) { t = base_type(type_deref(t)); gbString str = NULL; if (node != NULL) { @@ -361,7 +361,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en GB_ASSERT(f->kind == Entity_Variable); String name = f->token.string; HashKey key = hash_string(name); - Entity **found = map_entity_get(entity_map, key); + Entity **found = map_get(entity_map, key); if (found != NULL) { Entity *e = *found; // TODO(bill): Better type error @@ -371,7 +371,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en error(e->token, "`%.*s` is already declared`", LIT(name)); } } else { - map_entity_set(entity_map, key, f); + map_set(entity_map, key, f); add_entity(c, c->context.scope, NULL, f); if (f->flags & EntityFlag_Using) { populate_using_entity_map(c, node, f->type, entity_map); @@ -390,8 +390,8 @@ isize check_fields(Checker *c, AstNode *node, Array decls, String context) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - MapEntity entity_map = {}; - map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); + Map entity_map = {}; + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); Entity *using_index_expr = NULL; @@ -433,7 +433,7 @@ isize check_fields(Checker *c, AstNode *node, Array decls, error_node(name, "`__tag` is a reserved identifier for fields"); } else { HashKey key = hash_string(name_token.string); - Entity **found = map_entity_get(&entity_map, key); + Entity **found = map_get(&entity_map, key); if (found != NULL) { Entity *e = *found; // NOTE(bill): Scope checking already checks the declaration but in many cases, this can happen so why not? @@ -441,7 +441,7 @@ isize check_fields(Checker *c, AstNode *node, Array decls, error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string)); error(e->token, "\tpreviously declared"); } else { - map_entity_set(&entity_map, key, e); + map_set(&entity_map, key, e); fields[field_index++] = e; add_entity(c, c->context.scope, name, e); } @@ -650,8 +650,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - MapEntity entity_map = {}; // Key: String - map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*variant_count); + Map entity_map = {}; // Key: String + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*variant_count); Entity *using_index_expr = NULL; @@ -666,7 +666,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { for (isize i = 0; i < field_count; i++) { Entity *f = fields[i]; String name = f->token.string; - map_entity_set(&entity_map, hash_string(name), f); + map_set(&entity_map, hash_string(name), f); } union_type->Record.fields = fields; @@ -735,11 +735,11 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { } HashKey key = hash_string(name_token.string); - if (map_entity_get(&entity_map, key) != NULL) { + if (map_get(&entity_map, key) != NULL) { // NOTE(bill): Scope checking already checks the declaration error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); } else { - map_entity_set(&entity_map, key, e); + map_set(&entity_map, key, e); variants[variant_index++] = e; } add_entity_use(c, f->name, e); @@ -801,8 +801,8 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod // NOTE(bill): Must be up here for the `check_init_constant` system enum_type->Record.enum_base_type = base_type; - MapEntity entity_map = {}; // Key: String - map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count)); + Map entity_map = {}; // Key: String + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count)); Entity **fields = gb_alloc_array(c->allocator, Entity *, et->fields.count); isize field_count = 0; @@ -888,10 +888,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod e->flags |= EntityFlag_Visited; HashKey key = hash_string(name); - if (map_entity_get(&entity_map, key) != NULL) { + if (map_get(&entity_map, key) != NULL) { error_node(ident, "`%.*s` is already declared in this enumeration", LIT(name)); } else { - map_entity_set(&entity_map, key, e); + map_set(&entity_map, key, e); add_entity(c, c->context.scope, NULL, e); fields[field_count++] = e; add_entity_use(c, field, e); @@ -922,8 +922,8 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - MapEntity entity_map = {}; // Key: String - map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(bft->fields.count)); + Map entity_map = {}; // Key: String + map_init_with_reserve(&entity_map, c->tmp_allocator, 2*(bft->fields.count)); isize field_count = 0; Entity **fields = gb_alloc_array(c->allocator, Entity *, bft->fields.count); @@ -967,10 +967,10 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As HashKey key = hash_string(name); if (name != "_" && - map_entity_get(&entity_map, key) != NULL) { + map_get(&entity_map, key) != NULL) { error_node(ident, "`%.*s` is already declared in this bit field", LIT(name)); } else { - map_entity_set(&entity_map, key, e); + map_set(&entity_map, key, e); add_entity(c, c->context.scope, NULL, e); add_entity_use(c, field, e); @@ -1418,7 +1418,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * if (e->kind == Entity_Procedure) { // NOTE(bill): Overloads are only allowed with the same scope Scope *s = e->scope; - overload_count = map_entity_multi_count(&s->elements, key); + overload_count = multi_map_count(&s->elements, key); if (overload_count > 1) { is_overloaded = true; } @@ -1429,7 +1429,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * bool skip = false; Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); - map_entity_multi_get_all(&s->elements, key, procs); + multi_map_get_all(&s->elements, key, procs); if (type_hint != NULL) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); // NOTE(bill): These should be done @@ -2488,7 +2488,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { TokenPos pos = ast_node_token(x->expr).pos; if (x_is_untyped) { - ExprInfo *info = map_expr_info_get(&c->info.untyped, hash_pointer(x->expr)); + ExprInfo *info = map_get(&c->info.untyped, hash_pointer(x->expr)); if (info != NULL) { info->is_lhs = true; } @@ -2944,7 +2944,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) { HashKey key = hash_pointer(e); - ExprInfo *found = map_expr_info_get(&c->info.untyped, key); + ExprInfo *found = map_get(&c->info.untyped, key); if (found == NULL) { return; } @@ -2983,12 +2983,12 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) { if (!final && is_type_untyped(type)) { old.type = base_type(type); - map_expr_info_set(&c->info.untyped, key, old); + map_set(&c->info.untyped, key, old); return; } // We need to remove it and then give it a new one - map_expr_info_remove(&c->info.untyped, key); + map_remove(&c->info.untyped, key); if (old.is_lhs && !is_type_integer(type)) { gbString expr_str = expr_to_string(e); @@ -3003,7 +3003,7 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) { } void update_expr_value(Checker *c, AstNode *e, ExactValue value) { - ExprInfo *found = map_expr_info_get(&c->info.untyped, hash_pointer(e)); + ExprInfo *found = map_get(&c->info.untyped, hash_pointer(e)); if (found) { found->value = value; } @@ -3206,7 +3206,7 @@ isize entity_overload_count(Scope *s, String name) { } if (e->kind == Entity_Procedure) { // NOTE(bill): Overloads are only allowed with the same scope - return map_entity_multi_count(&s->elements, hash_string(e->token.string)); + return multi_map_count(&s->elements, hash_string(e->token.string)); } return 1; } @@ -3298,7 +3298,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h isize overload_count = entity_overload_count(import_scope, entity_name); bool is_overloaded = overload_count > 1; - bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL; + bool implicit_is_found = map_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL; bool is_not_exported = !is_entity_exported(entity); if (!implicit_is_found) { is_not_exported = false; @@ -3320,7 +3320,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h bool skip = false; Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); - map_entity_multi_get_all(&import_scope->elements, key, procs); + multi_map_get_all(&import_scope->elements, key, procs); for (isize i = 0; i < overload_count; i++) { Type *t = base_type(procs[i]->type); @@ -3329,7 +3329,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } // NOTE(bill): Check to see if it's imported - if (map_bool_get(&import_scope->implicit, hash_pointer(procs[i]))) { + if (map_get(&import_scope->implicit, hash_pointer(procs[i]))) { gb_swap(Entity *, procs[i], procs[overload_count-1]); overload_count--; i--; // NOTE(bill): Counteract the post event @@ -4892,7 +4892,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod for (isize i = 0; i < overload_count; i++) { Entity *e = procs[i]; - DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); + DeclInfo **found = map_get(&c->info.entities, hash_pointer(e)); GB_ASSERT(found != NULL); DeclInfo *d = *found; check_entity_decl(c, e, d, NULL); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 859aa593d..d35a49478 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -389,11 +389,6 @@ struct TypeAndToken { Token token; }; -#define MAP_TYPE TypeAndToken -#define MAP_PROC map_type_and_token_ -#define MAP_NAME MapTypeAndToken -#include "map.cpp" - void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) { flags &= ~Stmt_CheckScopeDecls; Operand operand = {Addressing_Invalid}; @@ -535,7 +530,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) { // TODO(bill): Make it work for unions too - Scope **found_ = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); + Scope **found_ = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found_ != NULL); Scope *found = *found_; for_array(i, found->elements.entries) { @@ -1130,8 +1125,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } - MapTypeAndToken seen = {}; // NOTE(bill): Multimap - map_type_and_token_init(&seen, heap_allocator()); + Map seen = {}; // NOTE(bill): Multimap + map_init(&seen, heap_allocator()); for_array(i, bs->stmts) { AstNode *stmt = bs->stmts[i]; @@ -1222,13 +1217,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (y.value.kind != ExactValue_Invalid) { HashKey key = hash_exact_value(y.value); - TypeAndToken *found = map_type_and_token_get(&seen, key); + TypeAndToken *found = map_get(&seen, key); if (found != NULL) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - isize count = map_type_and_token_multi_count(&seen, key); + isize count = multi_map_count(&seen, key); TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); - map_type_and_token_multi_get_all(&seen, key, taps); + multi_map_get_all(&seen, key, taps); bool continue_outer = false; for (isize i = 0; i < count; i++) { @@ -1254,7 +1249,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } TypeAndToken tap = {y.type, ast_node_token(y.expr)}; - map_type_and_token_multi_insert(&seen, key, tap); + multi_map_insert(&seen, key, tap); } } } @@ -1268,7 +1263,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_close_scope(c); } - map_type_and_token_destroy(&seen); + map_destroy(&seen); check_close_scope(c); case_end; @@ -1346,8 +1341,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } - MapBool seen = {}; // Multimap - map_bool_init(&seen, heap_allocator()); + Map seen = {}; // Multimap + map_init(&seen, heap_allocator()); for_array(i, bs->stmts) { AstNode *stmt = bs->stmts[i]; @@ -1391,7 +1386,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } HashKey key = hash_pointer(y.type); - bool *found = map_bool_get(&seen, key); + bool *found = map_get(&seen, key); if (found) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); @@ -1403,7 +1398,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { gb_string_free(expr_str); break; } - map_bool_set(&seen, key, cast(bool)true); + map_set(&seen, key, cast(bool)true); } } @@ -1434,7 +1429,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_stmt_list(c, cc->stmts, mod_flags); check_close_scope(c); } - map_bool_destroy(&seen); + map_destroy(&seen); check_close_scope(c); case_end; @@ -1635,7 +1630,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { - Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); for_array(i, (*found)->elements.entries) { Entity *f = (*found)->elements.entries[i].value; diff --git a/src/checker.cpp b/src/checker.cpp index 389740694..dd0b60a9c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -195,7 +195,7 @@ struct DeclInfo { AstNode * init_expr; AstNode * proc_lit; // AstNode_ProcLit - MapBool deps; // Key: Entity * + Map deps; // Key: Entity * Array labels; }; @@ -226,18 +226,13 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue -#define MAP_TYPE Entity * -#define MAP_PROC map_entity_ -#define MAP_NAME MapEntity -#include "map.cpp" - struct Scope { Scope * parent; Scope * prev, *next; Scope * first_child; Scope * last_child; - MapEntity elements; // Key: String - MapBool implicit; // Key: Entity * + Map elements; // Key: String + Map implicit; // Key: Entity * Array shared; Array imported; @@ -254,31 +249,6 @@ gb_global Scope *universal_scope = NULL; -#define MAP_TYPE TypeAndValue -#define MAP_PROC map_tav_ -#define MAP_NAME MapTypeAndValue -#include "map.cpp" - -#define MAP_TYPE Scope * -#define MAP_PROC map_scope_ -#define MAP_NAME MapScope -#include "map.cpp" - -#define MAP_TYPE DeclInfo * -#define MAP_PROC map_decl_info_ -#define MAP_NAME MapDeclInfo -#include "map.cpp" - -#define MAP_TYPE AstFile * -#define MAP_PROC map_ast_file_ -#define MAP_NAME MapAstFile -#include "map.cpp" - -#define MAP_TYPE ExprInfo -#define MAP_PROC map_expr_info_ -#define MAP_NAME MapExprInfo -#include "map.cpp" - struct DelayedDecl { Scope * parent; AstNode *decl; @@ -304,16 +274,16 @@ struct CheckerContext { // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { - MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value) - MapEntity definitions; // Key: AstNode * | Identifier -> Entity - MapEntity uses; // Key: AstNode * | Identifier -> Entity - MapScope scopes; // Key: AstNode * | Node -> Scope - MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo - MapEntity implicits; // Key: AstNode * - MapDeclInfo entities; // Key: Entity * - MapEntity foreigns; // Key: String - MapAstFile files; // Key: String (full path) - MapIsize type_info_map; // Key: Type * + Map types; // Key: AstNode * | Expression -> Type (and value) + Map definitions; // Key: AstNode * | Identifier -> Entity + Map uses; // Key: AstNode * | Identifier -> Entity + Map scopes; // Key: AstNode * | Node -> Scope + Map untyped; // Key: AstNode * | Expression -> ExprInfo + Map implicits; // Key: AstNode * + Map entities; // Key: Entity * + Map foreigns; // Key: String + Map files; // Key: String (full path) + Map type_info_map; // Key: Type * isize type_info_count; }; @@ -352,7 +322,7 @@ struct DelayedEntity { void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { d->parent = parent; d->scope = scope; - map_bool_init(&d->deps, heap_allocator()); + map_init(&d->deps, heap_allocator()); array_init(&d->labels, heap_allocator()); } @@ -363,7 +333,7 @@ DeclInfo *make_declaration_info(gbAllocator a, Scope *scope, DeclInfo *parent) { } void destroy_declaration_info(DeclInfo *d) { - map_bool_destroy(&d->deps); + map_destroy(&d->deps); } bool decl_info_has_init(DeclInfo *d) { @@ -390,8 +360,8 @@ bool decl_info_has_init(DeclInfo *d) { Scope *make_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); s->parent = parent; - map_entity_init(&s->elements, heap_allocator()); - map_bool_init(&s->implicit, heap_allocator()); + map_init(&s->elements, heap_allocator()); + map_init(&s->implicit, heap_allocator()); array_init(&s->shared, heap_allocator()); array_init(&s->imported, heap_allocator()); @@ -417,8 +387,8 @@ void destroy_scope(Scope *scope) { destroy_scope(child); } - map_entity_destroy(&scope->elements); - map_bool_destroy(&scope->implicit); + map_destroy(&scope->elements); + map_destroy(&scope->implicit); array_free(&scope->shared); array_free(&scope->imported); @@ -428,7 +398,7 @@ void destroy_scope(Scope *scope) { void add_scope(Checker *c, AstNode *node, Scope *scope) { GB_ASSERT(node != NULL); GB_ASSERT(scope != NULL); - map_scope_set(&c->info.scopes, hash_pointer(node), scope); + map_set(&c->info.scopes, hash_pointer(node), scope); } @@ -454,13 +424,13 @@ void check_close_scope(Checker *c) { Entity *current_scope_lookup_entity(Scope *s, String name) { HashKey key = hash_string(name); - Entity **found = map_entity_get(&s->elements, key); + Entity **found = map_get(&s->elements, key); if (found) { return *found; } for_array(i, s->shared) { Scope *shared = s->shared[i]; - Entity **found = map_entity_get(&shared->elements, key); + Entity **found = map_get(&shared->elements, key); if (found) { Entity *e = *found; if (e->kind == Entity_Variable && @@ -485,7 +455,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit bool gone_thru_file = false; HashKey key = hash_string(name); for (Scope *s = scope; s != NULL; s = s->parent) { - Entity **found = map_entity_get(&s->elements, key); + Entity **found = map_get(&s->elements, key); if (found) { Entity *e = *found; if (gone_thru_proc) { @@ -510,7 +480,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit // Check shared scopes - i.e. other files @ global scope for_array(i, s->shared) { Scope *shared = s->shared[i]; - Entity **found = map_entity_get(&shared->elements, key); + Entity **found = map_get(&shared->elements, key); if (found) { Entity *e = *found; if (e->kind == Entity_Variable && @@ -558,7 +528,7 @@ Entity *scope_lookup_entity(Scope *s, String name) { Entity *scope_insert_entity(Scope *s, Entity *entity) { String name = entity->token.string; HashKey key = hash_string(name); - Entity **found = map_entity_get(&s->elements, key); + Entity **found = map_get(&s->elements, key); #if 1 // IMPORTANT NOTE(bill): Procedure overloading code @@ -576,15 +546,15 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { if (s->is_global) { return prev; } - map_entity_multi_insert(&s->elements, key, entity); + multi_map_insert(&s->elements, key, entity); } else { - map_entity_set(&s->elements, key, entity); + map_set(&s->elements, key, entity); } #else if (found) { return *found; } - map_entity_set(&s->elements, key, entity); + map_set(&s->elements, key, entity); #endif if (entity->scope == NULL) { entity->scope = s; @@ -599,7 +569,7 @@ void check_scope_usage(Checker *c, Scope *scope) { void add_dependency(DeclInfo *d, Entity *e) { - map_bool_set(&d->deps, hash_pointer(e), cast(bool)true); + map_set(&d->deps, hash_pointer(e), cast(bool)true); } void add_declaration_dependency(Checker *c, Entity *e) { @@ -607,7 +577,7 @@ void add_declaration_dependency(Checker *c, Entity *e) { return; } if (c->context.decl != NULL) { - DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); + DeclInfo **found = map_get(&c->info.entities, hash_pointer(e)); if (found) { add_dependency(c->context.decl, e); } @@ -705,31 +675,31 @@ void init_universal_scope(void) { void init_checker_info(CheckerInfo *i) { gbAllocator a = heap_allocator(); - map_tav_init(&i->types, a); - map_entity_init(&i->definitions, a); - map_entity_init(&i->uses, a); - map_scope_init(&i->scopes, a); - map_decl_info_init(&i->entities, a); - map_expr_info_init(&i->untyped, a); - map_entity_init(&i->foreigns, a); - map_entity_init(&i->implicits, a); - map_isize_init(&i->type_info_map, a); - map_ast_file_init(&i->files, a); + map_init(&i->types, a); + map_init(&i->definitions, a); + map_init(&i->uses, a); + map_init(&i->scopes, a); + map_init(&i->entities, a); + map_init(&i->untyped, a); + map_init(&i->foreigns, a); + map_init(&i->implicits, a); + map_init(&i->type_info_map, a); + map_init(&i->files, a); i->type_info_count = 0; } void destroy_checker_info(CheckerInfo *i) { - map_tav_destroy(&i->types); - map_entity_destroy(&i->definitions); - map_entity_destroy(&i->uses); - map_scope_destroy(&i->scopes); - map_decl_info_destroy(&i->entities); - map_expr_info_destroy(&i->untyped); - map_entity_destroy(&i->foreigns); - map_entity_destroy(&i->implicits); - map_isize_destroy(&i->type_info_map); - map_ast_file_destroy(&i->files); + map_destroy(&i->types); + map_destroy(&i->definitions); + map_destroy(&i->uses); + map_destroy(&i->scopes); + map_destroy(&i->entities); + map_destroy(&i->untyped); + map_destroy(&i->foreigns); + map_destroy(&i->implicits); + map_destroy(&i->type_info_map); + map_destroy(&i->files); } @@ -793,11 +763,11 @@ void destroy_checker(Checker *c) { Entity *entity_of_ident(CheckerInfo *i, AstNode *identifier) { if (identifier->kind == AstNode_Ident) { - Entity **found = map_entity_get(&i->definitions, hash_pointer(identifier)); + Entity **found = map_get(&i->definitions, hash_pointer(identifier)); if (found) { return *found; } - found = map_entity_get(&i->uses, hash_pointer(identifier)); + found = map_get(&i->uses, hash_pointer(identifier)); if (found) { return *found; } @@ -808,7 +778,7 @@ Entity *entity_of_ident(CheckerInfo *i, AstNode *identifier) { TypeAndValue type_and_value_of_expr(CheckerInfo *i, AstNode *expression) { TypeAndValue result = {}; - TypeAndValue *found = map_tav_get(&i->types, hash_pointer(expression)); + TypeAndValue *found = map_get(&i->types, hash_pointer(expression)); if (found) result = *found; return result; } @@ -831,7 +801,7 @@ Type *type_of_expr(CheckerInfo *i, AstNode *expr) { void add_untyped(CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value) { - map_expr_info_set(&i->untyped, hash_pointer(expression), make_expr_info(lhs, mode, basic_type, value)); + map_set(&i->untyped, hash_pointer(expression), make_expr_info(lhs, mode, basic_type, value)); } void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) { @@ -858,7 +828,7 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode tv.type = type; tv.value = value; tv.mode = mode; - map_tav_set(&i->types, hash_pointer(expression), tv); + map_set(&i->types, hash_pointer(expression), tv); } void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) { @@ -868,7 +838,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) return; } HashKey key = hash_pointer(identifier); - map_entity_set(&i->definitions, key, entity); + map_set(&i->definitions, key, entity); } else { // NOTE(bill): Error should handled elsewhere } @@ -918,7 +888,7 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) { return; } HashKey key = hash_pointer(identifier); - map_entity_set(&c->info.uses, key, entity); + map_set(&c->info.uses, key, entity); add_declaration_dependency(c, entity); // TODO(bill): Should this be here? } @@ -928,14 +898,14 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn GB_ASSERT(e != NULL && d != NULL); GB_ASSERT(identifier->Ident.string == e->token.string); add_entity(c, e->scope, identifier, e); - map_decl_info_set(&c->info.entities, hash_pointer(e), d); + map_set(&c->info.entities, hash_pointer(e), d); } void add_implicit_entity(Checker *c, AstNode *node, Entity *e) { GB_ASSERT(node != NULL); GB_ASSERT(e != NULL); - map_entity_set(&c->info.implicits, hash_pointer(node), e); + map_set(&c->info.implicits, hash_pointer(node), e); } @@ -951,14 +921,14 @@ void add_type_info_type(Checker *c, Type *t) { return; // Could be nil } - if (map_isize_get(&c->info.type_info_map, hash_pointer(t)) != NULL) { + if (map_get(&c->info.type_info_map, hash_pointer(t)) != NULL) { // Types have already been added return; } isize ti_index = -1; for_array(i, c->info.type_info_map.entries) { - MapIsizeEntry *e = &c->info.type_info_map.entries[i]; + auto *e = &c->info.type_info_map.entries[i]; Type *prev_type = cast(Type *)e->key.ptr; if (are_types_identical(t, prev_type)) { // Duplicate entry @@ -972,7 +942,7 @@ void add_type_info_type(Checker *c, Type *t) { ti_index = c->info.type_info_count; c->info.type_info_count++; } - map_isize_set(&c->info.type_info_map, hash_pointer(t), ti_index); + map_set(&c->info.type_info_map, hash_pointer(t), ti_index); @@ -1123,17 +1093,17 @@ void add_curr_ast_file(Checker *c, AstFile *file) { -void add_dependency_to_map(MapEntity *map, CheckerInfo *info, Entity *node) { +void add_dependency_to_map(Map *map, CheckerInfo *info, Entity *node) { if (node == NULL) { return; } - if (map_entity_get(map, hash_pointer(node)) != NULL) { + if (map_get(map, hash_pointer(node)) != NULL) { return; } - map_entity_set(map, hash_pointer(node), node); + map_set(map, hash_pointer(node), node); - DeclInfo **found = map_decl_info_get(&info->entities, hash_pointer(node)); + DeclInfo **found = map_get(&info->entities, hash_pointer(node)); if (found == NULL) { return; } @@ -1145,9 +1115,9 @@ void add_dependency_to_map(MapEntity *map, CheckerInfo *info, Entity *node) { } } -MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { - MapEntity map = {}; // Key: Entity * - map_entity_init(&map, heap_allocator()); +Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { + Map map = {}; // Key: Entity * + map_init(&map, heap_allocator()); for_array(i, info->definitions.entries) { Entity *e = info->definitions.entries[i].value; @@ -1289,7 +1259,7 @@ bool check_is_entity_overloaded(Entity *e) { } Scope *s = e->scope; HashKey key = hash_string(e->token.string); - isize overload_count = map_entity_multi_count(&s->elements, key); + isize overload_count = multi_map_count(&s->elements, key); return overload_count > 1; } @@ -1309,7 +1279,7 @@ void check_procedure_overloading(Checker *c, Entity *e) { String name = e->token.string; HashKey key = hash_string(name); Scope *s = e->scope; - isize overload_count = map_entity_multi_count(&s->elements, key); + isize overload_count = multi_map_count(&s->elements, key); GB_ASSERT(overload_count >= 1); if (overload_count == 1) { e->Procedure.overload_kind = Overload_No; @@ -1320,7 +1290,7 @@ void check_procedure_overloading(Checker *c, Entity *e) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count); - map_entity_multi_get_all(&s->elements, key, procs); + multi_map_get_all(&s->elements, key, procs); for (isize j = 0; j < overload_count; j++) { Entity *p = procs[j]; @@ -1660,7 +1630,7 @@ void check_all_global_entities(Checker *c) { Scope *prev_file = {}; for_array(i, c->info.entities.entries) { - MapDeclInfoEntry *entry = &c->info.entities.entries[i]; + auto *entry = &c->info.entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; DeclInfo *d = entry->value; @@ -1698,7 +1668,7 @@ void check_all_global_entities(Checker *c) { } for_array(i, c->info.entities.entries) { - MapDeclInfoEntry *entry = &c->info.entities.entries[i]; + auto *entry = &c->info.entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; if (e->kind != Entity_Procedure) { continue; @@ -1769,7 +1739,7 @@ String path_to_entity_name(String name, String fullpath) { } } -void check_import_entities(Checker *c, MapScope *file_scopes) { +void check_import_entities(Checker *c, Map *file_scopes) { #if 0 // TODO(bill): Dependency ordering for imports { @@ -1810,7 +1780,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } HashKey key = hash_string(id->fullpath); - Scope **found = map_scope_get(file_scopes, key); + Scope **found = map_get(file_scopes, key); if (found == NULL) { for_array(scope_index, file_scopes->entries) { Scope *scope = file_scopes->entries[scope_index].value; @@ -1883,7 +1853,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } HashKey key = hash_string(id->fullpath); - Scope **found = map_scope_get(file_scopes, key); + Scope **found = map_get(file_scopes, key); if (found == NULL) { for_array(scope_index, file_scopes->entries) { Scope *scope = file_scopes->entries[scope_index].value; @@ -1946,7 +1916,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { // TODO(bill): Should these entities be imported but cause an error when used? bool ok = add_entity(c, parent_scope, e->identifier, e); if (ok) { - map_bool_set(&parent_scope->implicit, hash_pointer(e), true); + map_set(&parent_scope->implicit, hash_pointer(e), true); } } } else { @@ -2021,8 +1991,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { void check_parsed_files(Checker *c) { - MapScope file_scopes; // Key: String (fullpath) - map_scope_init(&file_scopes, heap_allocator()); + Map file_scopes; // Key: String (fullpath) + map_init(&file_scopes, heap_allocator()); // Map full filepaths to Scopes for_array(i, c->parser->files) { @@ -2047,8 +2017,8 @@ void check_parsed_files(Checker *c) { f->scope = scope; f->decl_info = make_declaration_info(c->allocator, f->scope, c->context.decl); HashKey key = hash_string(f->tokenizer.fullpath); - map_scope_set(&file_scopes, key, scope); - map_ast_file_set(&c->info.files, key, f); + map_set(&file_scopes, key, scope); + map_set(&c->info.files, key, f); } // Collect Entities @@ -2091,7 +2061,7 @@ void check_parsed_files(Checker *c) { // Add untyped expression values for_array(i, c->info.untyped.entries) { - MapExprInfoEntry *entry = &c->info.untyped.entries[i]; + auto *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; AstNode *expr = cast(AstNode *)cast(uintptr)key.key; ExprInfo *info = &entry->value; @@ -2166,6 +2136,6 @@ void check_parsed_files(Checker *c) { } } - map_scope_destroy(&file_scopes); + map_destroy(&file_scopes); } diff --git a/src/common.cpp b/src/common.cpp index c61f22a62..a38af63f4 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -18,6 +18,7 @@ gbAllocator heap_allocator(void) { #include "array.cpp" #include "integer128.cpp" #include "murmurhash3.cpp" +#include "map.cpp" u128 fnv128a(void const *data, isize len) { u128 o = u128_lo_hi(0x13bull, 0x1000000ull); @@ -234,23 +235,4 @@ f64 gb_sqrt(f64 x) { } \ } while (0) -//////////////////////////////////////////////////////////////// -// -// Generic Data Structures -// -//////////////////////////////////////////////////////////////// - -#define MAP_TYPE String -#define MAP_PROC map_string_ -#define MAP_NAME MapString -#include "map.cpp" - -#define MAP_TYPE bool -#define MAP_PROC map_bool_ -#define MAP_NAME MapBool -#include "map.cpp" -#define MAP_TYPE isize -#define MAP_PROC map_isize_ -#define MAP_NAME MapIsize -#include "map.cpp" diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 62ab326ea..b3d4e9f4f 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -4,6 +4,7 @@ // IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!! struct AstNode; +struct HashKey; struct Complex128 { f64 real, imag; diff --git a/src/ir.cpp b/src/ir.cpp index 4cd1734aa..e94f84e3b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3,15 +3,6 @@ struct irBlock; struct irValue; struct irDebugInfo; -#define MAP_TYPE irValue * -#define MAP_PROC map_ir_value_ -#define MAP_NAME MapIrValue -#include "map.cpp" - -#define MAP_TYPE irDebugInfo * -#define MAP_PROC map_ir_debug_info_ -#define MAP_NAME MapIrDebugInfo -#include "map.cpp" struct irModule { @@ -28,11 +19,11 @@ struct irModule { String layout; // String triple; - MapEntity min_dep_map; // Key: Entity * - MapIrValue values; // Key: Entity * - MapIrValue members; // Key: String - MapString entity_names; // Key: Entity * of the typename - MapIrDebugInfo debug_info; // Key: Unique pointer + Map min_dep_map; // Key: Entity * + Map values; // Key: Entity * + Map members; // Key: String + Map entity_names; // Key: Entity * of the typename + Map debug_info; // Key: Unique pointer i32 global_string_index; i32 global_array_index; // For ConstantSlice i32 global_generated_index; @@ -811,7 +802,7 @@ String ir_get_global_name(irModule *m, irValue *v) { irValueGlobal *g = &v->Global; Entity *e = g->entity; String name = e->token.string; - String *found = map_string_get(&m->entity_names, hash_pointer(e)); + String *found = map_get(&m->entity_names, hash_pointer(e)); if (found != NULL) { name = *found; } @@ -1136,14 +1127,14 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi irValue *value = ir_value_global(a, e, NULL); value->Global.is_private = true; ir_module_add_value(m, e, value); - map_ir_value_set(&m->members, hash_string(token.string), value); + map_set(&m->members, hash_string(token.string), value); return value; } irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) { Scope *scope = NULL; if (node != NULL) { - Scope **found = map_scope_get(&proc->module->info->scopes, hash_pointer(node)); + Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); if (found) { scope = *found; } else { @@ -1239,7 +1230,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value); irValue *g = ir_value_global(a, e, backing_array); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); return ir_value_constant_slice(a, type, g, count); } @@ -1270,7 +1261,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) { // g->Global.is_constant = true; ir_module_add_value(m, entity, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); return g; } @@ -1291,7 +1282,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) { // } if (expr != NULL && proc->entity != NULL) { - irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); + irDebugInfo *di = *map_get(&proc->module->debug_info, hash_pointer(proc->entity)); ir_emit(proc, ir_instr_debug_declare(proc, di, expr, e, true, instr)); } @@ -1299,7 +1290,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) { } irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero_initialized) { - Entity **found = map_entity_get(&proc->module->info->definitions, hash_pointer(name)); + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name)); if (found) { Entity *e = *found; ir_emit_comment(proc, e->token.string); @@ -1341,7 +1332,7 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) { irValue *g = ir_value_global(a, e, value); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); return g; } @@ -1407,7 +1398,7 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { di->File.filename = filename; di->File.directory = directory; - map_ir_debug_info_set(&proc->module->debug_info, hash_pointer(file), di); + map_set(&proc->module->debug_info, hash_pointer(file), di); return di; } @@ -1424,7 +1415,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na di->Proc.file = file; di->Proc.pos = entity->token.pos; - map_ir_debug_info_set(&proc->module->debug_info, hash_pointer(entity), di); + map_set(&proc->module->debug_info, hash_pointer(entity), di); return di; } @@ -1517,7 +1508,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_ irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count) { String name = make_string_c(name_); - irValue **found = map_ir_value_get(&proc->module->members, hash_string(name)); + irValue **found = map_get(&proc->module->members, hash_string(name)); GB_ASSERT_MSG(found != NULL, "%.*s", LIT(name)); irValue *gp = *found; return ir_emit_call(proc, gp, args, arg_count); @@ -3280,7 +3271,7 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) { isize entry_index = -1; HashKey key = hash_pointer(type); - isize *found_entry_index = map_isize_get(&info->type_info_map, key); + isize *found_entry_index = map_get(&info->type_info_map, key); if (found_entry_index) { entry_index = *found_entry_index; } @@ -3288,12 +3279,12 @@ isize ir_type_info_index(CheckerInfo *info, Type *type) { // NOTE(bill): Do manual search // TODO(bill): This is O(n) and can be very slow for_array(i, info->type_info_map.entries){ - MapIsizeEntry *e = &info->type_info_map.entries[i]; + auto *e = &info->type_info_map.entries[i]; Type *prev_type = cast(Type *)e->key.ptr; if (are_types_identical(prev_type, type)) { entry_index = e->value; // NOTE(bill): Add it to the search map - map_isize_set(&info->type_info_map, key, entry_index); + map_set(&info->type_info_map, key, entry_index); break; } } @@ -3434,7 +3425,7 @@ String ir_mangle_name(irGen *s, String path, Entity *e) { irModule *m = &s->module; CheckerInfo *info = m->info; gbAllocator a = m->allocator; - AstFile *file = *map_ast_file_get(&info->files, hash_string(path)); + AstFile *file = *map_get(&info->files, hash_string(path)); char *str = gb_alloc_array(a, char, path.len+1); gb_memmove(str, path.text, path.len); @@ -3496,14 +3487,14 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) { "%.*s.%.*s", LIT(parent), LIT(cn)); String child = {text, new_name_len-1}; - map_string_set(&m->entity_names, hash_pointer(field), child); + map_set(&m->entity_names, hash_pointer(field), child); ir_gen_global_type_name(m, field, child); } irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) { GB_ASSERT(ident->kind == AstNode_Ident); - Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(ident)); + Entity **found = map_get(&proc->module->info->uses, hash_pointer(ident)); GB_ASSERT(found != NULL); Entity *e = *found; GB_ASSERT(e->kind == Entity_Label); @@ -3553,7 +3544,7 @@ void ir_pop_target_list(irProcedure *proc) { void ir_gen_global_type_name(irModule *m, Entity *e, String name) { irValue *t = ir_value_type_name(m->allocator, name, e->type); ir_module_add_value(m, e, t); - map_ir_value_set(&m->members, hash_string(name), t); + map_set(&m->members, hash_string(name), t); if (is_type_union(e->type)) { Type *bt = base_type(e->type); @@ -3602,7 +3593,7 @@ irValue *ir_emit_clamp(irProcedure *proc, Type *t, irValue *x, irValue *min, irV irValue *ir_find_global_variable(irProcedure *proc, String name) { - irValue **value = map_ir_value_get(&proc->module->members, hash_string(name)); + irValue **value = map_get(&proc->module->members, hash_string(name)); GB_ASSERT_MSG(value != NULL, "Unable to find global variable `%.*s`", LIT(name)); return *value; } @@ -3660,7 +3651,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case_end; case_ast_node(i, Ident, expr); - Entity *e = *map_entity_get(&proc->module->info->uses, hash_pointer(expr)); + Entity *e = *map_get(&proc->module->info->uses, hash_pointer(expr)); if (e->kind == Entity_Builtin) { Token token = ast_node_token(expr); GB_PANIC("TODO(bill): ir_build_single_expr Entity_Builtin `%.*s`\n" @@ -3671,7 +3662,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { return ir_value_nil(proc->module->allocator, tv.type); } - irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e)); + irValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { irValue *v = *found; if (v->kind == irValue_Proc) { @@ -3873,7 +3864,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { case_ast_node(ce, CallExpr, expr); - if (map_tav_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { + if (map_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { GB_ASSERT(ce->args.count == 1); irValue *x = ir_build_expr(proc, ce->args[0]); irValue *y = ir_emit_conv(proc, x, tv.type); @@ -3882,7 +3873,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { AstNode *p = unparen_expr(ce->proc); if (p->kind == AstNode_Ident) { - Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(p)); + Entity **found = map_get(&proc->module->info->uses, hash_pointer(p)); if (found && (*found)->kind == Entity_Builtin) { Entity *e = *found; switch (e->Builtin.id) { @@ -4704,7 +4695,7 @@ irValue *ir_get_using_variable(irProcedure *proc, Entity *e) { 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 **pv = map_get(&proc->module->values, hash_pointer(parent)); irValue *v = NULL; if (pv != NULL) { v = *pv; @@ -4719,7 +4710,7 @@ irValue *ir_get_using_variable(irProcedure *proc, Entity *e) { // irValue *ir_add_using_variable(irProcedure *proc, Entity *e) { // irValue *var = ir_get_using_variable(proc, e); -// map_ir_value_set(&proc->module->values, hash_pointer(e), var); +// map_set(&proc->module->values, hash_pointer(e), var); // return var; // } @@ -4741,7 +4732,7 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) { GB_ASSERT(e->kind != Entity_Constant); irValue *v = NULL; - irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e)); + irValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { v = *found; } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { @@ -5720,7 +5711,7 @@ void ir_build_range_interval(irProcedure *proc, AstNodeBinaryExpr *node, Type *v } void ir_store_type_case_implicit(irProcedure *proc, AstNode *clause, irValue *value) { - Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause)); + Entity **found = map_get(&proc->module->info->implicits, hash_pointer(clause)); GB_ASSERT(found != NULL); Entity *e = *found; GB_ASSERT(e != NULL); irValue *x = ir_add_local(proc, e, NULL); @@ -5836,18 +5827,18 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *value = ir_value_type_name(proc->module->allocator, name, e->type); - map_string_set(&proc->module->entity_names, hash_pointer(e), name); + map_set(&proc->module->entity_names, hash_pointer(e), name); ir_gen_global_type_name(proc->module, e, name); } break; case Entity_Procedure: { - DeclInfo **decl_info = map_decl_info_get(&proc->module->info->entities, hash_pointer(e)); + DeclInfo **decl_info = map_get(&proc->module->info->entities, hash_pointer(e)); GB_ASSERT(decl_info != NULL); DeclInfo *dl = *decl_info; ast_node(pd, ProcLit, dl->proc_lit); if (pd->body != NULL) { CheckerInfo *info = proc->module->info; - if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) { + if (map_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) { // NOTE(bill): Nothing depends upon it so doesn't need to be built break; } @@ -5896,10 +5887,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (value->Proc.tags & ProcTag_foreign) { HashKey key = hash_string(name); - irValue **prev_value = map_ir_value_get(&proc->module->members, key); + irValue **prev_value = map_get(&proc->module->members, key); if (prev_value == NULL) { // NOTE(bill): Don't do mutliple declarations in the IR - map_ir_value_set(&proc->module->members, key, value); + map_set(&proc->module->members, key, value); } } else { array_add(&proc->children, &value->Proc); @@ -6509,7 +6500,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Entity *case_entity = NULL; { - Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause)); + Entity **found = map_get(&proc->module->info->implicits, hash_pointer(clause)); GB_ASSERT(found != NULL); case_entity = *found; } @@ -6679,7 +6670,7 @@ void ir_begin_procedure_body(irProcedure *proc) { array_init(&proc->children, heap_allocator()); array_init(&proc->branch_blocks, heap_allocator()); - DeclInfo **found = map_decl_info_get(&proc->module->info->entities, hash_pointer(proc->entity)); + DeclInfo **found = map_get(&proc->module->info->entities, hash_pointer(proc->entity)); if (found != NULL) { DeclInfo *decl = *found; for_array(i, decl->labels) { @@ -6774,12 +6765,12 @@ void ir_build_proc(irValue *value, irProcedure *parent) { CheckerInfo *info = m->info; Entity *e = proc->entity; String filename = e->token.pos.file; - AstFile **found = map_ast_file_get(&info->files, hash_string(filename)); + AstFile **found = map_get(&info->files, hash_string(filename)); GB_ASSERT(found != NULL); AstFile *f = *found; irDebugInfo *di_file = NULL; - irDebugInfo **di_file_found = map_ir_debug_info_get(&m->debug_info, hash_pointer(f)); + irDebugInfo **di_file_found = map_get(&m->debug_info, hash_pointer(f)); if (di_file_found) { di_file = *di_file_found; GB_ASSERT(di_file->kind == irDebugInfo_File); @@ -6831,7 +6822,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) { void ir_module_add_value(irModule *m, Entity *e, irValue *v) { - map_ir_value_set(&m->values, hash_pointer(e), v); + map_set(&m->values, hash_pointer(e), v); } void ir_init_module(irModule *m, Checker *c) { @@ -6844,10 +6835,10 @@ void ir_init_module(irModule *m, Checker *c) { m->tmp_allocator = gb_arena_allocator(&m->tmp_arena); m->info = &c->info; - map_ir_value_init(&m->values, heap_allocator()); - map_ir_value_init(&m->members, heap_allocator()); - map_ir_debug_info_init(&m->debug_info, heap_allocator()); - map_string_init(&m->entity_names, heap_allocator()); + map_init(&m->values, heap_allocator()); + map_init(&m->members, heap_allocator()); + map_init(&m->debug_info, heap_allocator()); + map_init(&m->entity_names, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); array_init(&m->foreign_library_paths, heap_allocator()); @@ -6861,7 +6852,7 @@ void ir_init_module(irModule *m, Checker *c) { { isize max_index = -1; for_array(type_info_map_index, m->info->type_info_map.entries) { - MapIsizeEntry *entry = &m->info->type_info_map.entries[type_info_map_index]; + auto *entry = &m->info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = ir_type_info_index(m->info, t); @@ -6876,7 +6867,7 @@ void ir_init_module(irModule *m, Checker *c) { irValue *g = ir_value_global(m->allocator, e, NULL); g->Global.is_private = true; ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); ir_global_type_info_data = g; } @@ -6886,7 +6877,7 @@ void ir_init_module(irModule *m, Checker *c) { isize count = 0; for_array(entry_index, m->info->type_info_map.entries) { - MapIsizeEntry *entry = &m->info->type_info_map.entries[entry_index]; + auto *entry = &m->info->type_info_map.entries[entry_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; switch (t->kind) { @@ -6914,7 +6905,7 @@ void ir_init_module(irModule *m, Checker *c) { make_type_array(m->allocator, t_type_info_ptr, count), false); irValue *g = ir_value_global(m->allocator, e, NULL); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); ir_global_type_info_member_types = g; } { @@ -6923,7 +6914,7 @@ void ir_init_module(irModule *m, Checker *c) { make_type_array(m->allocator, t_string, count), false); irValue *g = ir_value_global(m->allocator, e, NULL); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); ir_global_type_info_member_names = g; } { @@ -6932,7 +6923,7 @@ void ir_init_module(irModule *m, Checker *c) { make_type_array(m->allocator, t_int, count), false); irValue *g = ir_value_global(m->allocator, e, NULL); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); ir_global_type_info_member_offsets = g; } @@ -6942,7 +6933,7 @@ void ir_init_module(irModule *m, Checker *c) { make_type_array(m->allocator, t_bool, count), false); irValue *g = ir_value_global(m->allocator, e, NULL); ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); ir_global_type_info_member_usings = g; } } @@ -6953,15 +6944,15 @@ void ir_init_module(irModule *m, Checker *c) { di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file di->CompileUnit.producer = str_lit("odin"); - map_ir_debug_info_set(&m->debug_info, hash_pointer(m), di); + map_set(&m->debug_info, hash_pointer(m), di); } } void ir_destroy_module(irModule *m) { - map_ir_value_destroy(&m->values); - map_ir_value_destroy(&m->members); - map_string_destroy(&m->entity_names); - map_ir_debug_info_destroy(&m->debug_info); + map_destroy(&m->values); + map_destroy(&m->members); + map_destroy(&m->entity_names); + map_destroy(&m->debug_info); array_free(&m->procs); array_free(&m->procs_to_generate); array_free(&m->foreign_library_paths); @@ -7089,7 +7080,7 @@ void ir_gen_tree(irGen *s) { bool has_win_main = false; for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries[i]; + auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; String name = e->token.string; if (e->kind == Entity_Variable) { @@ -7121,7 +7112,7 @@ void ir_gen_tree(irGen *s) { m->min_dep_map = generate_minimum_dependency_map(info, entry_point); for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries[i]; + auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; DeclInfo *decl = entry->value; @@ -7131,7 +7122,7 @@ void ir_gen_tree(irGen *s) { continue; } - if (map_entity_get(&m->min_dep_map, hash_pointer(e)) == NULL) { + if (map_get(&m->min_dep_map, hash_pointer(e)) == NULL) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } @@ -7145,7 +7136,7 @@ void ir_gen_tree(irGen *s) { name = ir_mangle_name(s, e->token.pos.file, e); } } - map_string_set(&m->entity_names, hash_pointer(e), name); + map_set(&m->entity_names, hash_pointer(e), name); switch (e->kind) { case Entity_TypeName: @@ -7183,7 +7174,7 @@ void ir_gen_tree(irGen *s) { } ir_module_add_value(m, e, g); - map_ir_value_set(&m->members, hash_string(name), g); + map_set(&m->members, hash_string(name), g); } break; case Entity_Procedure: { @@ -7207,15 +7198,15 @@ void ir_gen_tree(irGen *s) { ir_module_add_value(m, e, p); HashKey hash_name = hash_string(name); - if (map_ir_value_get(&m->members, hash_name) == NULL) { - map_ir_value_multi_insert(&m->members, hash_name, p); + if (map_get(&m->members, hash_name) == NULL) { + multi_map_insert(&m->members, hash_name, p); } } break; } } for_array(i, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries[i]; + auto *entry = &m->members.entries[i]; irValue *v = entry->value; if (v->kind == irValue_Proc) { ir_build_proc(v, NULL); @@ -7228,7 +7219,7 @@ void ir_gen_tree(irGen *s) { isize all_proc_max_count = 0; for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; + auto *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; di->id = i; if (di->kind == irDebugInfo_Proc) { @@ -7237,12 +7228,12 @@ void ir_gen_tree(irGen *s) { } array_init(&all_procs->AllProcs.procs, m->allocator, all_proc_max_count); - map_ir_debug_info_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped + map_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped compile_unit->CompileUnit.all_procs = all_procs; for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; + auto *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; if (di->kind == irDebugInfo_Proc) { array_add(&all_procs->AllProcs.procs, di); @@ -7279,8 +7270,8 @@ void ir_gen_tree(irGen *s) { Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name); - map_ir_value_set(&m->values, hash_pointer(e), p); - map_ir_value_set(&m->members, hash_string(name), p); + map_set(&m->values, hash_pointer(e), p); + map_set(&m->members, hash_string(name), p); irProcedure *proc = &p->Proc; proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? @@ -7300,7 +7291,7 @@ void ir_gen_tree(irGen *s) { { String main_name = str_lit("main"); - irValue **found = map_ir_value_get(&m->members, hash_string(main_name)); + irValue **found = map_get(&m->members, hash_string(main_name)); if (found != NULL) { ir_emit_call(proc, *found, NULL, 0); } else { @@ -7350,8 +7341,8 @@ void ir_gen_tree(irGen *s) { m->entry_point_entity = e; - map_ir_value_set(&m->values, hash_pointer(e), p); - map_ir_value_set(&m->members, hash_string(name), p); + map_set(&m->values, hash_pointer(e), p); + map_set(&m->members, hash_string(name), p); irProcedure *proc = &p->Proc; proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? @@ -7373,8 +7364,8 @@ void ir_gen_tree(irGen *s) { Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name); - map_ir_value_set(&m->values, hash_pointer(e), p); - map_ir_value_set(&m->members, hash_string(name), p); + map_set(&m->values, hash_pointer(e), p); + map_set(&m->members, hash_string(name), p); irProcedure *proc = &p->Proc; @@ -7452,7 +7443,7 @@ void ir_gen_tree(irGen *s) { i32 type_info_member_offsets_index = 0; for_array(type_info_map_index, info->type_info_map.entries) { - MapIsizeEntry *entry = &info->type_info_map.entries[type_info_map_index]; + auto *entry = &info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = ir_type_info_index(info, t); @@ -7915,7 +7906,7 @@ void ir_gen_tree(irGen *s) { } for_array(type_info_map_index, info->type_info_map.entries) { - MapIsizeEntry *entry = &info->type_info_map.entries[type_info_map_index]; + auto *entry = &info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; t = default_type(t); isize entry_index = entry->value; @@ -7934,7 +7925,7 @@ void ir_gen_tree(irGen *s) { // Number debug info for_array(i, m->debug_info.entries) { - MapIrDebugInfoEntry *entry = &m->debug_info.entries[i]; + auto *entry = &m->debug_info.entries[i]; irDebugInfo *di = entry->value; di->id = i; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 823960352..cc008f4a1 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -306,7 +306,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { case Type_Named: if (is_type_struct(t) || is_type_union(t)) { - String *name = map_string_get(&m->entity_names, hash_pointer(t->Named.type_name)); + String *name = map_get(&m->entity_names, hash_pointer(t->Named.type_name)); GB_ASSERT_MSG(name != NULL, "%.*s", LIT(t->Named.name)); ir_print_encoded_local(f, *name); } else { @@ -1523,7 +1523,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (proc->entity != NULL) { if (proc->body != NULL) { - irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity)); + irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity)); if (di_ != NULL) { irDebugInfo *di = *di_; GB_ASSERT(di->kind == irDebugInfo_Proc); @@ -1606,7 +1606,7 @@ void print_llvm_ir(irGen *ir) { for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries[member_index]; + auto *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_TypeName) { continue; @@ -1619,7 +1619,7 @@ void print_llvm_ir(irGen *ir) { bool dll_main_found = false; for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries[member_index]; + auto *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Proc) { continue; @@ -1631,7 +1631,7 @@ void print_llvm_ir(irGen *ir) { } for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries[member_index]; + auto *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Proc) { continue; @@ -1643,7 +1643,7 @@ void print_llvm_ir(irGen *ir) { } for_array(member_index, m->members.entries) { - MapIrValueEntry *entry = &m->members.entries[member_index]; + auto *entry = &m->members.entries[member_index]; irValue *v = entry->value; if (v->kind != irValue_Global) { continue; @@ -1713,7 +1713,7 @@ void print_llvm_ir(irGen *ir) { switch (di->kind) { case irDebugInfo_CompileUnit: { - irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); + irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); ir_fprintf(f, "distinct !DICompileUnit(" "language: DW_LANG_Go, " // Is this good enough? diff --git a/src/map.cpp b/src/map.cpp index f03e83424..d45d2bccb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,38 +1,30 @@ -/* - Example of usage: - - #define MAP_TYPE String - #define MAP_PROC map_string_ - #define MAP_NAME MapString - #include "map.cpp" -*/ // A `Map` is an unordered hash table which can allow for a key to point to multiple values // with the use of the `multi_*` procedures. -// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out +// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out #ifndef MAP_UTIL_STUFF #define MAP_UTIL_STUFF // NOTE(bill): This util stuff is the same for every `Map` -typedef struct MapFindResult { +struct MapFindResult { isize hash_index; isize entry_prev; isize entry_index; -} MapFindResult; +}; -typedef enum HashKeyKind { +enum HashKeyKind { HashKey_Default, HashKey_String, HashKey_Pointer, -} HashKeyKind; +}; -typedef struct HashKey { +struct HashKey { HashKeyKind kind; u64 key; union { String string; // if String, s.len > 0 void * ptr; }; -} HashKey; +}; gb_inline HashKey hashing_proc(void const *data, isize len) { HashKey h = {HashKey_Default}; @@ -73,75 +65,75 @@ bool hash_key_equal(HashKey a, HashKey b) { } return false; } -#endif - -#define _J2_IND(a, b) a##b -#define _J2(a, b) _J2_IND(a, b) +bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); } +bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); } -/* -MAP_TYPE - Entry type -MAP_PROC - Function prefix (e.g. entity_map_) -MAP_NAME - Name of Map (e.g. EntityMap) -*/ -#define MAP_ENTRY _J2(MAP_NAME,Entry) +#endif -typedef struct MAP_ENTRY { +template +struct MapEntry { HashKey key; isize next; - MAP_TYPE value; -} MAP_ENTRY; - -typedef struct MAP_NAME { - Array hashes; - Array entries; -} MAP_NAME; - -void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a); -void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity); -void _J2(MAP_PROC,destroy) (MAP_NAME *h); -MAP_TYPE *_J2(MAP_PROC,get) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,set) (MAP_NAME *h, HashKey key, MAP_TYPE value); -void _J2(MAP_PROC,remove) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,clear) (MAP_NAME *h); -void _J2(MAP_PROC,grow) (MAP_NAME *h); -void _J2(MAP_PROC,rehash) (MAP_NAME *h, isize new_count); + T value; +}; + +template +struct Map { + Array hashes; + Array > entries; +}; + + +template void map_init (Map *h, gbAllocator a); +template void map_init_with_reserve(Map *h, gbAllocator a, isize capacity); +template void map_destroy (Map *h); +template T * map_get (Map *h, HashKey key); +template void map_set (Map *h, HashKey key, T const &value); +template void map_remove (Map *h, HashKey key); +template void map_clear (Map *h); +template void map_grow (Map *h); +template void map_rehash (Map *h, isize new_count); // Mutlivalued map procedure -MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key); -MAP_ENTRY *_J2(MAP_PROC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e); - -isize _J2(MAP_PROC,multi_count) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,multi_get_all) (MAP_NAME *h, HashKey key, MAP_TYPE *items); -void _J2(MAP_PROC,multi_insert) (MAP_NAME *h, HashKey key, MAP_TYPE value); -void _J2(MAP_PROC,multi_remove) (MAP_NAME *h, HashKey key, MAP_ENTRY *e); -void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key); +template MapEntry * multi_map_find_first(Map *h, HashKey key); +template MapEntry * multi_map_find_next (Map *h, MapEntry *e); +template isize multi_map_count (Map *h, HashKey key); +template void multi_map_get_all (Map *h, HashKey key, T *items); +template void multi_map_insert (Map *h, HashKey key, T const &value); +template void multi_map_remove (Map *h, HashKey key, MapEntry *e); +template void multi_map_remove_all(Map *h, HashKey key); -gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) { +template +gb_inline void map_init(Map *h, gbAllocator a) { array_init(&h->hashes, a); array_init(&h->entries, a); } -gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) { +template +gb_inline void map_init_with_reserve(Map *h, gbAllocator a, isize capacity) { array_init(&h->hashes, a, capacity); array_init(&h->entries, a, capacity); } -gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) { +template +gb_inline void map_destroy(Map *h) { array_free(&h->entries); array_free(&h->hashes); } -gb_internal isize _J2(MAP_PROC,_add_entry)(MAP_NAME *h, HashKey key) { - MAP_ENTRY e = {}; +template +gb_internal isize map__add_entry(Map *h, HashKey key) { + MapEntry e = {}; e.key = key; e.next = -1; array_add(&h->entries, e); return h->entries.count-1; } -gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) { +template +gb_internal MapFindResult map__find(Map *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = key.key % h->hashes.count; @@ -157,7 +149,8 @@ gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) { return fr; } -gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY *e) { +template +gb_internal MapFindResult map__find_from_entry(Map *h, MapEntry *e) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = e->key.key % h->hashes.count; @@ -173,33 +166,35 @@ gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY return fr; } - -gb_internal b32 _J2(MAP_PROC,_full)(MAP_NAME *h) { +template +gb_internal b32 map__full(Map *h) { return 0.75f * h->hashes.count <= h->entries.count; } -gb_inline void _J2(MAP_PROC,grow)(MAP_NAME *h) { +template +gb_inline void map_grow(Map *h) { isize new_count = ARRAY_GROW_FORMULA(h->entries.count); - _J2(MAP_PROC,rehash)(h, new_count); + map_rehash(h, new_count); } -void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { +template +void map_rehash(Map *h, isize new_count) { isize i, j; - MAP_NAME nh = {}; - _J2(MAP_PROC,init)(&nh, h->hashes.allocator); + Map nh = {}; + map_init(&nh, h->hashes.allocator); array_resize(&nh.hashes, new_count); array_reserve(&nh.entries, h->entries.count); for (i = 0; i < new_count; i++) { nh.hashes[i] = -1; } for (i = 0; i < h->entries.count; i++) { - MAP_ENTRY *e = &h->entries[i]; + MapEntry *e = &h->entries[i]; MapFindResult fr; if (nh.hashes.count == 0) { - _J2(MAP_PROC,grow)(&nh); + map_grow(&nh); } - fr = _J2(MAP_PROC,_find)(&nh, e->key); - j = _J2(MAP_PROC,_add_entry)(&nh, e->key); + fr = map__find(&nh, e->key); + j = map__add_entry(&nh, e->key); if (fr.entry_prev < 0) { nh.hashes[fr.hash_index] = j; } else { @@ -207,32 +202,34 @@ void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { } nh.entries[j].next = fr.entry_index; nh.entries[j].value = e->value; - if (_J2(MAP_PROC,_full)(&nh)) { - _J2(MAP_PROC,grow)(&nh); + if (map__full(&nh)) { + map_grow(&nh); } } - _J2(MAP_PROC,destroy)(h); + map_destroy(h); *h = nh; } -gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) { - isize index = _J2(MAP_PROC,_find)(h, key).entry_index; +template +gb_inline T *map_get(Map *h, HashKey key) { + isize index = map__find(h, key).entry_index; if (index >= 0) { return &h->entries[index].value; } return NULL; } -void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { +template +void map_set(Map *h, HashKey key, T const &value) { isize index; MapFindResult fr; if (h->hashes.count == 0) - _J2(MAP_PROC,grow)(h); - fr = _J2(MAP_PROC,_find)(h, key); + map_grow(h); + fr = map__find(h, key); if (fr.entry_index >= 0) { index = fr.entry_index; } else { - index = _J2(MAP_PROC,_add_entry)(h, key); + index = map__add_entry(h, key); if (fr.entry_prev >= 0) { h->entries[fr.entry_prev].next = index; } else { @@ -241,14 +238,14 @@ void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { } h->entries[index].value = value; - if (_J2(MAP_PROC,_full)(h)) { - _J2(MAP_PROC,grow)(h); + if (map__full(h)) { + map_grow(h); } } - -void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { +template +void map__erase(Map *h, MapFindResult fr) { MapFindResult last; if (fr.entry_prev < 0) { h->hashes[fr.hash_index] = h->entries[fr.entry_index].next; @@ -260,7 +257,7 @@ void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { return; } h->entries[fr.entry_index] = h->entries[h->entries.count-1]; - last = _J2(MAP_PROC,_find)(h, h->entries[fr.entry_index].key); + last = map__find(h, h->entries[fr.entry_index].key); if (last.entry_prev >= 0) { h->entries[last.entry_prev].next = fr.entry_index; } else { @@ -268,29 +265,33 @@ void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { } } -void _J2(MAP_PROC,remove)(MAP_NAME *h, HashKey key) { - MapFindResult fr = _J2(MAP_PROC,_find)(h, key); +template +void map_remove(Map *h, HashKey key) { + MapFindResult fr = map__find(h, key); if (fr.entry_index >= 0) { - _J2(MAP_PROC,_erase)(h, fr); + map__erase(h, fr); } } -gb_inline void _J2(MAP_PROC,clear)(MAP_NAME *h) { +template +gb_inline void map_clear(Map *h) { array_clear(&h->hashes); array_clear(&h->entries); } #if 1 -MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) { - isize i = _J2(MAP_PROC,_find)(h, key).entry_index; +template +MapEntry *multi_map_find_first(Map *h, HashKey key) { + isize i = map__find(h, key).entry_index; if (i < 0) { return NULL; } return &h->entries[i]; } -MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) { +template +MapEntry *multi_map_find_next(Map *h, MapEntry *e) { isize i = e->next; while (i >= 0) { if (hash_key_equal(h->entries[i].key, e->key)) { @@ -301,34 +302,37 @@ MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) { return NULL; } -isize _J2(MAP_PROC,multi_count)(MAP_NAME *h, HashKey key) { +template +isize multi_map_count(Map *h, HashKey key) { isize count = 0; - MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key); + MapEntry *e = multi_map_find_first(h, key); while (e != NULL) { count++; - e = _J2(MAP_PROC,multi_find_next)(h, e); + e = multi_map_find_next(h, e); } return count; } -void _J2(MAP_PROC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) { +template +void multi_map_get_all(Map *h, HashKey key, T *items) { isize i = 0; - MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key); + MapEntry *e = multi_map_find_first(h, key); while (e != NULL) { items[i++] = e->value; - e = _J2(MAP_PROC,multi_find_next)(h, e); + e = multi_map_find_next(h, e); } } -void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) { +template +void multi_map_insert(Map *h, HashKey key, T const &value) { MapFindResult fr; isize i; if (h->hashes.count == 0) { - _J2(MAP_PROC,grow)(h); + map_grow(h); } // Make - fr = _J2(MAP_PROC,_find)(h, key); - i = _J2(MAP_PROC,_add_entry)(h, key); + fr = map__find(h, key); + i = map__add_entry(h, key); if (fr.entry_prev < 0) { h->hashes[fr.hash_index] = i; } else { @@ -337,28 +341,23 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) { h->entries[i].next = fr.entry_index; h->entries[i].value = value; // Grow if needed - if (_J2(MAP_PROC,_full)(h)) { - _J2(MAP_PROC,grow)(h); + if (map__full(h)) { + map_grow(h); } } -void _J2(MAP_PROC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) { - MapFindResult fr = _J2(MAP_PROC,_find_from_entry)(h, e); +template +void multi_map_remove(Map *h, HashKey key, MapEntry *e) { + MapFindResult fr = map__find_from_entry(h, e); if (fr.entry_index >= 0) { - _J2(MAP_PROC,_erase)(h, fr); + map__erase(h, fr); } } -void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key) { - while (_J2(MAP_PROC,get)(h, key) != NULL) { - _J2(MAP_PROC,remove)(h, key); +template +void multi_map_remove_all(Map *h, HashKey key) { + while (map_get(h, key) != NULL) { + map_remove(h, key); } } #endif - - -#undef _J2 -#undef MAP_TYPE -#undef MAP_PROC -#undef MAP_NAME -#undef MAP_ENTRY diff --git a/src/ssa.cpp b/src/ssa.cpp index 010d11e6c..b9ed4e75a 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -14,10 +14,6 @@ enum ssaDeferExitKind; String ssa_mangle_name(ssaModule *m, String path, Entity *e); -#define MAP_TYPE ssaValue * -#define MAP_PROC map_ssa_value_ -#define MAP_NAME MapSsaValue -#include "map.cpp" #include "ssa_op.cpp" @@ -148,7 +144,7 @@ struct ssaProc { i32 block_id; i32 value_id; - MapSsaValue values; // Key: Entity * + Map values; // Key: Entity * Array defer_stmts; i32 scope_level; @@ -166,8 +162,8 @@ struct ssaModule { gbAllocator tmp_allocator; gbArena tmp_arena; - MapEntity min_dep_map; // Key: Entity * - MapSsaValue values; // Key: Entity * + Map min_dep_map; // Key: Entity * + Map values; // Key: Entity * // List of registers for the specific architecture Array registers; @@ -584,7 +580,7 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_ array_init(&p->blocks, heap_allocator()); array_init(&p->defer_stmts, heap_allocator()); - map_ssa_value_init(&p->values, heap_allocator()); + map_init(&p->values, heap_allocator()); return p; } @@ -597,14 +593,14 @@ ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { ssaValue *local = ssa_new_value0(p, ssaOp_Local, t); p->curr_block = cb; - map_ssa_value_set(&p->values, hash_pointer(e), local); - map_ssa_value_set(&p->module->values, hash_pointer(e), local); + map_set(&p->values, hash_pointer(e), local); + map_set(&p->module->values, hash_pointer(e), local); local->comment_string = e->token.string; ssa_new_value1(p, ssaOp_Zero, t, local); return ssa_addr(local); } ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) { - Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name)); + Entity **found = map_get(&p->module->info->definitions, hash_pointer(name)); if (found) { Entity *e = *found; return ssa_add_local(p, e, name); @@ -710,7 +706,7 @@ ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) { Entity *parent = e->using_parent; Selection sel = lookup_field(p->allocator, parent->type, name, false); GB_ASSERT(sel.entity != NULL); - ssaValue **pv = map_ssa_value_get(&p->module->values, hash_pointer(parent)); + ssaValue **pv = map_get(&p->module->values, hash_pointer(parent)); ssaValue *v = NULL; if (pv != NULL) { v = *pv; @@ -726,7 +722,7 @@ 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)); + ssaValue **found = map_get(&p->module->values, hash_pointer(e)); if (found) { v = *found; } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { @@ -1690,7 +1686,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { case_end; case_ast_node(i, Ident, expr); - Entity *e = *map_entity_get(&p->module->info->uses, hash_pointer(expr)); + Entity *e = *map_get(&p->module->info->uses, hash_pointer(expr)); if (e->kind == Entity_Builtin) { Token token = ast_node_token(expr); GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n" @@ -1702,7 +1698,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { return NULL; } - ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e)); + ssaValue **found = map_get(&p->module->values, hash_pointer(e)); if (found) { ssaValue *v = *found; if (v->op == ssaOp_Proc) { @@ -1840,7 +1836,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { case_ast_node(ce, CallExpr, expr); - if (map_tav_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { + if (map_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) { GB_ASSERT(ce->args.count == 1); ssaValue *x = ssa_build_expr(p, ce->args[0]); return ssa_emit_conv(p, x, tv.type); @@ -2484,7 +2480,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { m.tmp_allocator = gb_arena_allocator(&m.tmp_arena); m.allocator = gb_arena_allocator(&m.arena); - map_ssa_value_init(&m.values, heap_allocator()); + map_init(&m.values, heap_allocator()); array_init(&m.registers, heap_allocator()); array_init(&m.procs, heap_allocator()); array_init(&m.procs_to_generate, heap_allocator()); @@ -2496,7 +2492,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { bool has_win_main = false; for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries[i]; + auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; String name = e->token.string; if (e->kind == Entity_Variable) { @@ -2522,7 +2518,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { m.min_dep_map = generate_minimum_dependency_map(info, entry_point); for_array(i, info->entities.entries) { - MapDeclInfoEntry *entry = &info->entities.entries[i]; + auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; DeclInfo *decl = entry->value; @@ -2532,7 +2528,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { continue; } - if (map_entity_get(&m.min_dep_map, hash_pointer(e)) == NULL) { + if (map_get(&m.min_dep_map, hash_pointer(e)) == NULL) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } @@ -2579,8 +2575,8 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { // ssa_module_add_value(m, e, p); // HashKey hash_name = hash_string(name); - // if (map_ssa_value_get(&m.members, hash_name) == NULL) { - // map_ssa_value_set(&m.members, hash_name, p); + // if (map_get(&m.members, hash_name) == NULL) { + // map_set(&m.members, hash_name, p); // } } break; } @@ -2600,7 +2596,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e) { String name = e->token.string; CheckerInfo *info = m->info; gbAllocator a = m->allocator; - AstFile *file = *map_ast_file_get(&info->files, hash_string(path)); + AstFile *file = *map_get(&info->files, hash_string(path)); char *str = gb_alloc_array(a, char, path.len+1); gb_memmove(str, path.text, path.len); -- cgit v1.2.3 From af2736daec0e6579a006bd8d4567c977c8e56c45 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 8 Jun 2017 16:29:05 +0100 Subject: Fix bit field bug --- src/exact_value.cpp | 55 ++++++++++++++++++++++++++--------------------------- src/integer128.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++--- src/ir.cpp | 6 ++++-- 3 files changed, 78 insertions(+), 33 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/exact_value.cpp b/src/exact_value.cpp index b3d4e9f4f..ff740a057 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -317,7 +317,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) return v; case ExactValue_Integer: { ExactValue i = v; - i.value_integer = i128_neg(i.value_integer); + i.value_integer = -i.value_integer; return i; } case ExactValue_Float: { @@ -339,7 +339,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) case ExactValue_Invalid: return v; case ExactValue_Integer: - i = i128_not(v.value_integer); + i = ~v.value_integer; break; default: goto failure; @@ -349,7 +349,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) // limited to the types precision // IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored if (0 < precision && precision < 128) { - i = i128_and(i, i128_not(i128_shl(I128_NEG_ONE, precision))); + i = i & ~(I128_NEG_ONE << precision); } return exact_value_i128(i); @@ -461,19 +461,19 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) i128 b = y.value_integer; i128 c = I128_ZERO; switch (op) { - case Token_Add: c = i128_add(a, b); break; - case Token_Sub: c = i128_sub(a, b); break; - case Token_Mul: c = i128_mul(a, b); break; + case Token_Add: c = a + b; break; + case Token_Sub: c = a - b; break; + case Token_Mul: c = a * b; break; case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b))); - case Token_QuoEq: c = i128_quo(a, b); break; // NOTE(bill): Integer division - case Token_Mod: c = i128_mod(a, b); break; - case Token_ModMod: c = i128_mod(i128_add(i128_mod(a, b), b), b); break; - case Token_And: c = i128_and (a, b); break; - case Token_Or: c = i128_or (a, b); break; - case Token_Xor: c = i128_xor (a, b); break; - case Token_AndNot: c = i128_and_not(a, b); break; - case Token_Shl: c = i128_shl (a, i128_to_u64(b)); break; - case Token_Shr: c = i128_shr (a, i128_to_u64(b)); break; + case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division + case Token_Mod: c = a % b; break; + case Token_ModMod: c = ((a % b) + b) % b; break; + case Token_And: c = a & b; break; + case Token_Or: c = a | b; break; + case Token_Xor: c = a ^ b; break; + case Token_AndNot: c = i128_and_not(a, b); break; + case Token_Shl: c = a << i128_to_u64(b); break; + case Token_Shr: c = a >> i128_to_u64(b); break; default: goto error; } @@ -560,12 +560,12 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { i128 a = x.value_integer; i128 b = y.value_integer; switch (op) { - case Token_CmpEq: return i128_eq(a, b); - case Token_NotEq: return i128_ne(a, b); - case Token_Lt: return i128_lt(a, b); - case Token_LtEq: return i128_le(a, b); - case Token_Gt: return i128_gt(a, b); - case Token_GtEq: return i128_ge(a, b); + case Token_CmpEq: return a == b; + case Token_NotEq: return a != b; + case Token_Lt: return a < b; + case Token_LtEq: return a <= b; + case Token_Gt: return a > b; + case Token_GtEq: return a >= b; } } break; @@ -596,15 +596,14 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { case ExactValue_String: { String a = x.value_string; String b = y.value_string; - isize len = gb_min(a.len, b.len); // TODO(bill): gb_memcompare is used because the strings are UTF-8 switch (op) { - case Token_CmpEq: return gb_memcompare(a.text, b.text, len) == 0; - case Token_NotEq: return gb_memcompare(a.text, b.text, len) != 0; - case Token_Lt: return gb_memcompare(a.text, b.text, len) < 0; - case Token_LtEq: return gb_memcompare(a.text, b.text, len) <= 0; - case Token_Gt: return gb_memcompare(a.text, b.text, len) > 0; - case Token_GtEq: return gb_memcompare(a.text, b.text, len) >= 0; + case Token_CmpEq: return a == b; + case Token_NotEq: return a != b; + case Token_Lt: return a < b; + case Token_LtEq: return a <= b; + case Token_Gt: return a > b; + case Token_GtEq: return a >= b; } } break; } diff --git a/src/integer128.cpp b/src/integer128.cpp index 39d834ab3..73cd1c7a0 100644 --- a/src/integer128.cpp +++ b/src/integer128.cpp @@ -1,10 +1,12 @@ -typedef struct u128 {u64 lo; u64 hi;} u128; -typedef struct i128 {u64 lo; i64 hi;} i128; - #define BIT128_U64_HIGHBIT 0x8000000000000000ull #define BIT128_U64_BITS62 0x7fffffffffffffffull #define BIT128_U64_ALLBITS 0xffffffffffffffffull + +typedef struct u128 { u64 lo; u64 hi; } u128; +typedef struct i128 { u64 lo; i64 hi; } i128; + + static u128 const U128_ZERO = {0, 0}; static u128 const U128_ONE = {1, 0}; static i128 const I128_ZERO = {0, 0}; @@ -84,6 +86,48 @@ void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem); i128 i128_quo (i128 a, i128 b); i128 i128_mod (i128 a, i128 b); +bool operator==(u128 a, u128 b) { return u128_eq(a, b); } +bool operator!=(u128 a, u128 b) { return u128_ne(a, b); } +bool operator< (u128 a, u128 b) { return u128_lt(a, b); } +bool operator> (u128 a, u128 b) { return u128_gt(a, b); } +bool operator<=(u128 a, u128 b) { return u128_le(a, b); } +bool operator>=(u128 a, u128 b) { return u128_ge(a, b); } + +u128 operator+(u128 a, u128 b) { return u128_add(a, b); } +u128 operator-(u128 a, u128 b) { return u128_sub(a, b); } +u128 operator*(u128 a, u128 b) { return u128_mul(a, b); } +u128 operator/(u128 a, u128 b) { return u128_quo(a, b); } +u128 operator%(u128 a, u128 b) { return u128_mod(a, b); } +u128 operator&(u128 a, u128 b) { return u128_and(a, b); } +u128 operator|(u128 a, u128 b) { return u128_or (a, b); } +u128 operator^(u128 a, u128 b) { return u128_xor(a, b); } +u128 operator~(u128 a) { return u128_not(a); } +u128 operator+(u128 a) { return a; } +u128 operator-(u128 a) { return u128_neg(a); } +u128 operator<<(u128 a, u32 b) { return u128_shl(a, b); } +u128 operator>>(u128 a, u32 b) { return u128_shr(a, b); } + + +bool operator==(i128 a, i128 b) { return i128_eq(a, b); } +bool operator!=(i128 a, i128 b) { return i128_ne(a, b); } +bool operator< (i128 a, i128 b) { return i128_lt(a, b); } +bool operator> (i128 a, i128 b) { return i128_gt(a, b); } +bool operator<=(i128 a, i128 b) { return i128_le(a, b); } +bool operator>=(i128 a, i128 b) { return i128_ge(a, b); } + +i128 operator+(i128 a, i128 b) { return i128_add(a, b); } +i128 operator-(i128 a, i128 b) { return i128_sub(a, b); } +i128 operator*(i128 a, i128 b) { return i128_mul(a, b); } +i128 operator/(i128 a, i128 b) { return i128_quo(a, b); } +i128 operator%(i128 a, i128 b) { return i128_mod(a, b); } +i128 operator&(i128 a, i128 b) { return i128_and(a, b); } +i128 operator|(i128 a, i128 b) { return i128_or (a, b); } +i128 operator^(i128 a, i128 b) { return i128_xor(a, b); } +i128 operator~(i128 a) { return i128_not(a); } +i128 operator+(i128 a) { return a; } +i128 operator-(i128 a) { return i128_neg(a); } +i128 operator<<(i128 a, u32 b) { return i128_shl(a, b); } +i128 operator>>(i128 a, u32 b) { return i128_shr(a, b); } //////////////////////////////////////////////////////////////// diff --git a/src/ir.cpp b/src/ir.cpp index e94f84e3b..bcea8a515 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1902,12 +1902,14 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { return v; } + GB_ASSERT(8 > bit_inset); + irValue *shift_amount = ir_value_constant(a, int_type, exact_value_i64(bit_inset)); irValue *first_byte = ir_emit_load(proc, bytes); - irValue *res = ir_emit_arith(proc, Token_Shr, first_byte, ir_const_int(a, 8 - bit_inset), int_type); + irValue *res = ir_emit_arith(proc, Token_Shr, first_byte, shift_amount, int_type); irValue *remaining_bytes = ir_emit_load(proc, ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), int_ptr)); - remaining_bytes = ir_emit_arith(proc, Token_Shl, remaining_bytes, ir_const_int(a, bit_inset), int_type); + remaining_bytes = ir_emit_arith(proc, Token_Shl, remaining_bytes, shift_amount, int_type); return ir_emit_arith(proc, Token_Or, res, remaining_bytes, int_type); } -- cgit v1.2.3 From b2fdb69b4dd7f52f42414139a257b3800eb51a90 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 11 Jun 2017 12:01:40 +0100 Subject: Named procedure calls --- src/check_decl.cpp | 6 +- src/check_expr.cpp | 317 +++++++++++++++++++++++++++++++++++++++------------- src/check_stmt.cpp | 2 +- src/checker.cpp | 6 +- src/common.cpp | 10 +- src/integer128.cpp | 59 +++++++++- src/ir.cpp | 41 ++++++- src/map.cpp | 7 +- src/murmurhash3.cpp | 39 ++++--- src/parser.cpp | 5 + src/ssa.cpp | 2 +- src/timings.cpp | 2 +- 12 files changed, 380 insertions(+), 116 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 28aa41b8e..57fb2c7f4 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex // TODO(bill): is this a good enough error message? // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use error_node(operand->expr, - "Cannot assign builtin procedure `%s` in %.*s", + "Cannot assign built-in procedure `%s` in %.*s", expr_str, LIT(context_name)); @@ -145,7 +145,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { // gb_printf_err("%.*s %p\n", LIT(e->token.string), e); - Type *bt = check_type_extra(c, type_expr, named); + Type *bt = check_type(c, type_expr, named); named->Named.base = base_type(bt); if (named->Named.base == t_invalid) { // gb_printf("check_type_decl: %s\n", type_to_string(named)); @@ -408,7 +408,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count e->flags |= EntityFlag_Visited; if (type_expr != NULL) { - e->type = check_type_extra(c, type_expr, NULL); + e->type = check_type(c, type_expr); } if (init_expr == NULL) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5043f9b38..d967ff504 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2,8 +2,7 @@ void check_expr (Checker *c, Operand *operand, AstNode * void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); -Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type); -Type * check_type (Checker *c, AstNode *expression); +Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint); void check_not_tuple (Checker *c, Operand *operand); @@ -22,11 +21,6 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type * Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call); -gb_inline Type *check_type(Checker *c, AstNode *expression) { - return check_type_extra(c, expression, NULL); -} - - void error_operand_not_expression(Operand *o) { if (o->mode == Addressing_Type) { gbString err = expr_to_string(o->expr); @@ -326,7 +320,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n // TODO(bill): is this a good enough error message? // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use error_node(operand->expr, - "Cannot assign builtin procedure `%s` in %.*s", + "Cannot assign built-in procedure `%s` in %.*s", expr_str, LIT(context_name)); } else { @@ -1605,8 +1599,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { ast_node(mt, MapType, node); i64 count = check_array_or_map_count(c, mt->count, true); - Type *key = check_type_extra(c, mt->key, NULL); - Type *value = check_type_extra(c, mt->value, NULL); + Type *key = check_type(c, mt->key); + Type *value = check_type(c, mt->value); if (!is_type_valid_for_keys(key)) { if (is_type_boolean(key)) { @@ -1702,7 +1696,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { // error_node(node, "`map` types are not yet implemented"); } -bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_type) { +bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) { GB_ASSERT_NOT_NULL(type); if (e == NULL) { *type = t_invalid; @@ -1759,7 +1753,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_end; case_ast_node(pe, ParenExpr, e); - *type = check_type_extra(c, pe->expr, named_type); + *type = check_type(c, pe->expr, named_type); return true; case_end; @@ -1794,7 +1788,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_ast_node(at, ArrayType, e); if (at->count != NULL) { - Type *elem = check_type_extra(c, at->elem, NULL); + Type *elem = check_type(c, at->elem, NULL); i64 count = check_array_or_map_count(c, at->count, false); if (count < 0) { error_node(at->count, ".. can only be used in conjuction with compound literals"); @@ -1825,7 +1819,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_end; case_ast_node(dat, DynamicArrayType, e); - Type *elem = check_type_extra(c, dat->elem, NULL); + Type *elem = check_type(c, dat->elem); i64 esz = type_size_of(c->allocator, elem); #if 0 if (esz == 0) { @@ -1934,9 +1928,9 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ -Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { +Type *check_type(Checker *c, AstNode *e, Type *named_type) { Type *type = NULL; - bool ok = check_type_extra_internal(c, e, &type, named_type); + bool ok = check_type_internal(c, e, &type, named_type); if (!ok) { gbString err_str = expr_to_string(e); @@ -3533,6 +3527,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } } + if (ce->args.count > 0) { + if (ce->args[0]->kind == AstNode_FieldValue) { + error_node(call, "`field = value` calling is not allowed on built-in procedures"); + return false; + } + } + + bool vari_expand = (ce->ellipsis.pos.line != 0); if (vari_expand && id != BuiltinProc_append) { error(ce->ellipsis, "Invalid use of `..` with built-in procedure `append`"); @@ -3556,7 +3558,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id switch (id) { default: - GB_PANIC("Implement builtin procedure: %.*s", LIT(builtin_procs[id].name)); + GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_procs[id].name)); break; case BuiltinProc_len: @@ -4707,6 +4709,10 @@ enum CallArgumentError { CallArgumentError_ArgumentCount, CallArgumentError_TooFewArguments, CallArgumentError_TooManyArguments, + CallArgumentError_InvalidFieldValue, + CallArgumentError_ParameterNotFound, + CallArgumentError_ParameterMissing, + CallArgumentError_DuplicateParameter, }; enum CallArgumentErrorMode { @@ -4714,8 +4720,59 @@ enum CallArgumentErrorMode { CallArgumentMode_ShowErrors, }; -CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, - CallArgumentErrorMode show_error_mode, i64 *score_) { + +struct ValidProcAndScore { + isize index; + i64 score; +}; + +int valid_proc_and_score_cmp(void const *a, void const *b) { + i64 si = (cast(ValidProcAndScore const *)a)->score; + i64 sj = (cast(ValidProcAndScore const *)b)->score; + return sj < si ? -1 : sj > si; +} + +bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, Array rhs, bool allow_ok) { + bool optional_ok = false; + for_array(i, rhs) { + Operand o = {}; + check_multi_expr(c, &o, rhs[i]); + + if (o.type == NULL || o.type->kind != Type_Tuple) { + if (allow_ok && lhs_count == 2 && rhs.count == 1 && + (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) { + Type *tuple = make_optional_ok_type(c->allocator, o.type); + add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); + + Operand val = o; + Operand ok = o; + val.mode = Addressing_Value; + ok.mode = Addressing_Value; + ok.type = t_bool; + array_add(operands, val); + array_add(operands, ok); + + optional_ok = true; + } else { + array_add(operands, o); + } + } else { + TypeTuple *tuple = &o.type->Tuple; + for (isize j = 0; j < tuple->variable_count; j++) { + o.type = tuple->variables[j]->type; + array_add(operands, o); + } + } + } + + return optional_ok; +} + +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array operands, CallArgumentErrorMode show_error_mode, i64 *score_) +typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); + + +CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { ast_node(ce, CallExpr, call); isize param_count = 0; bool variadic = proc_type->Proc.variadic; @@ -4740,15 +4797,15 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type return CallArgumentError_NonVariadicExpand; } - if (operand_count == 0 && param_count == 0) { + if (operands.count == 0 && param_count == 0) { if (score_) *score_ = score; return CallArgumentError_None; } i32 error_code = 0; - if (operand_count < param_count) { + if (operands.count < param_count) { error_code = -1; - } else if (!variadic && operand_count > param_count) { + } else if (!variadic && operands.count > param_count) { error_code = +1; } if (error_code != 0) { @@ -4795,7 +4852,7 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type GB_ASSERT(is_type_slice(slice)); Type *elem = base_type(slice)->Slice.elem; Type *t = elem; - for (; operand_index < operand_count; operand_index++) { + for (; operand_index < operands.count; operand_index++) { Operand o = operands[operand_index]; if (vari_expand) { variadic_expand = true; @@ -4823,61 +4880,136 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type return err; } -struct ValidProcAndScore { - isize index; - i64 score; -}; +bool is_call_expr_field_value(AstNodeCallExpr *ce) { + GB_ASSERT(ce != NULL); -int valid_proc_and_score_cmp(void const *a, void const *b) { - i64 si = (cast(ValidProcAndScore const *)a)->score; - i64 sj = (cast(ValidProcAndScore const *)b)->score; - return sj < si ? -1 : sj > si; + if (ce->args.count == 0) { + return false; + } + return ce->args[0]->kind == AstNode_FieldValue; } -bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, Array rhs, bool allow_ok) { - bool optional_ok = false; - for_array(i, rhs) { - Operand o = {}; - check_multi_expr(c, &o, rhs[i]); +isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { + isize param_count = pt->param_count; + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->params->Tuple.variables[i]; + String name = e->token.string; + if (name == "_") { + continue; + } + if (name == parameter_name) { + return i; + } + } + return -1; +} - if (o.type == NULL || o.type->kind != Type_Tuple) { - if (allow_ok && lhs_count == 2 && rhs.count == 1 && - (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) { - Type *tuple = make_optional_ok_type(c->allocator, o.type); - add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); +CALL_ARGUMENT_CHECKER(check_named_call_arguments) { + ast_node(ce, CallExpr, call); + GB_ASSERT(is_type_proc(proc_type)); + TypeProc *pt = &base_type(proc_type)->Proc; - Operand val = o; - Operand ok = o; - val.mode = Addressing_Value; - ok.mode = Addressing_Value; - ok.type = t_bool; - array_add(operands, val); - array_add(operands, ok); + i64 score = 0; + bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + CallArgumentError err = CallArgumentError_None; - optional_ok = true; - } else { - array_add(operands, o); + isize param_count = pt->param_count; + bool *params_visited = gb_alloc_array(c->allocator, bool, param_count); + + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + ast_node(fv, FieldValue, arg); + if (fv->field->kind != AstNode_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error_node(arg, "Invalid parameter name `%s` in procedure call", expr_str); + gb_string_free(expr_str); } - } else { - TypeTuple *tuple = &o.type->Tuple; - for (isize j = 0; j < tuple->variable_count; j++) { - o.type = tuple->variables[j]->type; - array_add(operands, o); + err = CallArgumentError_InvalidFieldValue; + continue; + } + String name = fv->field->Ident.string; + isize index = lookup_procedure_parameter(pt, name); + if (index < 0) { + if (show_error) { + error_node(arg, "No parameter named `%.*s` for this procedure type", LIT(name)); } + err = CallArgumentError_ParameterNotFound; + continue; } + if (params_visited[index]) { + if (show_error) { + error_node(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name)); + } + err = CallArgumentError_DuplicateParameter; + continue; + } + + params_visited[index] = true; + Operand *o = &operands[i]; + + Type *param_type = pt->params->Tuple.variables[index]->type; + + i64 s = 0; + if (!check_is_assignable_to_with_score(c, o, param_type, &s)) { + if (show_error) { + check_assignment(c, o, param_type, str_lit("procedure argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; } - return optional_ok; + +#if 1 + isize param_count_to_check = param_count; + if (pt->variadic) { + param_count_to_check--; + } + for (isize i = 0; i < param_count_to_check; i++) { + if (!params_visited[i]) { + if (show_error) { + Entity *e = pt->params->Tuple.variables[i]; + gbString str = type_to_string(e->type); + error_node(call, "Parameter `%.*s` of type `%s` is missing in procedure call", + LIT(e->token.string), str); + gb_string_free(str); + } + err = CallArgumentError_ParameterMissing; + } + } +#endif + + if (score_) *score_ = score; + + return err; } -Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { - GB_ASSERT(call->kind == AstNode_CallExpr); +Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { ast_node(ce, CallExpr, call); - Array operands; - array_init(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, -1, &operands, ce->args, false); + CallArgumentCheckerType *call_checker = NULL; + Array operands = {}; + defer (array_free(&operands)); + + if (is_call_expr_field_value(ce)) { + call_checker = check_named_call_arguments; + + array_init_count(&operands, heap_allocator(), ce->args.count); + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + ast_node(fv, FieldValue, arg); + check_expr(c, &operands[i], fv->value); + } + } else { + call_checker = check_call_arguments_internal; + + array_init(&operands, heap_allocator(), 2*ce->args.count); + check_unpack_arguments(c, -1, &operands, ce->args, false); + } + + GB_ASSERT(call_checker != NULL); if (operand->mode == Addressing_Overload) { GB_ASSERT(operand->overload_entities != NULL && @@ -4888,6 +5020,9 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count); isize valid_count = 0; + defer (gb_free(heap_allocator(), procs)); + defer (gb_free(heap_allocator(), valids)); + String name = procs[0]->token.string; for (isize i = 0; i < overload_count; i++) { @@ -4903,7 +5038,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod Type *proc_type = base_type(p->type); if (proc_type != NULL && is_type_proc(proc_type)) { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_NoErrors, &score); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_NoErrors, &score); if (err == CallArgumentError_None) { valids[valid_count].index = i; valids[valid_count].score = score; @@ -4948,16 +5083,14 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod add_entity_use(c, expr, e); proc_type = e->type; i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); } - - gb_free(heap_allocator(), valids); - gb_free(heap_allocator(), procs); } else { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); - array_free(&operands); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); } + + return proc_type; } @@ -4990,9 +5123,37 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { ast_node(ce, CallExpr, call); check_expr_or_type(c, operand, ce->proc); + if (ce->args.count > 0) { + bool fail = false; + bool first_is_field_value = (ce->args[0]->kind == AstNode_FieldValue); + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != AstNode_FieldValue; + } else { + mix = arg->kind == AstNode_FieldValue; + } + if (mix) { + error_node(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed"); + fail = true; + } + } + + if (fail) { + operand->mode = Addressing_Invalid; + operand->expr = call; + return Expr_Stmt; + } + } + if (operand->mode == Addressing_Invalid) { for_array(i, ce->args) { - check_expr_base(c, operand, ce->args[i], NULL); + AstNode *arg = ce->args[i]; + if (arg->kind == AstNode_FieldValue) { + arg = arg->FieldValue.value; + } + check_expr_base(c, operand, arg, NULL); } operand->mode = Addressing_Invalid; operand->expr = call; @@ -5005,14 +5166,20 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { operand->mode = Addressing_Invalid; isize arg_count = ce->args.count; switch (arg_count) { - case 0: error_node(call, "Missing argument in convertion to `%s`", str); break; - default: error_node(call, "Too many arguments in convertion to `%s`", str); break; - case 1: - check_expr(c, operand, ce->args[0]); + case 0: error_node(call, "Missing argument in conversion to `%s`", str); break; + default: error_node(call, "Too many arguments in conversion to `%s`", str); break; + case 1: { + AstNode *arg = ce->args[0]; + if (arg->kind == AstNode_FieldValue) { + error_node(call, "`field = value` cannot be used in a type conversion"); + arg = arg->FieldValue.value; + // NOTE(bill): Carry on the cast regardless + } + check_expr(c, operand, arg); if (operand->mode != Addressing_Invalid) { check_cast(c, operand, t); } - break; + } break; } gb_string_free(str); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d35a49478..80233a38f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1583,7 +1583,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { Type *init_type = NULL; if (vd->type) { - init_type = check_type_extra(c, vd->type, NULL); + init_type = check_type(c, vd->type, NULL); if (init_type == NULL) { init_type = t_invalid; } diff --git a/src/checker.cpp b/src/checker.cpp index dd0b60a9c..05503c608 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1631,7 +1631,7 @@ void check_all_global_entities(Checker *c) { for_array(i, c->info.entities.entries) { auto *entry = &c->info.entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; DeclInfo *d = entry->value; if (d->scope != e->scope) { @@ -1669,7 +1669,7 @@ void check_all_global_entities(Checker *c) { for_array(i, c->info.entities.entries) { auto *entry = &c->info.entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; if (e->kind != Entity_Procedure) { continue; } @@ -2063,7 +2063,7 @@ void check_parsed_files(Checker *c) { for_array(i, c->info.untyped.entries) { auto *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; - AstNode *expr = cast(AstNode *)cast(uintptr)key.key; + AstNode *expr = cast(AstNode *)key.ptr; ExprInfo *info = &entry->value; if (info != NULL && expr != NULL) { if (is_type_typed(info->type)) { diff --git a/src/common.cpp b/src/common.cpp index a38af63f4..0c096a40d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -3,7 +3,7 @@ #include #endif -#define GB_NO_DEFER +// #define GB_NO_DEFER #define GB_IMPLEMENTATION #include "gb/gb.h" @@ -18,18 +18,22 @@ gbAllocator heap_allocator(void) { #include "array.cpp" #include "integer128.cpp" #include "murmurhash3.cpp" -#include "map.cpp" u128 fnv128a(void const *data, isize len) { u128 o = u128_lo_hi(0x13bull, 0x1000000ull); u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull); u8 const *bytes = cast(u8 const *)data; for (isize i = 0; i < len; i++) { - h = u128_mul(u128_xor(h, u128_from_u64(bytes[i])), o); + h.lo ^= bytes[i]; + h = h * o; } return h; } +#include "map.cpp" + + + gb_global String global_module_path = {0}; gb_global bool global_module_path_set = false; diff --git a/src/integer128.cpp b/src/integer128.cpp index 73cd1c7a0..35023a220 100644 --- a/src/integer128.cpp +++ b/src/integer128.cpp @@ -1,3 +1,10 @@ + +#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) + #define MSVC_AMD64_INTRINSICS + #include + #pragma intrinsic(_mul128) +#endif + #define BIT128_U64_HIGHBIT 0x8000000000000000ull #define BIT128_U64_BITS62 0x7fffffffffffffffull #define BIT128_U64_ALLBITS 0xffffffffffffffffull @@ -376,7 +383,11 @@ u128 u128_shl(u128 a, u32 n) { if (n >= 128) { return u128_lo_hi(0, 0); } - +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.hi = __shiftleft128(a.lo, a.hi, n); + a.lo = a.lo << n; + return a; +#else if (n >= 64) { n -= 64; a.hi = a.lo; @@ -391,13 +402,18 @@ u128 u128_shl(u128 a, u32 n) { a.lo <<= n; } return a; +#endif } u128 u128_shr(u128 a, u32 n) { if (n >= 128) { return u128_lo_hi(0, 0); } - +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.lo = __shiftright128(a.lo, a.hi, n); + a.hi = a.hi >> n; + return a; +#else if (n >= 64) { n -= 64; a.lo = a.hi; @@ -411,6 +427,7 @@ u128 u128_shr(u128 a, u32 n) { a.hi >>= n; } return a; +#endif } @@ -427,6 +444,14 @@ u128 u128_mul(u128 a, u128 b) { return a; } + +#if defined(MSVC_AMD64_INTRINSICS) + if (a.hi == 0 && b.hi == 0) { + a.lo = _umul128(a.lo, b.lo, &a.hi); + return a; + } +#endif + u128 res = {0}; u128 t = b; for (u32 i = 0; i < 128; i++) { @@ -440,6 +465,8 @@ u128 u128_mul(u128 a, u128 b) { return res; } +bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; } + void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { if (u128_eq(den, U128_ZERO)) { if (quo) *quo = u128_from_u64(num.lo/den.lo); @@ -450,7 +477,7 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { u128 x = U128_ONE; u128 r = U128_ZERO; - while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) { + while (u128_ge(n, d) && !u128_hibit(&d)) { x = u128_shl(x, 1); d = u128_shl(d, 1); } @@ -471,11 +498,18 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { } u128 u128_quo(u128 a, u128 b) { + if (a.hi == 0 && b.hi == 0) { + return u128_from_u64(a.lo/b.lo); + } + u128 res = {0}; u128_divide(a, b, &res, NULL); return res; } u128 u128_mod(u128 a, u128 b) { + if (a.hi == 0 && b.hi == 0) { + return u128_from_u64(a.lo%b.lo); + } u128 res = {0}; u128_divide(a, b, NULL, &res); return res; @@ -535,6 +569,11 @@ i128 i128_shl(i128 a, u32 n) { return i128_lo_hi(0, 0); } +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.hi = __shiftleft128(a.lo, a.hi, n); + a.lo = a.lo << n; + return a; +#else if (n >= 64) { n -= 64; a.hi = a.lo; @@ -549,6 +588,7 @@ i128 i128_shl(i128 a, u32 n) { a.lo <<= n; } return a; +#endif } i128 i128_shr(i128 a, u32 n) { @@ -556,6 +596,11 @@ i128 i128_shr(i128 a, u32 n) { return i128_lo_hi(0, 0); } +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.lo = __shiftright128(a.lo, a.hi, n); + a.hi = a.hi >> n; + return a; +#else if (n >= 64) { n -= 64; a.lo = a.hi; @@ -569,6 +614,7 @@ i128 i128_shr(i128 a, u32 n) { a.hi >>= n; } return a; +#endif } @@ -585,6 +631,13 @@ i128 i128_mul(i128 a, i128 b) { return a; } +#if defined(MSVC_AMD64_INTRINSICS) + if (a.hi == 0 && b.hi == 0) { + a.lo = _mul128(a.lo, b.lo, &a.hi); + return a; + } +#endif + i128 res = {0}; i128 t = b; for (u32 i = 0; i < 128; i++) { diff --git a/src/ir.cpp b/src/ir.cpp index bcea8a515..a8cfb0649 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4599,6 +4599,35 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *type = &proc_type_->Proc; + if (is_call_expr_field_value(ce)) { + isize param_count = type->param_count; + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count); + + for_array(arg_index, ce->args) { + AstNode *arg = ce->args[arg_index]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == AstNode_Ident); + String name = fv->field->Ident.string; + isize index = lookup_procedure_parameter(type, name); + GB_ASSERT(index >= 0); + irValue *expr = ir_build_expr(proc, fv->value); + args[index] = expr; + + } + TypeTuple *pt = &type->params->Tuple; + for (isize i = 0; i < param_count; i++) { + Type *param_type = pt->variables[i]->type; + if (args[i] == NULL) { + args[i] = ir_value_nil(proc->module->allocator, param_type); + } else { + args[i] = ir_emit_conv(proc, args[i], param_type); + } + } + + return ir_emit_call(proc, value, args, param_count); + // GB_PANIC("HERE!\n"); + } + isize arg_index = 0; isize arg_count = 0; @@ -4612,7 +4641,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count); - bool variadic = proc_type_->Proc.variadic; + bool variadic = type->variadic; bool vari_expand = ce->ellipsis.pos.line != 0; for_array(i, ce->args) { @@ -6855,7 +6884,7 @@ void ir_init_module(irModule *m, Checker *c) { isize max_index = -1; for_array(type_info_map_index, m->info->type_info_map.entries) { auto *entry = &m->info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = ir_type_info_index(m->info, t); if (max_index < entry_index) { @@ -6880,7 +6909,7 @@ void ir_init_module(irModule *m, Checker *c) { for_array(entry_index, m->info->type_info_map.entries) { auto *entry = &m->info->type_info_map.entries[entry_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; switch (t->kind) { case Type_Record: @@ -7083,7 +7112,7 @@ void ir_gen_tree(irGen *s) { for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; if (e->kind == Entity_Variable) { global_variable_max_count++; @@ -7446,7 +7475,7 @@ void ir_gen_tree(irGen *s) { for_array(type_info_map_index, info->type_info_map.entries) { auto *entry = &info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = ir_type_info_index(info, t); @@ -7909,7 +7938,7 @@ void ir_gen_tree(irGen *s) { for_array(type_info_map_index, info->type_info_map.entries) { auto *entry = &info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = entry->value; diff --git a/src/map.cpp b/src/map.cpp index d45d2bccb..57942365a 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -19,6 +19,7 @@ enum HashKeyKind { struct HashKey { HashKeyKind kind; + // u128 key; u64 key; union { String string; // if String, s.len > 0 @@ -29,9 +30,8 @@ struct HashKey { gb_inline HashKey hashing_proc(void const *data, isize len) { HashKey h = {HashKey_Default}; h.kind = HashKey_Default; - // h.key = gb_murmur64(data, len); + // h.key = u128_from_u64(gb_fnv64a(data, len)); h.key = gb_fnv64a(data, len); - // h.key = MurmurHash3_128(data, len, 0x3803cb8e); return h; } @@ -136,7 +136,8 @@ template gb_internal MapFindResult map__find(Map *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { - fr.hash_index = key.key % h->hashes.count; + // fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count)); + fr.hash_index = key.key % h->hashes.count; fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index >= 0) { if (hash_key_equal(h->entries[fr.entry_index].key, key)) { diff --git a/src/murmurhash3.cpp b/src/murmurhash3.cpp index 23c9ac454..7eacdc060 100644 --- a/src/murmurhash3.cpp +++ b/src/murmurhash3.cpp @@ -41,15 +41,15 @@ gb_inline u64 fmix64(u64 k) { return k; } -gb_inline u32 mm3_getblock32(u32 *const p, isize i) { +gb_inline u32 mm3_getblock32(u32 const *p, isize i) { return p[i]; } -gb_inline u64 mm3_getblock64(u64 *const p, isize i) { +gb_inline u64 mm3_getblock64(u64 const *p, isize i) { return p[i]; } -u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { - u8 *const data = cast(u8 *const)key; +void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) { + u8 const * data = cast(u8 const *)key; isize nblocks = len / 16; u64 h1 = seed; @@ -58,7 +58,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { u64 const c1 = 0x87c37b91114253d5ULL; u64 const c2 = 0x4cf5ad432745937fULL; - u64 *const blocks = cast(u64 *const)data; + u64 const * blocks = cast(u64 const *)data; for (isize i = 0; i < nblocks; i++) { u64 k1 = mm3_getblock64(blocks, i*2 + 0); @@ -70,7 +70,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; } - u8 *const tail = cast(u8 *const)(data + nblocks*16); + u8 const * tail = cast(u8 const *)(data + nblocks*16); u64 k1 = 0; u64 k2 = 0; @@ -108,11 +108,12 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { h1 += h2; h2 += h1; - return u128_lo_hi(h1, h2); + ((u64 *)out)[0] = h1; + ((u64 *)out)[1] = h2; } -u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { - u8 *const data = cast(u8 * const)key; +void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) { + u8 const * data = cast(u8 * const)key; isize nblocks = len / 16; u32 h1 = seed; @@ -128,7 +129,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { //---------- // body - u32 *const blocks = cast(u32 *const)(data + nblocks*16); + u32 const * blocks = cast(u32 const *)(data + nblocks*16); for (isize i = -nblocks; i != 0; i++) { u32 k1 = mm3_getblock32(blocks, i*4 + 0); @@ -156,7 +157,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { //---------- // tail - u8 *const tail = cast(u8 *const)(data + nblocks*16); + u8 const * tail = cast(u8 const *)(data + nblocks*16); u32 k1 = 0; u32 k2 = 0; @@ -204,17 +205,21 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; - u64 lo = (u64)h1 | ((u64)h2 << 32); - u64 hi = (u64)h3 | ((u64)h4 << 32); - return u128_lo_hi(lo, hi); + + ((u32 *)out)[0] = h1; + ((u32 *)out)[1] = h2; + ((u32 *)out)[2] = h3; + ((u32 *)out)[3] = h4; } -gb_inline u128 MurmurHash3_128(void *const key, isize len, u32 seed) { +gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) { + u128 res; #if defined(GB_ARCH_64_BIT) - return MurmurHash3_x64_128(key, len, seed); + MurmurHash3_x64_128(key, len, seed, &res); #else - return MurmurHash3_x86_128(key, len, seed); + MurmurHash3_x86_128(key, len, seed, &res); #endif + return res; } diff --git a/src/parser.cpp b/src/parser.cpp index 120bb63cc..d741e569f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2128,6 +2128,11 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { } AstNode *arg = parse_expr(f, false); + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + AstNode *value = parse_value(f); + arg = ast_field_value(f, arg, value, eq); + } array_add(&args, arg); if (!allow_token(f, Token_Comma)) { diff --git a/src/ssa.cpp b/src/ssa.cpp index b9ed4e75a..f3c187222 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -2493,7 +2493,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; if (e->kind == Entity_Variable) { global_variable_max_count++; diff --git a/src/timings.cpp b/src/timings.cpp index d00d5d0ba..27ee1f3a4 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -110,7 +110,7 @@ f64 time_stamp_as_ms(TimeStamp ts, u64 freq) { void timings_print_all(Timings *t) { char const SPACES[] = " "; - isize max_len, i; + isize max_len; timings__stop_current_section(t); t->total.finish = time_stamp_time_now(); -- cgit v1.2.3 From 366b306df04e14a5841868a40016cd844e120d99 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 11 Jun 2017 18:38:30 +0100 Subject: Default parameters for procedures --- src/check_expr.cpp | 118 +++++++++++++++++++++++++++++++++++++++++------------ src/entity.cpp | 9 ++-- src/ir.cpp | 39 ++++++++++++++---- src/parser.cpp | 60 +++++++++++++++++++++------ 4 files changed, 175 insertions(+), 51 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 07fe9cbc2..a8453f0cb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -255,13 +255,18 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { } +i64 assign_score_function(i64 distance) { + // TODO(bill): A decent score function + return gb_max(1000000 - distance*distance, 0); +} + + bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score_) { i64 score = 0; i64 distance = check_distance_between_types(c, operand, type); bool ok = distance >= 0; if (ok) { - // TODO(bill): A decent score function - score = gb_max(1000000 - distance*distance, 0); + score = assign_score_function(distance); } if (score_) *score_ = score; return ok; @@ -1051,7 +1056,22 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } ast_node(p, Field, params[i]); AstNode *type_expr = p->type; - if (type_expr) { + Type *type = NULL; + AstNode *default_value = p->default_value; + ExactValue value = {}; + + if (type_expr == NULL) { + Operand o = {}; + check_expr(c, &o, default_value); + + if (o.mode != Addressing_Constant) { + error_node(default_value, "Default parameter must be a constant"); + } else { + value = o.value; + } + + type = default_type(o.type); + } else { if (type_expr->kind == AstNode_Ellipsis) { type_expr = type_expr->Ellipsis.expr; if (i+1 == params.count) { @@ -1061,28 +1081,49 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } } - Type *type = check_type(c, type_expr); - if (p->flags&FieldFlag_no_alias) { - if (!is_type_pointer(type)) { - error_node(params[i], "`no_alias` can only be applied to fields of pointer type"); - p->flags &= ~FieldFlag_no_alias; // Remove the flag + type = check_type(c, type_expr); + + if (default_value != NULL) { + Operand o = {}; + check_expr(c, &o, default_value); + + if (o.mode != Addressing_Constant) { + error_node(default_value, "Default parameter must be a constant"); + } else { + value = o.value; } + + check_is_assignable_to(c, &o, type); } - for_array(j, p->names) { - AstNode *name = p->names[j]; - if (ast_node_expect(name, AstNode_Ident)) { - Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, - (p->flags&FieldFlag_using) != 0, (p->flags&FieldFlag_immutable) != 0); - if (p->flags&FieldFlag_no_alias) { - param->flags |= EntityFlag_NoAlias; - } - if (p->flags&FieldFlag_immutable) { - param->Variable.is_immutable = true; - } - add_entity(c, scope, name, param); - variables[variable_index++] = param; + } + if (type == NULL) { + error_node(params[i], "Invalid parameter type"); + type = t_invalid; + } + + if (p->flags&FieldFlag_no_alias) { + if (!is_type_pointer(type)) { + error_node(params[i], "`no_alias` can only be applied to fields of pointer type"); + p->flags &= ~FieldFlag_no_alias; // Remove the flag + } + } + + for_array(j, p->names) { + AstNode *name = p->names[j]; + if (ast_node_expect(name, AstNode_Ident)) { + Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, + (p->flags&FieldFlag_using) != 0, (p->flags&FieldFlag_immutable) != 0); + if (p->flags&FieldFlag_no_alias) { + param->flags |= EntityFlag_NoAlias; + } + if (p->flags&FieldFlag_immutable) { + param->Variable.is_immutable = true; } + param->Variable.default_value = value; + + add_entity(c, scope, name, param); + variables[variable_index++] = param; } } } @@ -4775,18 +4816,35 @@ typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { ast_node(ce, CallExpr, call); isize param_count = 0; + isize param_count_excluding_defaults = 0; bool variadic = proc_type->Proc.variadic; bool vari_expand = (ce->ellipsis.pos.line != 0); i64 score = 0; bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + TypeTuple *param_tuple = NULL; + if (proc_type->Proc.params != NULL) { - param_count = proc_type->Proc.params->Tuple.variable_count; + param_tuple = &proc_type->Proc.params->Tuple; + + param_count = param_tuple->variable_count; if (variadic) { param_count--; } } + param_count_excluding_defaults = param_count; + if (param_tuple != NULL) { + for (isize i = param_count-1; i >= 0; i--) { + Entity *e = param_tuple->variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.default_value.kind == ExactValue_Invalid) { + break; + } + param_count_excluding_defaults--; + } + } + if (vari_expand && !variadic) { if (show_error) { error(ce->ellipsis, @@ -4797,13 +4855,13 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { return CallArgumentError_NonVariadicExpand; } - if (operands.count == 0 && param_count == 0) { + if (operands.count == 0 && param_count_excluding_defaults == 0) { if (score_) *score_ = score; return CallArgumentError_None; } i32 error_code = 0; - if (operands.count < param_count) { + if (operands.count < param_count_excluding_defaults) { error_code = -1; } else if (!variadic && operands.count > param_count) { error_code = +1; @@ -4818,7 +4876,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (show_error) { gbString proc_str = expr_to_string(ce->proc); - error_node(call, err_fmt, proc_str, param_count); + error_node(call, err_fmt, proc_str, param_count_excluding_defaults); gb_string_free(proc_str); } if (score_) *score_ = score; @@ -4828,9 +4886,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { CallArgumentError err = CallArgumentError_None; GB_ASSERT(proc_type->Proc.params != NULL); - Entity **sig_params = proc_type->Proc.params->Tuple.variables; + Entity **sig_params = param_tuple->variables; isize operand_index = 0; - for (; operand_index < param_count; operand_index++) { + for (; operand_index < param_count_excluding_defaults; operand_index++) { Type *t = sig_params[operand_index]->type; Operand o = operands[operand_index]; if (variadic) { @@ -4972,6 +5030,12 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { if (e->token.string == "_") { continue; } + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.default_value.kind != ExactValue_Invalid) { + score += assign_score_function(1); + continue; + } + if (show_error) { gbString str = type_to_string(e->type); error_node(call, "Parameter `%.*s` of type `%s` is missing in procedure call", diff --git a/src/entity.cpp b/src/entity.cpp index d8159d449..26e94dbf1 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -81,10 +81,11 @@ struct Entity { ExactValue value; } Constant; struct { - i32 field_index; - i32 field_src_index; - bool is_immutable; - bool is_thread_local; + i32 field_index; + i32 field_src_index; + bool is_immutable; + bool is_thread_local; + ExactValue default_value; } Variable; struct { bool is_type_alias; diff --git a/src/ir.cpp b/src/ir.cpp index a8cfb0649..95c277f59 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4616,16 +4616,20 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } TypeTuple *pt = &type->params->Tuple; for (isize i = 0; i < param_count; i++) { - Type *param_type = pt->variables[i]->type; + Entity *e = pt->variables[i]; + GB_ASSERT(e->kind == Entity_Variable); if (args[i] == NULL) { - args[i] = ir_value_nil(proc->module->allocator, param_type); + if (e->Variable.default_value.kind != ExactValue_Invalid) { + args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else { + args[i] = ir_value_nil(proc->module->allocator, e->type); + } } else { - args[i] = ir_emit_conv(proc, args[i], param_type); + args[i] = ir_emit_conv(proc, args[i], e->type); } } return ir_emit_call(proc, value, args, param_count); - // GB_PANIC("HERE!\n"); } isize arg_index = 0; @@ -4640,7 +4644,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { arg_count++; } } - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count); + + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count)); bool variadic = type->variadic; bool vari_expand = ce->ellipsis.pos.line != 0; @@ -4660,6 +4666,23 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { TypeTuple *pt = &type->params->Tuple; + if (arg_count < type->param_count) { + isize end = type->param_count; + if (variadic) { + end--; + } + while (arg_index < end) { + Entity *e = pt->variables[arg_index]; + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.default_value.kind != ExactValue_Invalid) { + args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else { + args[arg_index++] = ir_value_nil(proc->module->allocator, e->type); + } + } + } + + if (variadic) { isize i = 0; for (; i < type->param_count-1; i++) { @@ -4674,7 +4697,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } } else { - for (isize i = 0; i < arg_count; i++) { + for (isize i = 0; i < type->param_count; i++) { args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type); } } @@ -4704,7 +4727,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { args[arg_count-1] = ir_emit_load(proc, slice); } - return ir_emit_call(proc, value, args, arg_count); + return ir_emit_call(proc, value, args, type->param_count); case_end; case_ast_node(se, SliceExpr, expr); @@ -6680,7 +6703,7 @@ void ir_number_proc_registers(irProcedure *proc) { b->index = i; for_array(j, b->instrs) { irValue *value = b->instrs[j]; - GB_ASSERT(value->kind == irValue_Instr); + GB_ASSERT_MSG(value->kind == irValue_Instr, "%.*s", LIT(proc->name)); irInstr *instr = &value->Instr; if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions value->index = -1; diff --git a/src/parser.cpp b/src/parser.cpp index d741e569f..2feaa1fc2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -326,9 +326,10 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ }) \ AST_NODE_KIND(_DeclEnd, "", i32) \ AST_NODE_KIND(Field, "field", struct { \ - Array names; \ - AstNode * type; \ - u32 flags; \ + Array names; \ + AstNode * type; \ + AstNode * default_value; \ + u32 flags; \ }) \ AST_NODE_KIND(FieldList, "field list", struct { \ Token token; \ @@ -1276,10 +1277,11 @@ AstNode *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -AstNode *ast_field(AstFile *f, Array names, AstNode *type, u32 flags) { +AstNode *ast_field(AstFile *f, Array names, AstNode *type, AstNode *default_value, u32 flags) { AstNode *result = make_ast_node(f, AstNode_Field); result->Field.names = names; result->Field.type = type; + result->Field.default_value = default_value; result->Field.flags = flags; return result; } @@ -2645,7 +2647,7 @@ AstNode *parse_results(AstFile *f) { Array empty_names = {}; Array list = make_ast_node_array(f); AstNode *type = parse_type(f); - array_add(&list, ast_field(f, empty_names, type, 0)); + array_add(&list, ast_field(f, empty_names, type, NULL, 0)); return ast_field_list(f, begin_token, list); } @@ -2839,6 +2841,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok Array list = {}; array_init(&list, heap_allocator()); // LEAK(bill): isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; + bool is_procedure = (allowed_flags&FieldFlag_Signature) != 0; while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && @@ -2866,8 +2869,25 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok total_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); - AstNode *type = parse_var_type(f, allow_ellipsis); - AstNode *param = ast_field(f, names, type, set_flags); + AstNode *type = NULL; + AstNode *default_value = NULL; + + if (f->curr_token.kind != Token_Eq) { + type = parse_var_type(f, allow_ellipsis); + } + if (allow_token(f, Token_Eq)) { + // TODO(bill): Should this be true==lhs or false==rhs? + default_value = parse_expr(f, true); + if (!is_procedure) { + syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); + } + } + + if (default_value != NULL && names.count > 1) { + syntax_error(f->curr_token, "Default parameters can only be applied to single values"); + } + + AstNode *param = ast_field(f, names, type, default_value, set_flags); array_add(¶ms, param); parse_expect_field_separator(f, type); @@ -2884,8 +2904,24 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok total_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); - AstNode *type = parse_var_type(f, allow_ellipsis); - AstNode *param = ast_field(f, names, type, set_flags); + AstNode *type = NULL; + AstNode *default_value = NULL; + if (f->curr_token.kind != Token_Eq) { + type = parse_var_type(f, allow_ellipsis); + } + if (allow_token(f, Token_Eq)) { + // TODO(bill): Should this be true==lhs or false==rhs? + default_value = parse_expr(f, true); + if (!is_procedure) { + syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); + } + } + + if (default_value != NULL && names.count > 1) { + syntax_error(f->curr_token, "Default parameters can only be applied to single values"); + } + + AstNode *param = ast_field(f, names, type, default_value, set_flags); array_add(¶ms, param); if (!parse_expect_field_separator(f, param)) { @@ -2907,7 +2943,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok names[0] = ast_ident(f, token); u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags); - AstNode *param = ast_field(f, names, list[i].node, flags); + AstNode *param = ast_field(f, names, list[i].node, NULL, flags); array_add(¶ms, param); } @@ -3084,7 +3120,7 @@ AstNode *parse_type_or_ident(AstFile *f) { total_decl_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); AstNode *type = parse_var_type(f, false); - array_add(&decls, ast_field(f, names, type, set_flags)); + array_add(&decls, ast_field(f, names, type, NULL, set_flags)); } else { Array names = parse_ident_list(f); if (names.count == 0) { @@ -3095,7 +3131,7 @@ AstNode *parse_type_or_ident(AstFile *f) { total_decl_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); AstNode *type = parse_var_type(f, false); - array_add(&decls, ast_field(f, names, type, set_flags)); + array_add(&decls, ast_field(f, names, type, NULL, set_flags)); } else { AstNode *name = names[0]; Token open = expect_token(f, Token_OpenBrace); -- cgit v1.2.3