From ae51214c47178a73436237a0fc3aa01d27fbb589 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 16 Aug 2022 21:18:14 +0200 Subject: [PATCH] Added clz, ctz, popcount, bswap, bitreverse. --- lib/std/bits.c3 | 41 ++++++++++++++++++++++++++++++++ lib/std/core/types.c3 | 13 ++++++++++ src/compiler/compiler_internal.h | 1 + src/compiler/enums.h | 5 ++++ src/compiler/llvm_codegen_expr.c | 15 ++++++++++++ src/compiler/sema_expr.c | 26 +++++++++++++++++++- src/compiler/symtab.c | 5 ++++ src/compiler/types.c | 8 +++++++ src/version.h | 2 +- 9 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 lib/std/bits.c3 diff --git a/lib/std/bits.c3 b/lib/std/bits.c3 new file mode 100644 index 000000000..e2f12c6ea --- /dev/null +++ b/lib/std/bits.c3 @@ -0,0 +1,41 @@ +module std::bits; + +/** + * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` + **/ +macro popcount(i) +{ + return $$popcount(i); +} + +/** + * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` + **/ +macro reverse(i) +{ + return $$bitreverse(i); +} + +/** + * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` + **/ +macro bswap(i) @builtin +{ + return $$bswap(i); +} + +/** + * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` + **/ +macro ctz(i) @builtin +{ + return $$ctz(i); +} + +/** + * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` + **/ +macro clz(i) @builtin +{ + return $$clz(i); +} diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 07682747e..b7e05ca46 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -121,6 +121,19 @@ macro bool is_subarray_convertable($Type) $endswitch; } +macro bool is_intlike($Type) +{ + $switch ($Type.kind): + $case SIGNED_INT: + $case UNSIGNED_INT: + return true; + $case VECTOR: + return is_intlike($Type.inner); + $default: + return false; + $endswitch; +} + macro bool is_equatable_value(value) { $if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)): diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 4bd18253e..5e5e876b0 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2101,6 +2101,7 @@ Type *type_from_token(TokenType type); bool type_is_user_defined(Type *type); bool type_is_structurally_equivalent(Type *type1, Type *type); bool type_flat_is_floatlike(Type *type); +bool type_flat_is_intlike(Type *type); bool type_may_have_sub_elements(Type *type); const char *type_to_error_string(Type *type); const char *type_quoted_error_string(Type *type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 26f9ebfb4..d3bb0f969 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -758,6 +758,11 @@ typedef enum BUILTIN_EXP, BUILTIN_FABS, BUILTIN_FMA, + BUILTIN_CTPOP, + BUILTIN_CTLZ, + BUILTIN_CTTZ, + BUILTIN_BITREVERSE, + BUILTIN_BSWAP, BUILTIN_VOLATILE_LOAD, BUILTIN_VOLATILE_STORE, BUILTIN_MEMCOPY, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 4c21d86bd..bfb5affb0 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -4099,6 +4099,11 @@ static void llvm_emit_intrinsic_expr(GenContext *c, unsigned intrinsic, BEValue llvm_value_rvalue(c, be_value); arg_results[i] = be_value->value; } + if (intrinsic == intrinsic_id.ctlz || intrinsic == intrinsic_id.cttz) + { + arg_results[1] = llvm_get_zero_raw(c->bool_type); + arguments++; + } LLVMTypeRef call_type[3]; int call_args = 0; if (expr->type != type_void) @@ -4321,6 +4326,16 @@ unsigned llvm_get_intrinsic(BuiltinFunction func) return intrinsic_id.fabs; case BUILTIN_FMA: return intrinsic_id.fma; + case BUILTIN_BITREVERSE: + return intrinsic_id.bitreverse; + case BUILTIN_BSWAP: + return intrinsic_id.bswap; + case BUILTIN_CTLZ: + return intrinsic_id.ctlz; + case BUILTIN_CTTZ: + return intrinsic_id.cttz; + case BUILTIN_CTPOP: + return intrinsic_id.ctpop; case BUILTIN_LOG2: return intrinsic_id.log2; case BUILTIN_POW: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 1f25f211b..c43051099 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2486,6 +2486,11 @@ static inline unsigned builtin_expected_args(BuiltinFunction func) case BUILTIN_LOG10: case BUILTIN_FABS: case BUILTIN_VOLATILE_LOAD: + case BUILTIN_CTPOP: + case BUILTIN_CTTZ: + case BUILTIN_CTLZ: + case BUILTIN_BSWAP: + case BUILTIN_BITREVERSE: return 1; case BUILTIN_POW: case BUILTIN_MAX: @@ -2511,6 +2516,7 @@ typedef enum BA_BOOL, BA_CHAR, BA_FLOATLIKE, + BA_INTLIKE, } BuiltinArg; static bool sema_check_builtin_args_match(Expr **args, size_t arg_len) @@ -2577,7 +2583,14 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar case BA_FLOATLIKE: if (!type_flat_is_floatlike(type)) { - SEMA_ERROR(args[i], "Expected a floating point or floating point array."); + SEMA_ERROR(args[i], "Expected a floating point or floating point vector."); + return false; + } + break; + case BA_INTLIKE: + if (!type_flat_is_intlike(type)) + { + SEMA_ERROR(args[i], "Expected an int or int vector."); return false; } break; @@ -2676,6 +2689,16 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex case BUILTIN_STACKTRACE: rtype = type_voidptr; break; + case BUILTIN_CTPOP: + case BUILTIN_CTTZ: + case BUILTIN_CTLZ: + case BUILTIN_BITREVERSE: + case BUILTIN_BSWAP: + if (!sema_check_builtin_args(args, + (BuiltinArg[]) { BA_INTLIKE }, + arg_count)) return false; + rtype = args[0]->type; + break; case BUILTIN_CEIL: case BUILTIN_TRUNC: case BUILTIN_SQRT: @@ -2691,6 +2714,7 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex arg_count)) return false; rtype = args[0]->type; break; + case BUILTIN_POW: case BUILTIN_MAX: case BUILTIN_MIN: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 5212329d6..80b1ffd79 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -180,6 +180,11 @@ void symtab_init(uint32_t capacity) builtin_list[BUILTIN_SYSCLOCK] = KW_DEF("sysclock"); builtin_list[BUILTIN_UNREACHABLE] = KW_DEF("unreachable"); builtin_list[BUILTIN_STACKTRACE] = KW_DEF("stacktrace"); + builtin_list[BUILTIN_BSWAP] = KW_DEF("bswap"); + builtin_list[BUILTIN_BITREVERSE] = KW_DEF("bitreverse"); + builtin_list[BUILTIN_CTLZ] = KW_DEF("clz"); + builtin_list[BUILTIN_CTTZ] = KW_DEF("ctz"); + builtin_list[BUILTIN_CTPOP] = KW_DEF("popcount"); builtin_list[BUILTIN_CEIL] = KW_DEF("ceil"); builtin_list[BUILTIN_TRUNC] = KW_DEF("trunc"); builtin_list[BUILTIN_SIN] = KW_DEF("sin"); diff --git a/src/compiler/types.c b/src/compiler/types.c index 581ffaa2b..7eec504cf 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -328,6 +328,14 @@ bool type_flat_is_floatlike(Type *type) return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST; } +bool type_flat_is_intlike(Type *type) +{ + type = type_flatten(type); + if (type->type_kind == TYPE_VECTOR) type = type->array.base; + TypeKind kind = type->type_kind; + return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST; +} + bool type_is_int128(Type *type) { diff --git a/src/version.h b/src/version.h index c9a6edf93..8d009837e 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.18" \ No newline at end of file +#define COMPILER_VERSION "0.3.19" \ No newline at end of file