From 6b928c7a3dae786f2053fbed7b50b7e282bc4648 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 3 Feb 2023 00:25:29 +0100 Subject: [PATCH] Add saturated math and expect macros. --- lib/std/core/builtin.c3 | 11 ++++++ lib/std/math/math.c3 | 50 ++++++++++++++++++++++++++++ src/compiler/enums.h | 3 +- src/compiler/llvm_codegen.c | 2 ++ src/compiler/llvm_codegen_builtins.c | 15 +++++++++ src/compiler/llvm_codegen_internal.h | 2 ++ src/compiler/sema_builtins.c | 39 ++++++++++++++++++++++ src/compiler/symtab.c | 2 ++ src/version.h | 2 +- 9 files changed, 124 insertions(+), 2 deletions(-) diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 550ac05de..787ce5623 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -120,6 +120,17 @@ macro enum_by_name($Type, String enum_name) @builtin return SearchResult.MISSING!; } +macro bool @expect_true(bool value) @builtin => $$expect(value, true); +macro bool @expect_false(bool value) @builtin => $$expect(value, false); + +/** + * @require values.is_int(value) + * @checked $typeof(value) a = expected + **/ +macro @expect(value, expected) @builtin +{ + return $$expect(value, ($typeof(value))expected); +} /** * Locality for prefetch, levels 0 - 3, corresponding * to "extremely local" to "no locality" diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index 8a0e7a937..ea2724c8a 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -593,6 +593,56 @@ macro uint128 uint128[<*>].xor(uint128[<*>] x) => $$reduce_xor(x); macro uint128 uint128[<*>].max(uint128[<*>] x) => $$reduce_max(x); macro uint128 uint128[<*>].min(uint128[<*>] x) => $$reduce_min(x); +macro char char.sat_add(char x, char y) => $$sat_add(x, y); +macro char char.sat_sub(char x, char y) => $$sat_sub(x, y); +macro char char.sat_mul(char x, char y) => $$sat_mul(x, y); +macro char char.sat_shl(char x, char y) => $$sat_shl(x, y); + +macro ichar ichar.sat_add(ichar x, ichar y) => $$sat_add(x, y); +macro ichar ichar.sat_sub(ichar x, ichar y) => $$sat_sub(x, y); +macro ichar ichar.sat_mul(ichar x, ichar y) => $$sat_mul(x, y); +macro ichar ichar.sat_shl(ichar x, ichar y) => $$sat_shl(x, y); + +macro ushort ushort.sat_add(ushort x, ushort y) => $$sat_add(x, y); +macro ushort ushort.sat_sub(ushort x, ushort y) => $$sat_sub(x, y); +macro ushort ushort.sat_mul(ushort x, ushort y) => $$sat_mul(x, y); +macro ushort ushort.sat_shl(ushort x, ushort y) => $$sat_shl(x, y); + +macro short short.sat_add(short x, short y) => $$sat_add(x, y); +macro short short.sat_sub(short x, short y) => $$sat_sub(x, y); +macro short short.sat_mul(short x, short y) => $$sat_mul(x, y); +macro short short.sat_shl(short x, short y) => $$sat_shl(x, y); + +macro uint uint.sat_add(uint x, uint y) => $$sat_add(x, y); +macro uint uint.sat_sub(uint x, uint y) => $$sat_sub(x, y); +macro uint uint.sat_mul(uint x, uint y) => $$sat_mul(x, y); +macro uint uint.sat_shl(uint x, uint y) => $$sat_shl(x, y); + +macro int int.sat_add(int x, int y) => $$sat_add(x, y); +macro int int.sat_sub(int x, int y) => $$sat_sub(x, y); +macro int int.sat_mul(int x, int y) => $$sat_mul(x, y); +macro int int.sat_shl(int x, int y) => $$sat_shl(x, y); + +macro ulong ulong.sat_add(ulong x, ulong y) => $$sat_add(x, y); +macro ulong ulong.sat_sub(ulong x, ulong y) => $$sat_sub(x, y); +macro ulong ulong.sat_mul(ulong x, ulong y) => $$sat_mul(x, y); +macro ulong ulong.sat_shl(ulong x, ulong y) => $$sat_shl(x, y); + +macro long long.sat_add(long x, long y) => $$sat_add(x, y); +macro long long.sat_sub(long x, long y) => $$sat_sub(x, y); +macro long long.sat_mul(long x, long y) => $$sat_mul(x, y); +macro long long.sat_shl(long x, long y) => $$sat_shl(x, y); + +macro uint128 uint128.sat_add(uint128 x, uint128 y) => $$sat_add(x, y); +macro uint128 uint128.sat_sub(uint128 x, uint128 y) => $$sat_sub(x, y); +macro uint128 uint128.sat_mul(uint128 x, uint128 y) => $$sat_mul(x, y); +macro uint128 uint128.sat_shl(uint128 x, uint128 y) => $$sat_shl(x, y); + +macro int128 int128.sat_add(int128 x, int128 y) => $$sat_add(x, y); +macro int128 int128.sat_sub(int128 x, int128 y) => $$sat_sub(x, y); +macro int128 int128.sat_mul(int128 x, int128 y) => $$sat_mul(x, y); +macro int128 int128.sat_shl(int128 x, int128 y) => $$sat_shl(x, y); + /** * @checked x & 1 */ diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 805af7669..53fcaa78a 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -833,6 +833,8 @@ typedef enum BUILTIN_EXACT_SUB, BUILTIN_EXP, BUILTIN_EXP2, + BUILTIN_EXPECT, + BUILTIN_EXPECT_WITH_PROBABILITY, BUILTIN_FLOOR, BUILTIN_FMA, BUILTIN_FMULADD, @@ -895,7 +897,6 @@ typedef enum BUILTIN_VOLATILE_STORE, BUILTIN_WASM_MEMORY_SIZE, BUILTIN_WASM_MEMORY_GROW, - BUILTIN_NONE, NUMBER_OF_BUILTINS = BUILTIN_NONE, diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 9ba053b0b..c85c7cdd5 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -633,6 +633,8 @@ static void llvm_codegen_setup() intrinsic_id.cttz = lookup_intrinsic("llvm.cttz"); intrinsic_id.exp = lookup_intrinsic("llvm.exp"); intrinsic_id.exp2 = lookup_intrinsic("llvm.exp2"); + intrinsic_id.expect = lookup_intrinsic("llvm.expect"); + intrinsic_id.expect_with_probability = lookup_intrinsic("llvm.expect.with.probability"); intrinsic_id.fabs = lookup_intrinsic("llvm.fabs"); intrinsic_id.floor = lookup_intrinsic("llvm.floor"); intrinsic_id.fma = lookup_intrinsic("llvm.fma"); diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 18e1ac9be..72364425a 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -424,6 +424,7 @@ void llvm_emit_simple_builtin(GenContext *c, BEValue *be_value, Expr *expr, unsi llvm_value_set(be_value, result, expr->type); } + void llvm_emit_builtin_args_types3(GenContext *c, BEValue *be_value, Expr *expr, unsigned intrinsic, Type *type1, Type *type2, Type *type3) { Expr **args = expr->call_expr.arguments; @@ -710,6 +711,20 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case BUILTIN_CTLZ: llvm_emit_int_with_bool_builtin(c, intrinsic_id.ctlz, result_value, expr, false); return; + case BUILTIN_EXPECT: + llvm_emit_simple_builtin(c, result_value, expr, intrinsic_id.expect); + return; + case BUILTIN_EXPECT_WITH_PROBABILITY: + if (active_target.optimization_level == OPTIMIZATION_NONE) + { + Expr **args = expr->call_expr.arguments; + llvm_emit_expr(c, result_value, args[0]); + BEValue dummy; + llvm_emit_expr(c, &dummy, args[1]); + return; + } + llvm_emit_simple_builtin(c, result_value, expr, intrinsic_id.expect_with_probability); + return; case BUILTIN_MAX: llvm_emit_3_variant_builtin(c, result_value, expr, intrinsic_id.smax, intrinsic_id.umax, intrinsic_id.maxnum); return; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index e4e1bdf77..2c8756e77 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -131,6 +131,8 @@ typedef struct unsigned cttz; unsigned exp; unsigned exp2; + unsigned expect; + unsigned expect_with_probability; unsigned fabs; unsigned floor; unsigned fma; diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 032d317d3..8a9646530 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -15,6 +15,7 @@ typedef enum BA_INTLIKE, BA_NUMLIKE, BA_BOOLINTVEC, + BA_BOOLINT, BA_INTVEC, BA_FLOATVEC, BA_VEC, @@ -118,6 +119,13 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar return false; } break; + case BA_BOOLINT: + if (!type_is_integer_or_bool_kind(type)) + { + SEMA_ERROR(args[i], "Expected a boolean or integer value."); + return false; + } + break; case BA_BOOLINTVEC: if (type->type_kind != TYPE_VECTOR || !type_flat_is_boolintlike(type->array.base)) @@ -464,6 +472,35 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC }, arg_count)) return false; rtype = args[0]->type; break; + case BUILTIN_EXPECT: + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINT, BA_BOOLINT }, arg_count)) return false; + if (!sema_check_builtin_args_match(args, arg_count)) return false; + rtype = args[0]->type; + break; + case BUILTIN_EXPECT_WITH_PROBABILITY: + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_BOOLINT, BA_BOOLINT }, 2)) return false; + if (!cast_implicit(context, args[2], type_double)) + { + SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type)); + return false; + } + if (!expr_is_const(args[2])) + { + SEMA_ERROR(args[2], "This value must be a constant."); + return false; + } + else + { + Real r = args[2]->const_expr.fxx.f; + if (r < 0 || r > 1) + { + SEMA_ERROR(args[2], "The probability must be between 0 and 1."); + return false; + } + } + if (!sema_check_builtin_args_match(args, 2)) return false; + rtype = args[0]->type; + break; case BUILTIN_CEIL: case BUILTIN_COPYSIGN: case BUILTIN_COS: @@ -699,6 +736,7 @@ static inline int builtin_expected_args(BuiltinFunction func) case BUILTIN_EXACT_MOD: case BUILTIN_EXACT_MUL: case BUILTIN_EXACT_SUB: + case BUILTIN_EXPECT: case BUILTIN_MAX: case BUILTIN_MIN: case BUILTIN_POW: @@ -717,6 +755,7 @@ static inline int builtin_expected_args(BuiltinFunction func) case BUILTIN_VECCOMPEQ: case BUILTIN_WASM_MEMORY_GROW: return 2; + case BUILTIN_EXPECT_WITH_PROBABILITY: case BUILTIN_FMA: case BUILTIN_FSHL: case BUILTIN_FSHR: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index a0b20bae5..7c894ae43 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -200,6 +200,8 @@ void symtab_init(uint32_t capacity) builtin_list[BUILTIN_EXACT_SUB] = KW_DEF("sub"); builtin_list[BUILTIN_EXP] = KW_DEF("exp"); builtin_list[BUILTIN_EXP2] = KW_DEF("exp2"); + builtin_list[BUILTIN_EXPECT] = KW_DEF("expect"); + builtin_list[BUILTIN_EXPECT_WITH_PROBABILITY] = KW_DEF("expect_with_probability"); builtin_list[BUILTIN_FLOOR] = KW_DEF("floor"); builtin_list[BUILTIN_FMA] = KW_DEF("fma"); builtin_list[BUILTIN_FMULADD] = KW_DEF("fmuladd"); diff --git a/src/version.h b/src/version.h index c4ceee62f..7bdb41d21 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.40" \ No newline at end of file +#define COMPILER_VERSION "0.4.41" \ No newline at end of file