diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index d677becf1..d02948744 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -30,6 +30,14 @@ typedef EmptySlot = void*; macro @is_empty_macro_slot(#arg) @const @builtin => @typeis(#arg, EmptySlot); macro @is_valid_macro_slot(#arg) @const @builtin => !@typeis(#arg, EmptySlot); +<* + Returns a random value at compile time. + + @ensure return >= 0.0 && return < 1.0 + @return "A compile time random" +*> +macro @rnd() @const @builtin => $$rnd(); + /* Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds. */ diff --git a/releasenotes.md b/releasenotes.md index f8356931b..98f01711d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -8,6 +8,7 @@ - Deprecate uXX and iXX bit suffixes. - Add experimental LL / ULL suffixes for int128 and uint128 literals. - Allow the right hand side of `|||` and `&&&` be runtime values. +- Added `@rnd()` compile time random function (using the `$$rnd()` builtin). #2078 ### Fixes - Assert triggered when casting from `int[2]` to `uint[2]` #2115 diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 0bb5f5089..7bba26579 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -487,6 +487,7 @@ typedef enum BUILTIN_REVERSE, BUILTIN_RETURNADDRESS, BUILTIN_RINT, + BUILTIN_RND, BUILTIN_ROUND, BUILTIN_ROUNDEVEN, BUILTIN_SAT_ADD, diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 6e7831705..0f70ceea1 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -1009,6 +1009,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case BUILTIN_STR_FIND: case BUILTIN_WIDESTRING_16: case BUILTIN_WIDESTRING_32: + case BUILTIN_RND: UNREACHABLE case BUILTIN_NONE: UNREACHABLE diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 9d03c469f..a81c328f1 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -289,6 +289,20 @@ static bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr) return true; } +uint64_t rand_u64() +{ + return ((uint64_t)rand() << 48) ^ ((uint64_t)rand() << 32) ^ ((uint64_t)rand() << 16) ^ rand(); +} + +bool sema_expr_analyse_rnd(SemaContext *context UNUSED, Expr *expr) +{ + uint64_t r = rand_u64(); + uint64_t mantissa = r >> 11; + double val = (double)mantissa / (double)(1ULL << 53); // Not secure random but... + expr_rewrite_const_float(expr, type_double, val); + return true; +} + bool sema_expr_analyse_str_hash(SemaContext *context, Expr *expr) { Expr *inner = expr->call_expr.arguments[0]; @@ -516,6 +530,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) switch (func) { + case BUILTIN_RND: + return sema_expr_analyse_rnd(context, expr); case BUILTIN_STR_HASH: return sema_expr_analyse_str_hash(context, expr); case BUILTIN_STR_UPPER: @@ -1124,6 +1140,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_TRAP: case BUILTIN_BREAKPOINT: case BUILTIN_UNREACHABLE: + case BUILTIN_RND: UNREACHABLE } expr->type = type_add_optional(rtype, optional); @@ -1147,6 +1164,7 @@ static inline int builtin_expected_args(BuiltinFunction func) case BUILTIN_TRAP: case BUILTIN_BREAKPOINT: case BUILTIN_UNREACHABLE: + case BUILTIN_RND: return 0; case BUILTIN_ABS: case BUILTIN_BITREVERSE: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index ee6d5b6e6..1159782c2 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -261,6 +261,7 @@ void symtab_init(uint32_t capacity) builtin_list[BUILTIN_REVERSE] = KW_DEF("reverse"); builtin_list[BUILTIN_RETURNADDRESS] = KW_DEF("returnaddress"); builtin_list[BUILTIN_RINT] = KW_DEF("rint"); + builtin_list[BUILTIN_RND] = KW_DEF("rnd"); builtin_list[BUILTIN_ROUND] = KW_DEF("round"); builtin_list[BUILTIN_ROUNDEVEN] = KW_DEF("roundeven"); builtin_list[BUILTIN_SAT_ADD] = KW_DEF("sat_add"); diff --git a/src/main.c b/src/main.c index e469b0d0c..64b6e93e5 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,7 @@ const char *compiler_exe_name; int main_real(int argc, const char *argv[]) { + srand((unsigned int)time(NULL)); compiler_exe_name = argv[0]; bench_begin();