[RFC] Introduce new clang builtin __builtin_allow_runtime_check

With [IR] Introduce `llvm.allow.{runtime,ubsan}.check()` by vitalybuka · Pull Request #84850 · llvm/llvm-project · GitHub LLVM supports

declare i1 @llvm.allow.runtime.check(metadata %kind)

I propose to introduce builtin __builtin_allow_runtime_check for C/C++ programs

Summary

__builtin_allow_runtime_check return true if the check at the current program location should be executed.

Syntax:

    bool __builtin_allow_runtime_check(const char* kind)

Example of use:

  if (__builtin_allow_runtime_check("mycheck") && !ExpensiveCheck()) {
     abort();
  }

Description

__builtin_allow_runtime_check is lowered to llvm.allow.runtime.check. See LLVM Language Reference Manual — LLVM 19.0.0git documentation.

The __builtin_allow_runtime_check() is expected to be used with control flow
conditions such as in if to guard expensive runtime checks. The specific rules for selecting permitted checks can differ and are controlled by the compiler options.

Flags to control checks:

  • -mllvm -lower-allow-check-percentile-cutoff-hot=N where N is PGO hotness cutoff in range [0, 999999] to disallow checks in hot code.
  • -mllvm -lower-allow-check-random-rate=P where P is number in [0.0, 1.0] representation probability of keeping a check.
  • If both flags are specified, -lower-allow-check-random-rate takes precedence.
  • If none is specified, __builtin_allow_runtime_check is lowered as true, allowing all checks.

Parameter kind is a string literal representing a user selected kind for guarded check.
It’s unused now. It will enable kind specific lowering in future. E.g. a
higher hotness cutoff can be used for more expensive kind of check.

Query for this feature with __has_builtin(__builtin_allow_runtime_check).

Clang flags
In future we will have to decide on clang flags to control lowering. My interest is in PGO guided lowering. However there is expressed interest in more direct control of checks. Or partitioning of checks to make sure that for N builds of the same program, the check is enabled exactly in one of them.

Note: UBSAN supports equivalent intrinsic LLVM Language Reference Manual — LLVM 19.0.0git documentation, and we are planning to opt-out HWAsan, Asan, Tsan instrumentation in the similar way. So we need to develop consistent set of clang flags.

I propose to control lowering with semi-hidden -mllvm flags for now, and introduce clang flags with a time, taking into account first adopters feedback.

Suggestion for flags is welcomed!

1 Like

Thank you for posting the RFC! I don’t have any objections to adding this builtin to Clang.

Could you expand on how your RFC interacts with the sanitizers? In the example you give

  if (__builtin_allow_runtime_check("mycheck") && !ExpensiveCheck()) {
     abort();
  }

ExpensiveCheck looks like an explicit piece of code in the original source code. For the Sanitizers the checks are usually implicit (i.e. not written in the original source code). In that case how is it intended that the builtin interact with implicit checks added by the compiler instrumentation such as the Sanitizers?

This RFC does not affect sanitizers.

[RFC] Add llvm.allow.runtime.check() intrinsic for both sanitizers and code.

Right now UBSAN implicitly inserts llvm.allow.ubsan.check() if -mllvm -ubsan-guard-checks is specified llvm-project/clang/lib/CodeGen/CGExpr.cpp at fca2a493251597967d5d758ea0748c66dd29371a · llvm/llvm-project · GitHub

Clang will need frontend flags to control lowering of both llvm.allow.runtime.check and llvm.allow.ubsan.check. When we introduce those flags will be able to abandon -mllvm.