aboutsummaryrefslogtreecommitdiff
path: root/src/check_stmt.cpp
diff options
context:
space:
mode:
authorflysand7 <thebumboni@gmail.com>2025-03-02 20:05:55 +1100
committerflysand7 <thebumboni@gmail.com>2025-03-02 20:05:55 +1100
commit698c510ba7bb5794b3eeed7aecb8327386f00da7 (patch)
tree8c376debaf24f3ac8782192310e49e730509cdf9 /src/check_stmt.cpp
parent5d290dce069cb257b2e3effdd4e9b1e7dc21e722 (diff)
parentf390598b403eb336276ef9161753bf26d24d0d01 (diff)
Merge branch 'master' into docs-simd
Diffstat (limited to 'src/check_stmt.cpp')
-rw-r--r--src/check_stmt.cpp75
1 files changed, 65 insertions, 10 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 2418fcc5c..e81996566 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -894,15 +894,49 @@ gb_internal void error_var_decl_identifier(Ast *name) {
}
}
-gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
+gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(irs, UnrollRangeStmt, node);
check_open_scope(ctx, node);
+ defer (check_close_scope(ctx));
Type *val0 = nullptr;
Type *val1 = nullptr;
Entity *entities[2] = {};
isize entity_count = 0;
+ i64 unroll_count = -1;
+
+ if (irs->args.count > 0) {
+ if (irs->args.count > 1) {
+ error(irs->args[1], "#unroll only supports a single argument for the unroll per loop amount");
+ }
+ Ast *arg = irs->args[0];
+ if (arg->kind == Ast_FieldValue) {
+ error(arg, "#unroll does not yet support named arguments");
+ arg = arg->FieldValue.value;
+ }
+
+ Operand x = {};
+ check_expr(ctx, &x, arg);
+ if (x.mode != Addressing_Constant || !is_type_integer(x.type)) {
+ gbString s = expr_to_string(x.expr);
+ error(x.expr, "Expected a constant integer for #unroll, got '%s'", s);
+ gb_string_free(s);
+ } else {
+ ExactValue value = exact_value_to_integer(x.value);
+ i64 v = exact_value_to_i64(value);
+ if (v < 1) {
+ error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v);
+ } else {
+ unroll_count = v;
+ if (v > 1024) {
+ error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v);
+ }
+ }
+
+ }
+ }
+
Ast *expr = unparen_expr(irs->expr);
ExactValue inline_for_depth = exact_value_i64(0);
@@ -946,18 +980,39 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
val0 = t_rune;
val1 = t_int;
inline_for_depth = exact_value_i64(operand.value.value_string.len);
+ if (unroll_count > 0) {
+ error(node, "#unroll(%lld) does not support strings", cast(long long)unroll_count);
+ }
}
break;
case Type_Array:
val0 = t->Array.elem;
val1 = t_int;
- inline_for_depth = exact_value_i64(t->Array.count);
+ inline_for_depth = unroll_count > 0 ? exact_value_i64(unroll_count) : exact_value_i64(t->Array.count);
break;
case Type_EnumeratedArray:
val0 = t->EnumeratedArray.elem;
val1 = t->EnumeratedArray.index;
+ if (unroll_count > 0) {
+ error(node, "#unroll(%lld) does not support enumerated arrays", cast(long long)unroll_count);
+ }
inline_for_depth = exact_value_i64(t->EnumeratedArray.count);
break;
+
+ case Type_Slice:
+ if (unroll_count > 0) {
+ val0 = t->Slice.elem;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(unroll_count);
+ }
+ break;
+ case Type_DynamicArray:
+ if (unroll_count > 0) {
+ val0 = t->DynamicArray.elem;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(unroll_count);
+ }
+ break;
}
}
@@ -967,7 +1022,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t);
gb_string_free(t);
gb_string_free(s);
- } else if (operand.mode != Addressing_Constant) {
+ } else if (operand.mode != Addressing_Constant && unroll_count <= 0) {
error(operand.expr, "An '#unroll for' expression must be known at compile time");
}
}
@@ -1050,8 +1105,6 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
check_stmt(ctx, irs->body, mod_flags);
-
- check_close_scope(ctx);
}
gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
@@ -1393,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
Ast *nil_seen = nullptr;
- PtrSet<Type *> seen = {};
- defer (ptr_set_destroy(&seen));
+ TypeSet seen = {};
+ defer (type_set_destroy(&seen));
for (Ast *stmt : bs->stmts) {
if (stmt->kind != Ast_CaseClause) {
@@ -1462,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
GB_PANIC("Unknown type to type switch statement");
}
- if (type_ptr_set_update(&seen, y.type)) {
+ if (type_set_update(&seen, y.type)) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(y.expr,
@@ -1516,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count);
for (Type *t : variants) {
- if (!type_ptr_set_exists(&seen, t)) {
+ if (!type_set_exists(&seen, t)) {
array_add(&unhandled, t);
}
}
@@ -2605,6 +2658,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
if (cond && cond->kind == Ast_BinaryExpr &&
cond->BinaryExpr.left && cond->BinaryExpr.right &&
cond->BinaryExpr.op.kind == Token_GtEq &&
+ type_of_expr(cond->BinaryExpr.left) != nullptr &&
is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
is_exact_value_zero(cond->BinaryExpr.right->tav.value)) {
@@ -2612,6 +2666,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
} else if (cond && cond->kind == Ast_BinaryExpr &&
cond->BinaryExpr.left && cond->BinaryExpr.right &&
cond->BinaryExpr.op.kind == Token_LtEq &&
+ type_of_expr(cond->BinaryExpr.right) != nullptr &&
is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
is_exact_value_zero(cond->BinaryExpr.left->tav.value)) {
@@ -2677,7 +2732,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
case_end;
case_ast_node(irs, UnrollRangeStmt, node);
- check_inline_range_stmt(ctx, node, mod_flags);
+ check_unroll_range_stmt(ctx, node, mod_flags);
case_end;
case_ast_node(ss, SwitchStmt, node);