From cc47fc81c497ccb1b48a928594af5d80cca9100e Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Sun, 5 Jul 2026 17:49:32 -0400 Subject: [PATCH] Assume for the GCC bounds checks --- include/prism/compiler/assume.h | 25 +++++++++++++++++++++++++ prism.gemspec | 1 + templates/src/diagnostic.c.erb | 3 +++ 3 files changed, 29 insertions(+) create mode 100644 include/prism/compiler/assume.h diff --git a/include/prism/compiler/assume.h b/include/prism/compiler/assume.h new file mode 100644 index 0000000000..500e93e73c --- /dev/null +++ b/include/prism/compiler/assume.h @@ -0,0 +1,25 @@ +/** + * @file compiler/assume.h + */ +#ifndef PRISM_COMPILER_ASSUME_H +#define PRISM_COMPILER_ASSUME_H + +/** + * Tell the compiler that the given expression can be assumed to be true. Unlike + * assert, this emits no runtime check — it only feeds the optimizer's value + * range analysis so it can prune impossible paths. Use it to communicate an + * invariant the caller guarantees but that the compiler cannot otherwise prove. + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L /* C23 or later */ + #define PRISM_ASSUME(expr_) [[assume(expr_)]] +#elif defined(__clang__) + #define PRISM_ASSUME(expr_) __builtin_assume(expr_) +#elif defined(_MSC_VER) + #define PRISM_ASSUME(expr_) __assume(expr_) +#elif defined(__GNUC__) + #define PRISM_ASSUME(expr_) ((expr_) ? (void) 0 : __builtin_unreachable()) +#else + #define PRISM_ASSUME(expr_) ((void) 0) +#endif + +#endif diff --git a/prism.gemspec b/prism.gemspec index aac056b3f8..c18d68f4d8 100644 --- a/prism.gemspec +++ b/prism.gemspec @@ -48,6 +48,7 @@ Gem::Specification.new do |spec| "include/prism.h", "include/prism/compiler/accel.h", "include/prism/compiler/align.h", + "include/prism/compiler/assume.h", "include/prism/compiler/exported.h", "include/prism/compiler/fallthrough.h", "include/prism/compiler/filesystem.h", diff --git a/templates/src/diagnostic.c.erb b/templates/src/diagnostic.c.erb index 0dea732869..0683978084 100644 --- a/templates/src/diagnostic.c.erb +++ b/templates/src/diagnostic.c.erb @@ -1,5 +1,6 @@ #include "prism/internal/diagnostic.h" +#include "prism/compiler/assume.h" #include "prism/compiler/inline.h" #include "prism/internal/allocator.h" @@ -446,6 +447,7 @@ pm_diagnostic_id_name(pm_diagnostic_id_t diag_id) { static PRISM_INLINE const char * pm_diagnostic_id_message(pm_diagnostic_id_t diag_id) { assert(diag_id < PM_DIAGNOSTIC_ID_MAX); + PRISM_ASSUME(diag_id < PM_DIAGNOSTIC_ID_MAX); const char *message = diagnostic_messages[diag_id].message; assert(message); @@ -456,6 +458,7 @@ pm_diagnostic_id_message(pm_diagnostic_id_t diag_id) { static PRISM_INLINE uint8_t pm_diagnostic_id_level(pm_diagnostic_id_t diag_id) { assert(diag_id < PM_DIAGNOSTIC_ID_MAX); + PRISM_ASSUME(diag_id < PM_DIAGNOSTIC_ID_MAX); return (uint8_t) diagnostic_messages[diag_id].level; }