From bb7496a2fcc58238a4e3abcc431313385a15183f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Feb 2026 14:28:16 +0000 Subject: [PATCH] Add `intrinsics.count_trailing_ones` and `intrinsics.count_leading_ones` --- base/intrinsics/intrinsics.odin | 2 ++ src/check_builtin.cpp | 23 +++++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend_proc.cpp | 6 ++++++ src/llvm_backend_utility.cpp | 12 ++++++++++++ 5 files changed, 47 insertions(+) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 2428e37b9..f06dbdfbf 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -38,6 +38,8 @@ count_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_sim count_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- +count_trailing_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- +count_leading_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e2428576e..1a094c1f0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5204,6 +5204,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_count_zeros: case BuiltinProc_count_trailing_zeros: case BuiltinProc_count_leading_zeros: + case BuiltinProc_count_trailing_ones: + case BuiltinProc_count_leading_ones: case BuiltinProc_reverse_bits: { Operand x = {}; @@ -5301,6 +5303,27 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As v += 1; } break; + + case BuiltinProc_count_trailing_ones: + for (u64 i = 0; i < bit_size; i++) { + u8 b = cast(u8)(i & 7); + u8 j = cast(u8)(i >> 3); + if ((rop[j] & (1 << b)) == 0) { + break; + } + v += 1; + } + break; + case BuiltinProc_count_leading_ones: + for (u64 i = bit_size-1; i < bit_size; i--) { + u8 b = cast(u8)(i & 7); + u8 j = cast(u8)(i >> 3); + if ((rop[j] & (1 << b)) == 0) { + break; + } + v += 1; + } + break; } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 5b446cc1c..a13ffc3cd 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -74,6 +74,8 @@ enum BuiltinProcId { BuiltinProc_count_zeros, BuiltinProc_count_trailing_zeros, BuiltinProc_count_leading_zeros, + BuiltinProc_count_trailing_ones, + BuiltinProc_count_leading_ones, BuiltinProc_reverse_bits, BuiltinProc_byte_swap, @@ -453,6 +455,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("count_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_trailing_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_leading_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("count_trailing_ones"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("count_leading_ones"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("reverse_bits"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("byte_swap"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b596f15ef..e52e91f75 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2850,6 +2850,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_count_leading_zeros: return lb_emit_count_leading_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); + case BuiltinProc_count_trailing_ones: + return lb_emit_count_trailing_ones(p, lb_build_expr(p, ce->args[0]), tv.type); + case BuiltinProc_count_leading_ones: + return lb_emit_count_leading_ones(p, lb_build_expr(p, ce->args[0]), tv.type); + + case BuiltinProc_count_ones: return lb_emit_count_ones(p, lb_build_expr(p, ce->args[0]), tv.type); case BuiltinProc_count_zeros: diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 367e7be75..8a7bced59 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -648,6 +648,18 @@ gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type return res; } +gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type); + +gb_internal lbValue lb_emit_count_trailing_ones(lbProcedure *p, lbValue x, Type *type) { + lbValue z = lb_emit_unary_arith(p, Token_Xor, x, type); + return lb_emit_count_trailing_zeros(p, z, type); +} + +gb_internal lbValue lb_emit_count_leading_ones(lbProcedure *p, lbValue x, Type *type) { + lbValue z = lb_emit_unary_arith(p, Token_Xor, x, type); + return lb_emit_count_leading_zeros(p, z, type); +} + gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {