diff --git a/CMakeLists.txt b/CMakeLists.txt index 7391b7349..8675cb046 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ set(LLVM_LINK_COMPONENTS llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS}) -file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR}) +file(COPY ${CMAKE_SOURCE_DIR}/lib DESTINATION ${CMAKE_BINARY_DIR}) # These don't seem to be reliable on windows. if(UNIX) diff --git a/resources/lib/std/array.c3 b/lib/std/array.c3 similarity index 100% rename from resources/lib/std/array.c3 rename to lib/std/array.c3 diff --git a/resources/lib/std/atomic.c3 b/lib/std/atomic.c3 similarity index 100% rename from resources/lib/std/atomic.c3 rename to lib/std/atomic.c3 diff --git a/resources/lib/std/builtin.c3 b/lib/std/builtin.c3 similarity index 100% rename from resources/lib/std/builtin.c3 rename to lib/std/builtin.c3 diff --git a/resources/lib/std/cinterop.c3 b/lib/std/cinterop.c3 similarity index 100% rename from resources/lib/std/cinterop.c3 rename to lib/std/cinterop.c3 diff --git a/resources/lib/std/enumset.c3 b/lib/std/enumset.c3 similarity index 100% rename from resources/lib/std/enumset.c3 rename to lib/std/enumset.c3 diff --git a/resources/lib/std/env.c3 b/lib/std/env.c3 similarity index 100% rename from resources/lib/std/env.c3 rename to lib/std/env.c3 diff --git a/resources/lib/std/hash/adler32.c3 b/lib/std/hash/adler32.c3 similarity index 100% rename from resources/lib/std/hash/adler32.c3 rename to lib/std/hash/adler32.c3 diff --git a/resources/lib/std/hash/crc32.c3 b/lib/std/hash/crc32.c3 similarity index 100% rename from resources/lib/std/hash/crc32.c3 rename to lib/std/hash/crc32.c3 diff --git a/resources/lib/std/hash/crc64.c3 b/lib/std/hash/crc64.c3 similarity index 100% rename from resources/lib/std/hash/crc64.c3 rename to lib/std/hash/crc64.c3 diff --git a/resources/lib/std/io.c3 b/lib/std/io.c3 similarity index 100% rename from resources/lib/std/io.c3 rename to lib/std/io.c3 diff --git a/resources/lib/std/libc.c3 b/lib/std/libc.c3 similarity index 100% rename from resources/lib/std/libc.c3 rename to lib/std/libc.c3 diff --git a/resources/lib/std/linkedlist.c3 b/lib/std/linkedlist.c3 similarity index 100% rename from resources/lib/std/linkedlist.c3 rename to lib/std/linkedlist.c3 diff --git a/resources/lib/std/list.c3 b/lib/std/list.c3 similarity index 100% rename from resources/lib/std/list.c3 rename to lib/std/list.c3 diff --git a/resources/lib/std/math.c3 b/lib/std/math.c3 similarity index 99% rename from resources/lib/std/math.c3 rename to lib/std/math.c3 index 137499b04..96e3253b7 100644 --- a/resources/lib/std/math.c3 +++ b/lib/std/math.c3 @@ -126,3 +126,7 @@ fn double ceil(double x) @inline { return $$ceil(x); } + + + + diff --git a/lib/std/math.simple_random.c3 b/lib/std/math.simple_random.c3 new file mode 100644 index 000000000..97f992404 --- /dev/null +++ b/lib/std/math.simple_random.c3 @@ -0,0 +1,47 @@ +module math; + +struct SimpleRandom +{ + long seed; +} + +private const long SIMPLE_RANDOM_MULTIPLIER = 0x5DEECE66Di64; +private const long SIMPLE_RANDOM_ADDEND = 0xB; +private const long SIMPLE_RANDOM_MASK = (1i64 << 48) - 1; + +private fn long simple_random_initial_scramble(long seed) +{ + return (seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK; +} + +private fn int SimpleRandom.next(SimpleRandom* r, int bits) +{ + long nextseed = (r.seed * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK; + r.seed = nextseed; + return (int)nextseed >> (48 - bits); +} + +fn void SimpleRandom.set_seed(SimpleRandom* r, long seed) +{ + r.seed = simple_random_initial_scramble(seed); +} + +fn int SimpleRandom.next_int(SimpleRandom* r) +{ + return r.next(32) @inline; +} + +fn bool SimpleRandom.next_bool(SimpleRandom* r) +{ + return r.next(1) != 0; +} + +fn float SimpleRandom.next_float(SimpleRandom* r) +{ + return r.next(24) / (float)(1 << 24); +} + +fn double SimpleRandom.next_double(SimpleRandom* r) +{ + return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53; +} diff --git a/resources/lib/std/mem.c3 b/lib/std/mem.c3 similarity index 100% rename from resources/lib/std/mem.c3 rename to lib/std/mem.c3 diff --git a/resources/lib/std/os/linux.c3 b/lib/std/os/linux.c3 similarity index 100% rename from resources/lib/std/os/linux.c3 rename to lib/std/os/linux.c3 diff --git a/resources/lib/std/os/macos.c3 b/lib/std/os/macos.c3 similarity index 100% rename from resources/lib/std/os/macos.c3 rename to lib/std/os/macos.c3 diff --git a/resources/lib/std/os/windows.c3 b/lib/std/os/windows.c3 similarity index 100% rename from resources/lib/std/os/windows.c3 rename to lib/std/os/windows.c3 diff --git a/resources/lib/std/runtime.c3 b/lib/std/runtime.c3 similarity index 100% rename from resources/lib/std/runtime.c3 rename to lib/std/runtime.c3 diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index 9dd41a282..48d57beca 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -291,11 +291,12 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) AlignSize type_alloca_alignment(Type *type) { - if (platform_target.abi == ABI_X64 || platform_target.abi == ABI_WIN64) + AlignSize align = type_abi_alignment(type); + if (align < 16 && (platform_target.abi == ABI_X64 || platform_target.abi == ABI_WIN64)) { type = type_lowering(type); if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16; } - return type_abi_alignment(type); + return align; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index effae5064..48efdee66 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1607,6 +1607,7 @@ extern const char *kw_max; extern const char *kw_min; extern const char *kw_elements; extern const char *kw_align; + extern const char *kw_deprecated; extern const char *kw_distinct; extern const char *kw_ensure; @@ -1625,6 +1626,7 @@ extern const char *kw_require; extern const char *kw_pure; extern const char *kw_param; extern const char *kw_ptr; +extern const char *kw_values; extern const char *kw_errors; extern const char *kw___ceil; extern const char *kw___round; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 379d8a076..ce1c9bb75 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -582,6 +582,7 @@ static inline void llvm_emit_vector_subscript(GenContext *c, BEValue *value, Exp } } + /** * Expand foo[123] or someCall()[n] or some such. * Evaluation order is left to right. @@ -621,7 +622,7 @@ static inline void gencontext_emit_subscript(GenContext *c, BEValue *value, Expr } llvm_emit_ptr_from_array(c, value); - assert(llvm_value_is_addr(value)); + llvm_value_addr(c, value); // Now calculate the index: BEValue index; llvm_emit_expr(c, &index, index_expr); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8626a1cc6..ee603098c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2472,6 +2472,59 @@ static Type *sema_expr_find_indexable_type_recursively(Type **type, Expr **paren } } +static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, uint32_t index) +{ + switch (initializer->kind) + { + case CONST_INIT_ZERO: + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + case CONST_INIT_VALUE: + return initializer; + case CONST_INIT_ARRAY_FULL: + return initializer->init_array_full[index]; + case CONST_INIT_ARRAY: + { + ConstInitializer **sub_values = initializer->init_array.elements; + VECEACH(sub_values, i) + { + ConstInitializer *init = sub_values[i]; + assert(init->kind == CONST_INIT_ARRAY_VALUE); + if (init->init_array_value.index == index) return init->init_array_value.element; + } + return NULL; + } + case CONST_INIT_ARRAY_VALUE: + UNREACHABLE + } +} +static inline bool sema_expr_index_const_list(Expr *const_list, Expr *index, Expr *result) +{ + assert(index->expr_kind == EXPR_CONST && index->const_expr.const_kind == CONST_INTEGER); + if (!int_fits(index->const_expr.ixx, TYPE_U32)) return false; + + uint32_t idx = index->const_expr.ixx.i.low; + assert(const_list->const_expr.const_kind == CONST_LIST); + + ConstInitializer *initializer = initializer_for_index(const_list->const_expr.list, idx); + ConstInitType kind = initializer ? initializer->kind : CONST_INIT_ZERO; + switch (kind) + { + case CONST_INIT_ZERO: + expr_rewrite_to_int_const(result, type_int, 0, true); + return true; + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + case CONST_INIT_ARRAY: + case CONST_INIT_ARRAY_FULL: + case CONST_INIT_ARRAY_VALUE: + return false; + case CONST_INIT_VALUE: + expr_replace(result, initializer->init_value); + return true; + } +} + static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, bool is_addr) { assert(expr->expr_kind == EXPR_SUBSCRIPT || expr->expr_kind == EXPR_SUBSCRIPT_ADDR); @@ -2599,8 +2652,18 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (!expr_check_index_in_range(context, current_type, index, false, expr->subscript_expr.from_back, &remove_from_back)) return false; if (remove_from_back) expr->subscript_expr.from_back = false; + if (is_addr) + { + inner_type = type_get_ptr(inner_type); + } + else + { + if (current_expr->expr_kind == EXPR_CONST && current_expr->const_expr.list && index->expr_kind == EXPR_CONST) + { + if (sema_expr_index_const_list(current_expr, index, expr)) return true; + } + } expr->subscript_expr.expr = current_expr; - if (is_addr) inner_type = type_get_ptr(inner_type); expr->type = type_get_opt_fail(inner_type, failable); return true; } @@ -2828,6 +2891,31 @@ static TokenId sema_expr_resolve_access_child(Expr *child) return INVALID_TOKEN_ID; } +static inline void expr_replace_with_enum_array(Expr *enum_array_expr, Decl *enum_decl) +{ + Decl **values = enum_decl->enums.values; + SourceSpan span = enum_array_expr->span; + Expr *initializer = expr_new(EXPR_INITIALIZER_LIST, span); + ArraySize elements = vec_size(values); + Expr **element_values = elements > 0 ? VECNEW(Expr*, elements) : NULL; + Type *kind = enum_decl->type; + for (ArraySize i = 0; i < elements; i++) + { + Decl *decl = values[i]; + Expr *expr = expr_new(EXPR_CONST, span); + expr->const_expr.const_kind = CONST_ENUM; + expr->const_expr.enum_val = decl; + expr->type = kind; + expr->resolve_status = RESOLVE_DONE; + vec_add(element_values, expr); + } + initializer->initializer_list = element_values; + enum_array_expr->expr_kind = EXPR_COMPOUND_LITERAL; + enum_array_expr->expr_compound_literal.initializer = initializer; + enum_array_expr->expr_compound_literal.type_info = type_info_new_base(type_get_array(kind, elements), span); + enum_array_expr->resolve_status = RESOLVE_NOT_DONE; +} + static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, TypeInfo *parent, bool was_group, bool is_macro, TokenId identifier_token) { // 1. Foo*.sizeof is not allowed, it must be (Foo*).sizeof @@ -2916,6 +3004,12 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp expr_replace(expr, max); return true; } + if (name == kw_values) + { + expr_replace_with_enum_array(expr, decl); + return sema_analyse_expr(context, expr); + return true; + } if (name == kw_min) { Expr *min = enum_minmax_value(decl, BINARYOP_LT); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 225c8f3d8..d9aad3ba2 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -61,6 +61,7 @@ const char *kw_pure; const char *kw_reqparse; const char *kw_require; const char *kw_std; +const char *kw_values; const char *kw___ceil; const char *kw___round; const char *kw___sqrt; @@ -152,6 +153,7 @@ void symtab_init(uint32_t capacity) kw_pure = KW_DEF("pure"); kw_require = KW_DEF("require"); kw_std = KW_DEF("std"); + kw_values = KW_DEF("values"); kw___ceil = KW_DEF("__ceil"); kw___round = KW_DEF("__round"); kw___sqrt = KW_DEF("__sqrt"); diff --git a/test/test_suite/enumerations/enum_values.c3t b/test/test_suite/enumerations/enum_values.c3t new file mode 100644 index 000000000..fa3a1bc47 --- /dev/null +++ b/test/test_suite/enumerations/enum_values.c3t @@ -0,0 +1,44 @@ +// #target: x64-darwin + +module test; + +enum Foo +{ + ABC = 3, + BCD = 123 +} + +int z = Foo.min; +int w = Foo.max; +Foo zfok = Foo.values[0]; +Foo[] zw = &&Foo.values; + +fn void test(int x) +{ + Foo zonk = Foo.values[x]; +} + +/* #expect: test.ll + +%"Foo[]" = type { i32*, i64 } + +@test.z = local_unnamed_addr global i32 3, align 4 +@test.w = local_unnamed_addr global i32 123, align 4 +@test.zfok = local_unnamed_addr global i32 3, align 4 +@.taddr = private global [2 x i32] [i32 3, i32 123], align 4 +@test.zw = local_unnamed_addr global %"Foo[]" { i32* getelementptr inbounds ([2 x i32], [2 x i32]* @.taddr, i32 0, i32 0), i64 2 }, align 8 + +define void @test.test(i32 %0) #0 { +entry: + %zonk = alloca i32, align 4 + %literal = alloca [2 x i32], align 4 + %1 = getelementptr inbounds [2 x i32], [2 x i32]* %literal, i64 0, i64 0 + store i32 3, i32* %1, align 4 + %2 = getelementptr inbounds [2 x i32], [2 x i32]* %literal, i64 0, i64 1 + store i32 123, i32* %2, align 4 + %sisiext = sext i32 %0 to i64 + %3 = getelementptr inbounds [2 x i32], [2 x i32]* %literal, i64 0, i64 %sisiext + %4 = load i32, i32* %3, align 4 + store i32 %4, i32* %zonk, align 4 + ret void +}