aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp2
-rw-r--r--src/check_decl.cpp18
-rw-r--r--src/check_expr.cpp140
-rw-r--r--src/check_stmt.cpp23
-rw-r--r--src/check_type.cpp30
-rw-r--r--src/checker.cpp131
-rw-r--r--src/checker.hpp8
-rw-r--r--src/ir.cpp45
-rw-r--r--src/ir_print.cpp45
-rw-r--r--src/main.cpp125
-rw-r--r--src/parser.cpp90
-rw-r--r--src/parser.hpp6
-rw-r--r--src/string.cpp1
-rw-r--r--src/tokenizer.cpp4
-rw-r--r--src/types.cpp153
15 files changed, 650 insertions, 171 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index ca9a77902..d7b85644d 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -110,6 +110,8 @@ struct BuildContext {
gbAffinity affinity;
isize thread_count;
+
+ Map<ExactValue> defined_values; // Key:
};
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 91fd0ff01..c2796e1da 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -551,20 +551,20 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
check_procedure_type(&tmp_ctx, proc_type, pl->type);
TypeProc *pt = &proc_type->Proc;
-
- bool is_foreign = e->Procedure.is_foreign;
- bool is_export = e->Procedure.is_export;
- bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
-
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
if (d != nullptr) {
check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
}
+ e->Procedure.is_export = ac.is_export;
e->deprecated_message = ac.deprecated_message;
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
+ bool is_foreign = e->Procedure.is_foreign;
+ bool is_export = e->Procedure.is_export;
+ bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
+
if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 ||
pt->result_count != 0) {
@@ -718,8 +718,14 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
}
- ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
+ e->Variable.is_export = ac.is_export;
+ if (ac.is_static) {
+ e->flags |= EntityFlag_Static;
+ } else {
+ e->flags &= ~EntityFlag_Static;
+ }
+ ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
String context_name = str_lit("variable declaration");
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index e5140ce25..d0e18d89f 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -991,7 +991,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
o->expr = n;
String name = n->Ident.token.string;
-
Entity *e = scope_lookup(c->scope, name);
if (e == nullptr) {
if (is_blank_ident(name)) {
@@ -1241,6 +1240,14 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
return false;
}
+ if (is_type_simd_vector(o->type)) {
+ switch (op.kind) {
+ case Token_ModMod:
+ case Token_ModModEq:
+ error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
+ return false;
+ }
+ }
break;
case Token_AndNot:
@@ -1249,6 +1256,14 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
error(op, "Operator '%.*s' is only allowed with integers and bit sets", LIT(op.string));
return false;
}
+ if (is_type_simd_vector(o->type)) {
+ switch (op.kind) {
+ case Token_AndNot:
+ case Token_AndNotEq:
+ error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
+ return false;
+ }
+ }
break;
case Token_CmpAnd:
@@ -2129,8 +2144,20 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
case Token_in:
case Token_notin:
- check_expr(c, x, be->left);
+ // IMPORTANT NOTE(bill): This uses right-left evaluation in type checking only no in
+
check_expr(c, y, be->right);
+
+ if (is_type_bit_set(y->type)) {
+ Type *elem = base_type(y->type)->BitSet.elem;
+ check_expr_with_type_hint(c, x, be->left, elem);
+ } else if (is_type_map(y->type)) {
+ Type *key = base_type(y->type)->Map.key;
+ check_expr_with_type_hint(c, x, be->left, key);
+ } else {
+ check_expr(c, x, be->left);
+ }
+
if (x->mode == Addressing_Invalid) {
return;
}
@@ -4072,6 +4099,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
+ case BuiltinProc_vector: {
+ Operand x = {};
+ Operand y = {};
+ x = *operand;
+ if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
+ error(call, "Expected a constant integer for 'intrinsics.vector'");
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+ if (x.value.value_integer.neg) {
+ error(call, "Negative vector element length");
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+ i64 count = big_int_to_i64(&x.value.value_integer);
+
+ check_expr_or_type(c, &y, ce->args[1]);
+ if (y.mode != Addressing_Type) {
+ error(call, "Expected a type 'intrinsics.vector'");
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+ Type *elem = y.type;
+ if (!is_type_valid_vector_elem(elem)) {
+ gbString str = type_to_string(elem);
+ error(call, "Invalid element type for 'intrinsics.vector', expected an integer or float with no specific endianness, got '%s'", str);
+ gb_string_free(str);
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ operand->mode = Addressing_Type;
+ operand->type = alloc_type_simd_vector(count, elem);
+ break;
+ }
+
case BuiltinProc_atomic_fence:
case BuiltinProc_atomic_fence_acq:
case BuiltinProc_atomic_fence_rel:
@@ -5372,7 +5439,8 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
operand->mode = Addressing_NoValue;
} else {
GB_ASSERT(is_type_tuple(result_type));
- switch (result_type->Tuple.variables.count) {
+ isize count = result_type->Tuple.variables.count;
+ switch (count) {
case 0:
operand->mode = Addressing_NoValue;
break;
@@ -5778,7 +5846,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
}
- if (!is_type_struct(t)) {
+ if (t->Struct.is_raw_union) {
if (cl->elems.count != 0) {
gbString type_str = type_to_string(type);
error(node, "Illegal compound literal type '%s'", type_str);
@@ -5902,6 +5970,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case Type_Slice:
case Type_Array:
case Type_DynamicArray:
+ case Type_SimdVector:
{
Type *elem_type = nullptr;
String context_name = {};
@@ -5922,6 +5991,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
add_package_dependency(c, "runtime", "__dynamic_array_reserve");
add_package_dependency(c, "runtime", "__dynamic_array_append");
+ } else if (t->kind == Type_SimdVector) {
+ elem_type = t->SimdVector.elem;
+ context_name = str_lit("simd vector literal");
+ max_type_count = t->SimdVector.count;
} else {
GB_PANIC("unreachable");
}
@@ -5972,6 +6045,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
}
}
+
+ if (t->kind == Type_SimdVector) {
+ if (!is_constant) {
+ error(node, "Expected all constant elements for a simd vector");
+ }
+ if (t->SimdVector.is_x86_mmx) {
+ error(node, "Compound literals are not allowed with intrinsics.x86_mmx");
+ }
+ }
break;
}
@@ -6107,7 +6189,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
continue;
}
- check_expr(c, o, elem);
+ check_expr_with_type_hint(c, o, elem, et);
if (is_constant) {
is_constant = o->mode == Addressing_Constant;
@@ -6338,6 +6420,47 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case_end;
+ case_ast_node(ise, ImplicitSelectorExpr, node);
+ o->type = t_invalid;
+ o->expr = node;
+ o->mode = Addressing_Invalid;
+
+ if (type_hint == nullptr) {
+ gbString str = expr_to_string(node);
+ error(node, "Cannot determine type for implicit selector expression '%s'", str);
+ gb_string_free(str);
+ return Expr_Expr;
+ }
+ o->type = type_hint;
+ if (!is_type_enum(type_hint)) {
+ gbString typ = type_to_string(type_hint);
+ gbString str = expr_to_string(node);
+ error(node, "Invalid type '%s' for implicit selector expression '%s'", typ, str);
+ gb_string_free(str);
+ gb_string_free(typ);
+ return Expr_Expr;
+ }
+ GB_ASSERT(ise->selector->kind == Ast_Ident);
+ String name = ise->selector->Ident.token.string;
+
+ Type *enum_type = base_type(type_hint);
+ GB_ASSERT(enum_type->kind == Type_Enum);
+ Entity *e = scope_lookup_current(enum_type->Enum.scope, name);
+ if (e == nullptr) {
+ gbString typ = type_to_string(type_hint);
+ error(node, "Undeclared name %.*s for type '%s'", LIT(name), typ);
+ gb_string_free(typ);
+ return Expr_Expr;
+ }
+ GB_ASSERT(are_types_identical(base_type(e->type), base_type(type_hint)));
+ GB_ASSERT(e->kind == Entity_Constant);
+ o->value = e->Constant.value;
+ o->mode = Addressing_Constant;
+ o->type = e->type;
+
+ return Expr_Expr;
+ case_end;
+
case_ast_node(ie, IndexExpr, node);
check_expr(c, o, ie->expr);
if (o->mode == Addressing_Invalid) {
@@ -6351,7 +6474,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (is_type_map(t)) {
Operand key = {};
- check_expr(c, &key, ie->index);
+ check_expr_with_type_hint(c, &key, ie->index, t->Map.key);
check_assignment(c, &key, t->Map.key, str_lit("map index"));
if (key.mode == Addressing_Invalid) {
o->mode = Addressing_Invalid;
@@ -6762,6 +6885,11 @@ gbString write_expr_to_string(gbString str, Ast *node) {
str = write_expr_to_string(str, se->selector);
case_end;
+ case_ast_node(se, ImplicitSelectorExpr, node);
+ str = gb_string_append_rune(str, '.');
+ str = write_expr_to_string(str, se->selector);
+ case_end;
+
case_ast_node(ta, TypeAssertion, node);
str = write_expr_to_string(str, ta->expr);
str = gb_string_appendc(str, ".(");
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 3262aea5d..cead61ce8 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -686,14 +686,14 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(ie, BinaryExpr, expr);
Operand lhs = {};
Operand rhs = {};
- check_expr(ctx, &lhs, ie->left);
+ check_expr_with_type_hint(ctx, &lhs, ie->left, x.type);
if (x.mode == Addressing_Invalid) {
continue;
}
if (lhs.mode == Addressing_Invalid) {
continue;
}
- check_expr(ctx, &rhs, ie->right);
+ check_expr_with_type_hint(ctx, &rhs, ie->right, x.type);
if (rhs.mode == Addressing_Invalid) {
continue;
}
@@ -732,7 +732,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
if (is_type_typeid(x.type)) {
check_expr_or_type(ctx, &y, expr, x.type);
} else {
- check_expr(ctx, &y, expr);
+ check_expr_with_type_hint(ctx, &y, expr, x.type);
}
if (x.mode == Addressing_Invalid ||
@@ -1665,8 +1665,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (!is_blank_ident(str)) {
found = scope_lookup_current(ctx->scope, str);
new_name_count += 1;
- } else if (vd->is_static) {
- error(name, "'static' is now allowed to be applied to '_'");
}
if (found == nullptr) {
entity = alloc_entity_variable(ctx->scope, token, nullptr, false);
@@ -1678,9 +1676,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
entity->Variable.is_foreign = true;
entity->Variable.foreign_library_ident = fl;
}
- if (vd->is_static) {
- entity->flags |= EntityFlag_Static;
- }
} else {
TokenPos pos = found->token.pos;
error(token,
@@ -1744,6 +1739,16 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name;
}
+
+ e->flags &= ~EntityFlag_Static;
+ if (ac.is_static) {
+ String name = e->token.string;
+ if (name == "_") {
+ error(e->token, "The 'static' attribute is not allowed to be applied to '_'");
+ } else {
+ e->flags |= EntityFlag_Static;
+ }
+ }
}
check_arity_match(ctx, vd);
@@ -1751,6 +1756,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
+
if (e->Variable.is_foreign) {
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
@@ -1842,6 +1848,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
}
}
}
+
} else {
// constant value declaration
// NOTE(bill): Check `_` declarations
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 953eebdda..451a388fb 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -1783,13 +1783,21 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
Type *new_type = original_type;
if (is_type_boolean(original_type)) {
- return t_llvm_bool;
+ Type *t = core_type(base_type(new_type));
+ if (t == t_bool) {
+ return t_llvm_bool;
+ }
+ return new_type;
}
if (build_context.ODIN_ARCH == "386") {
return new_type;
}
+ if (is_type_simd_vector(original_type)) {
+ return new_type;
+ }
+
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
@@ -1893,7 +1901,11 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
}
GB_ASSERT(is_type_tuple(original_type));
+ Type *single_type = reduce_tuple_to_single_type(original_type);
+ if (is_type_simd_vector(single_type)) {
+ return new_type;
+ }
if (build_context.ODIN_OS == "windows") {
Type *bt = core_type(reduce_tuple_to_single_type(original_type));
@@ -1941,15 +1953,16 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
return new_type;
}
-bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) {
+bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) {
if (abi_return_type == nullptr) {
return false;
}
- // switch (cc) {
- // case ProcCC_Odin:
- // case ProcCC_Contextless:
- // return false;
- // }
+
+ Type *single_type = reduce_tuple_to_single_type(abi_return_type);
+
+ if (is_type_simd_vector(single_type)) {
+ return false;
+ }
if (build_context.ODIN_OS == "windows") {
@@ -2036,6 +2049,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
type->Proc.is_polymorphic = pt->generic;
type->Proc.specialization_count = specialization_count;
type->Proc.diverging = pt->diverging;
+ type->Proc.tags = pt->tags;
if (param_count > 0) {
Entity *end = params->Tuple.variables[param_count-1];
@@ -2075,7 +2089,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
// NOTE(bill): The types are the same
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results);
- type->Proc.return_by_pointer = abi_compat_return_by_value(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type);
+ type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type);
return success;
}
diff --git a/src/checker.cpp b/src/checker.cpp
index 9cac82911..0253bc86b 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -712,6 +712,53 @@ void init_universal(void) {
}
}
+ // TODO(bill): Set the correct arch for this
+ if (bc->metrics.arch == TargetArch_amd64 || bc->metrics.arch == TargetArch_386) {
+ t_vector_x86_mmx = alloc_type(Type_SimdVector);
+ t_vector_x86_mmx->SimdVector.is_x86_mmx = true;
+
+ Entity *entity = alloc_entity(Entity_TypeName, nullptr, make_token_ident(str_lit("x86_mmx")), t_vector_x86_mmx);
+ add_global_entity(entity, intrinsics_pkg->scope);
+ }
+
+ bool defined_values_double_declaration = false;
+ for_array(i, bc->defined_values.entries) {
+ String name = bc->defined_values.entries[i].key.string;
+ ExactValue value = bc->defined_values.entries[i].value;
+ GB_ASSERT(value.kind != ExactValue_Invalid);
+
+ Type *type = nullptr;
+ switch (value.kind) {
+ case ExactValue_Bool:
+ type = t_untyped_bool;
+ break;
+ case ExactValue_String:
+ type = t_untyped_string;
+ break;
+ case ExactValue_Integer:
+ type = t_untyped_integer;
+ break;
+ case ExactValue_Float:
+ type = t_untyped_float;
+ break;
+ }
+ GB_ASSERT(type != nullptr);
+
+
+
+ Entity *entity = alloc_entity_constant(nullptr, make_token_ident(name), type, value);
+ entity->state = EntityState_Resolved;
+ if (scope_insert(builtin_pkg->scope, entity)) {
+ error(entity->token, "'%.*s' defined as an argument is already declared at the global scope", LIT(name));
+ defined_values_double_declaration = true;
+ // NOTE(bill): Just exit early before anything, even though the compiler will do that anyway
+ }
+ }
+
+ if (defined_values_double_declaration) {
+ gb_exit(1);
+ }
+
t_u8_ptr = alloc_type_pointer(t_u8);
t_int_ptr = alloc_type_pointer(t_int);
@@ -1248,6 +1295,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
add_type_info_type(c, bt->Proc.results);
break;
+ case Type_SimdVector:
+ add_type_info_type(c, bt->SimdVector.elem);
+ break;
+
default:
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
@@ -1419,6 +1470,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->Proc.results);
break;
+ case Type_SimdVector:
+ add_min_dep_type_info(c, bt->SimdVector.elem);
+ break;
+
default:
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
break;
@@ -1795,6 +1850,7 @@ void init_core_type_info(Checker *c) {
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque"));
+ t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
@@ -1818,6 +1874,7 @@ void init_core_type_info(Checker *c) {
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque);
+ t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
}
void init_mem_allocator(Checker *c) {
@@ -1933,7 +1990,18 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
}
DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
- if (name == "deferred") {
+ if (name == "export") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Invalid) {
+ ac->is_export = true;
+ } else if (ev.kind == ExactValue_Bool) {
+ ac->is_export = ev.value_bool;
+ } else {
+ error(value, "Expected either a boolean or no parameter for 'export'");
+ return false;
+ }
+ return true;
+ } else if (name == "deferred") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
@@ -2040,12 +2108,33 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value);
+ if (name == "static") {
+ if (value != nullptr) {
+ error(elem, "'static' does not have any parameters");
+ }
+ ac->is_static = true;
+ return true;
+ }
+
if (c->curr_proc_decl != nullptr) {
error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name));
return true;
}
- if (name == "link_name") {
+ if (name == "export") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Invalid) {
+ ac->is_export = true;
+ } else if (ev.kind == ExactValue_Bool) {
+ ac->is_export = ev.value_bool;
+ } else {
+ error(value, "Expected either a boolean or no parameter for 'export'");
+ return false;
+ }
+ if (ac->thread_local_model != "") {
+ error(elem, "An exported variable cannot be thread local");
+ }
+ } else if (name == "link_name") {
if (ev.kind == ExactValue_String) {
ac->link_name = ev.value_string;
if (!is_foreign_name_valid(ac->link_name)) {
@@ -2068,8 +2157,10 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
- } else if (c->foreign_context.curr_library || c->foreign_context.in_export) {
+ } else if (c->foreign_context.curr_library) {
error(elem, "A foreign block variable cannot be thread local");
+ } else if (ac->is_export) {
+ error(elem, "An exported variable cannot be thread local");
} else if (ev.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
} else if (ev.kind == ExactValue_String) {
@@ -2132,9 +2223,17 @@ void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, De
case_ast_node(i, Ident, elem);
name = i->token.string;
case_end;
+ case_ast_node(i, Implicit, elem);
+ name = i->string;
+ case_end;
case_ast_node(fv, FieldValue, elem);
- GB_ASSERT(fv->field->kind == Ast_Ident);
- name = fv->field->Ident.token.string;
+ if (fv->field->kind == Ast_Ident) {
+ name = fv->field->Ident.token.string;
+ } else if (fv->field->kind == Ast_Implicit) {
+ name = fv->field->Implicit.string;
+ } else {
+ GB_PANIC("Unknown Field Value name");
+ }
value = fv->value;
case_end;
default:
@@ -2372,10 +2471,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
e->flags |= EntityFlag_NotExported;
}
- if (vd->is_static) {
- e->flags |= EntityFlag_Static;
- }
-
if (vd->is_using) {
vd->is_using = false; // NOTE(bill): This error will be only caught once
error(name, "'using' is not allowed at the file scope");
@@ -2388,9 +2483,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
e->Variable.foreign_library_ident = fl;
e->Variable.link_prefix = c->foreign_context.link_prefix;
-
- } else if (c->foreign_context.in_export) {
- e->Variable.is_export = true;
}
Ast *init_expr = value;
@@ -2456,9 +2548,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
GB_ASSERT(cc != ProcCC_Invalid);
pl->type->ProcType.calling_convention = cc;
-
- } else if (c->foreign_context.in_export) {
- e->Procedure.is_export = true;
}
d->proc_lit = init;
d->type_expr = pl->type;
@@ -2480,14 +2569,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
e->flags |= EntityFlag_NotExported;
}
- if (vd->is_static) {
- if (e->kind == Entity_Constant) {
- e->flags |= EntityFlag_Static;
- } else {
- error(name, "'static' is not allowed on this constant value declaration");
- }
- }
-
if (vd->is_using) {
if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) {
d->is_using = true;
@@ -2497,7 +2578,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
}
if (e->kind != Entity_Procedure) {
- if (fl != nullptr || c->foreign_context.in_export) {
+ if (fl != nullptr) {
AstKind kind = init->kind;
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
if (kind == Ast_ProcType) {
@@ -2525,8 +2606,6 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) {
CheckerContext c = *ctx;
if (foreign_library->kind == Ast_Ident) {
c.foreign_context.curr_library = foreign_library;
- } else if (foreign_library->kind == Ast_Implicit && foreign_library->Implicit.kind == Token_export) {
- c.foreign_context.in_export = true;
} else {
error(foreign_library, "Foreign block name must be an identifier or 'export'");
c.foreign_context.curr_library = nullptr;
diff --git a/src/checker.hpp b/src/checker.hpp
index abc349129..4420d6bb4 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -89,6 +89,8 @@ enum BuiltinProcId {
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
+ BuiltinProc_vector,
+
BuiltinProc_atomic_fence,
BuiltinProc_atomic_fence_acq,
BuiltinProc_atomic_fence_rel,
@@ -194,6 +196,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
// "Intrinsics"
+ {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
+
+
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
@@ -300,6 +305,8 @@ struct DeferredProcedure {
struct AttributeContext {
+ bool is_export;
+ bool is_static;
String link_name;
String link_prefix;
isize init_expr_list_count;
@@ -418,7 +425,6 @@ struct ForeignContext {
Ast * curr_library;
ProcCallingConvention default_cc;
String link_prefix;
- bool in_export;
};
typedef Array<Entity *> CheckerTypePath;
diff --git a/src/ir.cpp b/src/ir.cpp
index aca3c3ce9..0d5e3fc36 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3035,6 +3035,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
break;
case DeferredProcedure_in:
result_as_args = in_args;
+ break;
case DeferredProcedure_out:
result_as_args = ir_value_to_array(p, result);
break;
@@ -3214,6 +3215,8 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
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_enum(t)) {
+ ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type));
} else if (is_type_typeid(t)) {
irValue *i = ir_emit_bitcast(proc, key, t_uint);
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type));
@@ -4644,6 +4647,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
}
+
// bool <-> llvm bool
if (is_type_boolean(src) && dst == t_llvm_bool) {
return ir_emit(proc, ir_instr_conv(proc, irConv_trunc, value, src_type, t));
@@ -4906,7 +4910,13 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_load(proc, result);
}
-
+ if (is_type_untyped(src)) {
+ if (is_type_string(src) && is_type_string(dst)) {
+ irValue *result = ir_add_local_generated(proc, t, false);
+ ir_emit_store(proc, result, value);
+ 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));
@@ -6258,6 +6268,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
return ir_addr_load(proc, ir_build_addr(proc, expr));
case_end;
+ case_ast_node(ise, ImplicitSelectorExpr, expr);
+ TypeAndValue tav = type_and_value_of_expr(expr);
+ GB_ASSERT(tav.mode == Addressing_Constant);
+
+ return ir_add_module_constant(proc->module, tv.type, tv.value);
+ case_end;
+
case_ast_node(te, TernaryExpr, expr);
ir_emit_comment(proc, str_lit("TernaryExpr"));
@@ -7260,6 +7277,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
case Type_Array: et = bt->Array.elem; break;
case Type_Slice: et = bt->Slice.elem; break;
case Type_BitSet: et = bt->BitSet.elem; break;
+ case Type_SimdVector: et = bt->SimdVector.elem; break;
}
String proc_name = {};
@@ -7351,7 +7369,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
case Type_Array: {
if (cl->elems.count > 0) {
- // ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
defer (array_free(&temp_data));
@@ -8157,7 +8175,16 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
if (vd->is_mutable) {
irModule *m = proc->module;
- if (vd->is_static) {
+ bool is_static = false;
+ if (vd->names.count > 0) {
+ Entity *e = entity_of_ident(vd->names[0]);
+ if (e->flags & EntityFlag_Static) {
+ // NOTE(bill): If one of the entities is static, they all are
+ is_static = true;
+ }
+ }
+
+ if (is_static) {
for_array(i, vd->names) {
irValue *value = nullptr;
if (vd->values.count > 0) {
@@ -9987,6 +10014,18 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem));
break;
+
+ case Type_SimdVector:
+ ir_emit_comment(proc, str_lit("Type_SimdVector"));
+ tag = ir_emit_conv(proc, variant_ptr, t_type_info_simd_vector_ptr);
+ if (t->SimdVector.is_x86_mmx) {
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), v_true);
+ } else {
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->SimdVector.elem));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(type_size_of(t->SimdVector.elem)));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(t->SimdVector.count));
+ }
+ break;
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index a3fdc282b..97194e794 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -316,8 +316,11 @@ void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
if (t->Proc.return_by_pointer) {
ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
// ir_fprintf(f, "* sret noalias ");
- ir_write_string(f, str_lit("* noalias "));
- if (param_count > 0) ir_write_string(f, str_lit(", "));
+ // ir_write_string(f, str_lit("* noalias "));
+ ir_write_string(f, str_lit("*"));
+ if (param_count > 0 || t->Proc.calling_convention == ProcCC_Odin) {
+ ir_write_string(f, str_lit(", "));
+ }
}
isize param_index = 0;
for (isize i = 0; i < param_count; i++) {
@@ -574,6 +577,16 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
case Type_Opaque:
ir_print_type(f, m, strip_opaque_type(t));
return;
+
+ case Type_SimdVector:
+ if (t->SimdVector.is_x86_mmx) {
+ ir_write_str_lit(f, "x86_mmx");
+ } else {
+ ir_fprintf(f, "<%lld x ", t->SimdVector.count);;
+ ir_print_type(f, m, t->SimdVector.elem);
+ ir_write_byte(f, '>');
+ }
+ return;
}
}
@@ -802,6 +815,31 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
}
ir_write_byte(f, ']');
+ } else if (is_type_simd_vector(type)) {
+ ast_node(cl, CompoundLit, value.value_compound);
+
+ Type *elem_type = type->SimdVector.elem;
+ isize elem_count = cl->elems.count;
+ if (elem_count == 0) {
+ ir_write_str_lit(f, "zeroinitializer");
+ break;
+ }
+ GB_ASSERT_MSG(elem_count == type->SimdVector.count, "%td != %td", elem_count, type->SimdVector.count);
+
+ ir_write_byte(f, '<');
+
+ for (isize i = 0; i < elem_count; i++) {
+ if (i > 0) ir_write_str_lit(f, ", ");
+ TypeAndValue tav = cl->elems[i]->tav;
+ GB_ASSERT(tav.mode != Addressing_Invalid);
+ ir_print_compound_element(f, m, tav.value, elem_type);
+ }
+ for (isize i = elem_count; i < type->SimdVector.count; i++) {
+ if (i >= elem_count) ir_write_str_lit(f, ", ");
+ ir_print_compound_element(f, m, empty_exact_value, elem_type);
+ }
+
+ ir_write_byte(f, '>');
} else if (is_type_struct(type)) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
@@ -1052,6 +1090,7 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
+ case ProcCC_None: ir_write_str_lit(f, ""); break;
default: GB_PANIC("unknown calling convention: %d", cc);
}
}
@@ -1664,7 +1703,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_BinaryOp: {
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
Type *type = base_type(ir_type(bo->left));
- Type *elem_type = type;
+ Type *elem_type = base_array_type(type);
ir_fprintf(f, "%%%d = ", value->index);
diff --git a/src/main.cpp b/src/main.cpp
index 51a6856d1..beda80cad 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,10 +2,10 @@
#include "common.cpp"
#include "timings.cpp"
-#include "build_settings.cpp"
#include "tokenizer.cpp"
#include "big_int.cpp"
#include "exact_value.cpp"
+#include "build_settings.cpp"
#include "parser.hpp"
#include "checker.hpp"
@@ -207,6 +207,7 @@ enum BuildFlagKind {
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
BuildFlag_Collection,
+ BuildFlag_Define,
BuildFlag_BuildMode,
BuildFlag_Debug,
BuildFlag_CrossCompile,
@@ -242,6 +243,41 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
array_add(build_flags, flag);
}
+ExactValue build_param_to_exact_value(String name, String param) {
+ ExactValue value = {};
+ if (str_eq_ignore_case(param, str_lit("t")) ||
+ str_eq_ignore_case(param, str_lit("true"))) {
+ value = exact_value_bool(true);
+ } else if (str_eq_ignore_case(param, str_lit("f")) ||
+ str_eq_ignore_case(param, str_lit("false"))) {
+ value = exact_value_bool(false);
+ } else if (param.len > 0) {
+ if (param[0] == '"') {
+ value = exact_value_string(param);
+ if (value.kind == ExactValue_String) {
+ String s = value.value_string;
+ if (s.len > 1 && s[0] == '"' && s[s.len-1] == '"') {
+ value.value_string = substring(s, 1, s.len-1);
+ }
+ }
+ } else if (param[0] == '-' || param[0] == '+' || gb_is_between(param[0], '0', '9')) {
+ if (string_contains_char(param, '.')) {
+ value = exact_value_float_from_string(param);
+ } else {
+ value = exact_value_integer_from_string(param);
+ }
+ if (value.kind == ExactValue_Invalid) {
+ gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
+ }
+ }
+ } else {
+ gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
+ }
+
+ return value;
+}
+
+
bool parse_build_flags(Array<String> args) {
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
@@ -251,6 +287,7 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
+ add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
@@ -276,7 +313,8 @@ bool parse_build_flags(Array<String> args) {
String name = substring(flag, 1, flag.len);
isize end = 0;
for (; end < name.len; end++) {
- if (name[end] == '=') break;
+ if (name[end] == ':') break;
+ if (name[end] == '=') break; // IMPORTANT TODO(bill): DEPRECATE THIS!!!!
}
name = substring(name, 0, end);
String param = {};
@@ -306,7 +344,9 @@ bool parse_build_flags(Array<String> args) {
} else {
ok = true;
switch (bf.param_kind) {
- default: ok = false; break;
+ default:
+ ok = false;
+ break;
case BuildFlagParam_Boolean: {
if (str_eq_ignore_case(param, str_lit("t")) ||
str_eq_ignore_case(param, str_lit("true")) ||
@@ -529,6 +569,62 @@ bool parse_build_flags(Array<String> args) {
continue;
}
+
+ case BuildFlag_Define: {
+ GB_ASSERT(value.kind == ExactValue_String);
+ String str = value.value_string;
+ isize eq_pos = -1;
+ for (isize i = 0; i < str.len; i++) {
+ if (str[i] == '=') {
+ eq_pos = i;
+ break;
+ }
+ }
+ if (eq_pos < 0) {
+ gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
+ bad_flags = true;
+ break;
+ }
+ String name = substring(str, 0, eq_pos);
+ String value = substring(str, eq_pos+1, str.len);
+ if (name.len == 0 || value.len == 0) {
+ gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
+ bad_flags = true;
+ break;
+ }
+
+ if (!string_is_valid_identifier(name)) {
+ gb_printf_err("Defined constant name '%.*s' must be a valid identifier\n", LIT(name));
+ bad_flags = true;
+ break;
+ }
+
+ if (name == "_") {
+ gb_printf_err("Defined constant name cannot be an underscore\n");
+ bad_flags = true;
+ break;
+ }
+
+ HashKey key = hash_string(name);
+
+ if (map_get(&build_context.defined_values, key) != nullptr) {
+ gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
+ bad_flags = true;
+ break;
+ }
+
+ ExactValue v = build_param_to_exact_value(name, value);
+ if (v.kind != ExactValue_Invalid) {
+ map_set(&build_context.defined_values, key, v);
+ } else {
+ bad_flags = true;
+ }
+
+ break;
+ }
+
+
+
case BuildFlag_BuildMode: {
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
@@ -599,8 +695,13 @@ void show_timings(Checker *c, Timings *t) {
isize tokens = p->total_token_count;
isize files = 0;
isize packages = p->packages.count;
+ isize total_file_size = 0;
for_array(i, p->packages) {
files += p->packages[i]->files.count;
+ for_array(j, p->packages[i]->files) {
+ AstFile *file = p->packages[i]->files[j];
+ total_file_size += file->tokenizer.end - file->tokenizer.start;
+ }
}
#if 1
timings_print_all(t);
@@ -608,10 +709,11 @@ void show_timings(Checker *c, Timings *t) {
{
timings_print_all(t);
gb_printf("\n");
- gb_printf("Total Lines - %td\n", lines);
- gb_printf("Total Tokens - %td\n", tokens);
- gb_printf("Total Files - %td\n", files);
- gb_printf("Total Packages - %td\n", packages);
+ gb_printf("Total Lines - %td\n", lines);
+ gb_printf("Total Tokens - %td\n", tokens);
+ gb_printf("Total Files - %td\n", files);
+ gb_printf("Total Packages - %td\n", packages);
+ gb_printf("Total File Size - %td\n", total_file_size);
gb_printf("\n");
}
{
@@ -623,6 +725,9 @@ void show_timings(Checker *c, Timings *t) {
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
+ gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
+ gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
+
gb_printf("\n");
}
{
@@ -634,6 +739,8 @@ void show_timings(Checker *c, Timings *t) {
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
+ gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
+ gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
gb_printf("\n");
}
{
@@ -643,6 +750,8 @@ void show_timings(Checker *c, Timings *t) {
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
+ gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
+ gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
gb_printf("\n");
}
#endif
@@ -741,6 +850,8 @@ int main(int arg_count, char **arg_ptr) {
// NOTE(bill): 'core' cannot be (re)defined by the user
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
+ map_init(&build_context.defined_values, heap_allocator());
+
Array<String> args = setup_args(arg_count, arg_ptr);
String command = args[1];
diff --git a/src/parser.cpp b/src/parser.cpp
index a62bac233..84c03587d 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -25,6 +25,11 @@ Token ast_token(Ast *node) {
return ast_token(node->SelectorExpr.selector);
}
return node->SelectorExpr.token;
+ case Ast_ImplicitSelectorExpr:
+ if (node->ImplicitSelectorExpr.selector != nullptr) {
+ return ast_token(node->ImplicitSelectorExpr.selector);
+ }
+ return node->ImplicitSelectorExpr.token;
case Ast_IndexExpr: return node->IndexExpr.open;
case Ast_SliceExpr: return node->SliceExpr.open;
case Ast_Ellipsis: return node->Ellipsis.token;
@@ -165,6 +170,9 @@ Ast *clone_ast(Ast *node) {
n->SelectorExpr.expr = clone_ast(n->SelectorExpr.expr);
n->SelectorExpr.selector = clone_ast(n->SelectorExpr.selector);
break;
+ case Ast_ImplicitSelectorExpr:
+ n->ImplicitSelectorExpr.selector = clone_ast(n->ImplicitSelectorExpr.selector);
+ break;
case Ast_IndexExpr:
n->IndexExpr.expr = clone_ast(n->IndexExpr.expr);
n->IndexExpr.index = clone_ast(n->IndexExpr.index);
@@ -504,11 +512,20 @@ Ast *ast_call_expr(AstFile *f, Ast *proc, Array<Ast *> args, Token open, Token c
Ast *ast_selector_expr(AstFile *f, Token token, Ast *expr, Ast *selector) {
Ast *result = alloc_ast_node(f, Ast_SelectorExpr);
+ result->SelectorExpr.token = token;
result->SelectorExpr.expr = expr;
result->SelectorExpr.selector = selector;
return result;
}
+Ast *ast_implicit_selector_expr(AstFile *f, Token token, Ast *selector) {
+ Ast *result = alloc_ast_node(f, Ast_ImplicitSelectorExpr);
+ result->ImplicitSelectorExpr.token = token;
+ result->ImplicitSelectorExpr.selector = selector;
+ return result;
+}
+
+
Ast *ast_index_expr(AstFile *f, Ast *expr, Ast *index, Token open, Token close) {
Ast *result = alloc_ast_node(f, Ast_IndexExpr);
result->IndexExpr.expr = expr;
@@ -1199,7 +1216,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
case Token_package:
case Token_foreign:
case Token_import:
- case Token_export:
case Token_if:
case Token_for:
@@ -1209,7 +1225,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
case Token_defer:
case Token_asm:
case Token_using:
- case Token_static:
case Token_break:
case Token_continue:
@@ -1614,7 +1629,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
case Token_offset_of:
return parse_call_expr(f, ast_implicit(f, advance_token(f)));
-
case Token_String:
return ast_basic_lit(f, advance_token(f));
@@ -2279,6 +2293,12 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) {
Ast *expr = parse_unary_expr(f, lhs);
return ast_unary_expr(f, token, expr);
}
+
+ case Token_Period: {
+ Token token = expect_token(f, Token_Period);
+ Ast *ident = parse_ident(f);
+ return ast_implicit_selector_expr(f, token, ident);
+ }
}
return parse_atom_expr(f, parse_operand(f, lhs), lhs);
@@ -2452,9 +2472,7 @@ void parse_foreign_block_decl(AstFile *f, Array<Ast *> *decls) {
Ast *parse_foreign_block(AstFile *f, Token token) {
CommentGroup *docs = f->lead_comment;
Ast *foreign_library = nullptr;
- if (f->curr_token.kind == Token_export) {
- foreign_library = ast_implicit(f, expect_token(f, Token_export));
- } else if (f->curr_token.kind == Token_OpenBrace) {
+ if (f->curr_token.kind == Token_OpenBrace) {
foreign_library = ast_ident(f, blank_token);
} else {
foreign_library = parse_ident(f);
@@ -2700,6 +2718,7 @@ ProcCallingConvention string_to_calling_convention(String s) {
if (s == "std") return ProcCC_StdCall;
if (s == "fastcall") return ProcCC_FastCall;
if (s == "fast") return ProcCC_FastCall;
+ if (s == "none") return ProcCC_None;
return ProcCC_Invalid;
}
@@ -3589,7 +3608,6 @@ Ast *parse_foreign_decl(AstFile *f) {
Token token = expect_token(f, Token_foreign);
switch (f->curr_token.kind) {
- case Token_export:
case Token_Ident:
case Token_OpenBrace:
return parse_foreign_block(f, token);
@@ -3666,6 +3684,7 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo
f->curr_token.kind != Token_EOF) {
Ast *elem = nullptr;
elem = parse_ident(f);
+
if (f->curr_token.kind == Token_Eq) {
Token eq = expect_token(f, Token_Eq);
Ast *value = parse_value(f);
@@ -3731,9 +3750,6 @@ Ast *parse_stmt(AstFile *f) {
case Token_import:
return parse_import_decl(f, ImportDecl_Standard);
- // case Token_export:
- // return parse_export_decl(f);
-
case Token_if: return parse_if_stmt(f);
case Token_when: return parse_when_stmt(f);
@@ -3756,33 +3772,33 @@ Ast *parse_stmt(AstFile *f) {
return s;
}
- case Token_static: {
- CommentGroup *docs = f->lead_comment;
- Token token = expect_token(f, Token_static);
-
- Ast *decl = nullptr;
- Array<Ast *> list = parse_lhs_expr_list(f);
- if (list.count == 0) {
- syntax_error(token, "Illegal use of 'static' statement");
- expect_semicolon(f, nullptr);
- return ast_bad_stmt(f, token, f->curr_token);
- }
-
- expect_token_after(f, Token_Colon, "identifier list");
- decl = parse_value_decl(f, list, docs);
-
- if (decl != nullptr && decl->kind == Ast_ValueDecl) {
- if (decl->ValueDecl.is_mutable) {
- decl->ValueDecl.is_static = true;
- } else {
- error(token, "'static' may only be currently used with variable declaration");
- }
- return decl;
- }
-
- syntax_error(token, "Illegal use of 'static' statement");
- return ast_bad_stmt(f, token, f->curr_token);
- } break;
+ // case Token_static: {
+ // CommentGroup *docs = f->lead_comment;
+ // Token token = expect_token(f, Token_static);
+
+ // Ast *decl = nullptr;
+ // Array<Ast *> list = parse_lhs_expr_list(f);
+ // if (list.count == 0) {
+ // syntax_error(token, "Illegal use of 'static' statement");
+ // expect_semicolon(f, nullptr);
+ // return ast_bad_stmt(f, token, f->curr_token);
+ // }
+
+ // expect_token_after(f, Token_Colon, "identifier list");
+ // decl = parse_value_decl(f, list, docs);
+
+ // if (decl != nullptr && decl->kind == Ast_ValueDecl) {
+ // if (decl->ValueDecl.is_mutable) {
+ // decl->ValueDecl.is_static = true;
+ // } else {
+ // error(token, "'static' may only be currently used with variable declaration");
+ // }
+ // return decl;
+ // }
+
+ // syntax_error(token, "Illegal use of 'static' statement");
+ // return ast_bad_stmt(f, token, f->curr_token);
+ // } break;
case Token_using: {
CommentGroup *docs = f->lead_comment;
diff --git a/src/parser.hpp b/src/parser.hpp
index fabb7ff8e..e08648eca 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -151,7 +151,6 @@ enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
ProcTag_require_results = 1<<4,
- ProcTag_no_context = 1<<6,
};
enum ProcCallingConvention {
@@ -166,6 +165,9 @@ enum ProcCallingConvention {
// ProcCC_VectorCall,
// ProcCC_ClrCall,
+ ProcCC_None,
+
+
ProcCC_ForeignBlockDefault = -1,
};
@@ -242,6 +244,7 @@ AST_KIND(_ExprBegin, "", bool) \
AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \
AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \
AST_KIND(SelectorExpr, "selector expression", struct { Token token; Ast *expr, *selector; }) \
+ AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \
AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \
AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \
AST_KIND(SliceExpr, "slice expression", struct { \
@@ -373,7 +376,6 @@ AST_KIND(_DeclBegin, "", bool) \
Array<Ast *> attributes; \
CommentGroup *docs; \
CommentGroup *comment; \
- bool is_static; \
bool is_using; \
bool is_mutable; \
}) \
diff --git a/src/string.cpp b/src/string.cpp
index 5f4a28960..39219789f 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -308,7 +308,6 @@ String directory_from_path(String const &s) {
return substring(s, 0, i);
}
-
String concatenate_strings(gbAllocator a, String const &x, String const &y) {
isize len = x.len+y.len;
u8 *data = gb_alloc_array(a, u8, len+1);
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 02770e371..d7a39e824 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -82,7 +82,6 @@ TOKEN_KIND(Token__OperatorEnd, ""), \
\
TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_import, "import"), \
- TOKEN_KIND(Token_export, "export"), \
TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_package, "package"), \
TOKEN_KIND(Token_typeid, "typeid"), \
@@ -101,14 +100,12 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_proc, "proc"), \
- TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_bit_field, "bit_field"), \
TOKEN_KIND(Token_bit_set, "bit_set"), \
TOKEN_KIND(Token_map, "map"), \
- TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_auto_cast, "auto_cast"), \
TOKEN_KIND(Token_cast, "cast"), \
@@ -123,6 +120,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_align_of, "align_of"), \
TOKEN_KIND(Token_offset_of, "offset_of"), \
TOKEN_KIND(Token_type_of, "type_of"), \
+ TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_const, "const"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_yield, "yield"), \
diff --git a/src/types.cpp b/src/types.cpp
index 52c06ef71..5aa2ab6e1 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -198,6 +198,7 @@ struct TypeUnion {
bool has_proc_default_values; \
bool has_named_results; \
bool diverging; /* no return */ \
+ u64 tags; \
isize specialization_count; \
ProcCallingConvention calling_convention; \
}) \
@@ -215,6 +216,12 @@ struct TypeUnion {
i64 lower; \
i64 upper; \
}) \
+ TYPE_KIND(SimdVector, struct { \
+ i64 count; \
+ Type *elem; \
+ bool is_x86_mmx; \
+ }) \
+
@@ -460,13 +467,13 @@ gb_global Type *t_type_info_map = nullptr;
gb_global Type *t_type_info_bit_field = nullptr;
gb_global Type *t_type_info_bit_set = nullptr;
gb_global Type *t_type_info_opaque = nullptr;
+gb_global Type *t_type_info_simd_vector = nullptr;
gb_global Type *t_type_info_named_ptr = nullptr;
gb_global Type *t_type_info_integer_ptr = nullptr;
gb_global Type *t_type_info_rune_ptr = nullptr;
gb_global Type *t_type_info_float_ptr = nullptr;
gb_global Type *t_type_info_complex_ptr = nullptr;
-gb_global Type *t_type_info_quaternion_ptr = nullptr;
gb_global Type *t_type_info_any_ptr = nullptr;
gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr;
@@ -484,6 +491,7 @@ gb_global Type *t_type_info_map_ptr = nullptr;
gb_global Type *t_type_info_bit_field_ptr = nullptr;
gb_global Type *t_type_info_bit_set_ptr = nullptr;
gb_global Type *t_type_info_opaque_ptr = nullptr;
+gb_global Type *t_type_info_simd_vector_ptr = nullptr;
gb_global Type *t_allocator = nullptr;
gb_global Type *t_allocator_ptr = nullptr;
@@ -496,6 +504,8 @@ gb_global Type *t_source_code_location_ptr = nullptr;
gb_global Type *t_map_key = nullptr;
gb_global Type *t_map_header = nullptr;
+gb_global Type *t_vector_x86_mmx = nullptr;
+
i64 type_size_of (Type *t);
@@ -722,6 +732,13 @@ Type *alloc_type_bit_set() {
+Type *alloc_type_simd_vector(i64 count, Type *elem) {
+ Type *t = alloc_type(Type_SimdVector);
+ t->SimdVector.count = count;
+ t->SimdVector.elem = elem;
+ return t;
+}
+
////////////////////////////////////////////////////////////////
@@ -958,11 +975,20 @@ bool is_type_poly_proc(Type *t) {
t = base_type(t);
return t->kind == Type_Proc && t->Proc.is_polymorphic;
}
+bool is_type_simd_vector(Type *t) {
+ t = base_type(t);
+ return t->kind == Type_SimdVector;
+}
+
Type *base_array_type(Type *t) {
if (is_type_array(t)) {
t = base_type(t);
return t->Array.elem;
}
+ if (is_type_simd_vector(t)) {
+ t = base_type(t);
+ return t->SimdVector.elem;
+ }
return t;
}
@@ -972,6 +998,7 @@ bool is_type_generic(Type *t) {
}
+
Type *core_array_type(Type *t) {
for (;;) {
Type *prev = t;
@@ -1193,6 +1220,25 @@ Type *bit_set_to_int(Type *t) {
return nullptr;
}
+bool is_type_valid_vector_elem(Type *t) {
+ t = base_type(t);
+ if (t->kind == Type_Basic) {
+ if (t->Basic.flags & BasicFlag_EndianLittle) {
+ return false;
+ }
+ if (t->Basic.flags & BasicFlag_EndianBig) {
+ return false;
+ }
+ if (is_type_integer(t)) {
+ return true;
+ }
+ if (is_type_float(t)) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool is_type_indexable(Type *t) {
Type *bt = base_type(t);
@@ -1637,6 +1683,18 @@ bool are_types_identical(Type *x, Type *y) {
are_types_identical(x->Map.value, y->Map.value);
}
break;
+
+ case Type_SimdVector:
+ if (y->kind == Type_SimdVector) {
+ if (x->SimdVector.is_x86_mmx == y->SimdVector.is_x86_mmx) {
+ if (x->SimdVector.is_x86_mmx) {
+ return true;
+ } else if (x->SimdVector.count == y->SimdVector.count) {
+ return are_types_identical(x->SimdVector.elem, y->SimdVector.elem);
+ }
+ }
+ }
+ break;
}
return false;
@@ -1681,65 +1739,6 @@ Type *default_type(Type *type) {
return type;
}
-/*
-// NOTE(bill): Valid Compile time execution #run type
-bool is_type_cte_safe(Type *type) {
- type = default_type(base_type(type));
- switch (type->kind) {
- case Type_Basic:
- switch (type->Basic.kind) {
- case Basic_rawptr:
- case Basic_any:
- return false;
- }
- return true;
-
- case Type_Pointer:
- return false;
-
- case Type_Array:
- return is_type_cte_safe(type->Array.elem);
-
- case Type_DynamicArray:
- return false;
- case Type_Map:
- return false;
-
- case Type_Slice:
- return false;
-
- case Type_Struct: {
- if (type->Struct.is_raw_union) {
- return false;
- }
- for_array(i, type->Struct.fields) {
- Entity *v = type->Struct.fields[i];
- if (!is_type_cte_safe(v->type)) {
- return false;
- }
- }
- return true;
- }
-
- case Type_Tuple: {
- for_array(i, type->Tuple.variables) {
- Entity *v = type->Tuple.variables[i];
- if (!is_type_cte_safe(v->type)) {
- return false;
- }
- }
- return true;
- }
-
- case Type_Proc:
- // TODO(bill): How should I handle procedures in the CTE stage?
- // return type->Proc.calling_convention == ProcCC_Odin;
- return false;
- }
-
- return false;
-}
- */
i64 union_variant_index(Type *u, Type *v) {
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
@@ -2389,7 +2388,18 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
if (bits <= 32) return 4;
if (bits <= 64) return 8;
return 8; // NOTE(bill): Could be an invalid range so limit it for now
+ }
+ case Type_SimdVector: {
+ if (t->SimdVector.is_x86_mmx) {
+ return 8;
+ }
+ // align of
+ i64 count = t->SimdVector.count;
+ Type *elem = t->SimdVector.elem;
+ i64 size = count * type_size_of_internal(elem, path);
+ // IMPORTANT TODO(bill): Figure out the alignment of vector types
+ return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
}
}
@@ -2622,6 +2632,15 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
if (bits <= 64) return 8;
return 8; // NOTE(bill): Could be an invalid range so limit it for now
}
+
+ case Type_SimdVector: {
+ if (t->SimdVector.is_x86_mmx) {
+ return 8;
+ }
+ i64 count = t->SimdVector.count;
+ Type *elem = t->SimdVector.elem;
+ return count * type_size_of_internal(elem, path);
+ }
}
// Catch all
@@ -2894,6 +2913,9 @@ gbString write_type_to_string(gbString str, Type *type) {
case ProcCC_FastCall:
str = gb_string_appendc(str, " \"fastcall\" ");
break;
+ case ProcCC_None:
+ str = gb_string_appendc(str, " \"none\" ");
+ break;
// case ProcCC_VectorCall:
// str = gb_string_appendc(str, " \"vectorcall\" ");
// break;
@@ -2947,6 +2969,17 @@ gbString write_type_to_string(gbString str, Type *type) {
}
str = gb_string_appendc(str, "]");
break;
+
+ case Type_SimdVector:
+ if (type->SimdVector.is_x86_mmx) {
+ return "intrinsics.x86_mmx";
+ } else {
+ str = gb_string_appendc(str, "intrinsics.vector(");
+ str = gb_string_append_fmt(str, "%d, ", cast(int)type->SimdVector.count);
+ str = write_type_to_string(str, type->SimdVector.elem);
+ str = gb_string_appendc(str, ")");
+ }
+ break;
}
return str;