From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2049) id C1A28385E00D; Mon, 14 Mar 2022 10:34:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C1A28385E00D Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Matthew Malcomson To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/morello)] Take CHERI headers from LLVM X-Act-Checkin: gcc X-Git-Author: Matthew Malcomson X-Git-Refname: refs/vendors/ARM/heads/morello X-Git-Oldrev: 0f4d52827c4424327302e27161840d26c8118b4a X-Git-Newrev: 5efe45f95cf351e9c695eaa8e38b7310b23a82fb Message-Id: <20220314103436.C1A28385E00D@sourceware.org> Date: Mon, 14 Mar 2022 10:34:36 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Mar 2022 10:34:36 -0000 https://gcc.gnu.org/g:5efe45f95cf351e9c695eaa8e38b7310b23a82fb commit 5efe45f95cf351e9c695eaa8e38b7310b23a82fb Author: Matthew Malcomson Date: Tue Mar 1 12:14:21 2022 +0000 Take CHERI headers from LLVM These modified for use in GCC. The original LLVM headers can be seen at the links below. https://git.morello_project.org/morello/llvm_project/_/blob/morello/dev/clang/lib/Headers/cheri.h https://git.morello_project.org/morello/llvm_project/_/blob/morello/dev/clang/lib/Headers/cheriintrin.h. At the time they are added, these are mostly commented out in the preprocessor since they largely use functionality that is not yet implemented in GCC. Diff: --- gcc/ginclude/cheri.h | 335 +++++++++++++++++++++++++++++++++++++++++++++ gcc/ginclude/cheriintrin.h | 145 ++++++++++++++++++++ 2 files changed, 480 insertions(+) diff --git a/gcc/ginclude/cheri.h b/gcc/ginclude/cheri.h new file mode 100644 index 00000000000..a6edbc89936 --- /dev/null +++ b/gcc/ginclude/cheri.h @@ -0,0 +1,335 @@ +/*===---- cheri.h - Header for CHERI capabilities -----------------------===*\ + * + * Copyright (c) 2014 David Chisnall + * Copyright (c) 2018 Alex Richardson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * +\*===----------------------------------------------------------------------===*/ + +/* Mirorred in the GCC source repo with modifications to work within the GNU + environment. Currently mostly unused since CHERI for GCC is still a WIP. */ +#ifndef _GCC_CHERI_H +#define _GCC_CHERI_H + +#ifdef __aarch64__ +typedef unsigned int cheri_perms_t; +#else +typedef unsigned short cheri_perms_t; +#endif +typedef unsigned short cheri_flags_t; +typedef unsigned __INT32_TYPE__ cheri_type_t; +#ifdef __cplusplus +#define __cheri_bool bool +#else +#define __cheri_bool _Bool +#endif + +#if __GCC_ARM_CAPABILITY_ANY +#define __IF_CAPS(x, y) x +typedef __intcap_t intcap_t; +typedef __uintcap_t uintcap_t; +#ifdef WANT_CHERI_QUALIFIER_MACROS +#define capability __capability +#define output __cheri_output +#define input __cheri_input +#endif +#else +#define __IF_CAPS(x, y) y +typedef __INTPTR_TYPE__ intcap_t; +typedef __UINTPTR_TYPE__ uintcap_t; +#define __capability +#ifdef WANT_CHERI_QUALIFIER_MACROS +#define capability +#define output +#define input +#endif +#endif + +/* MORELLO TODO Currently disabled until GCC has implemented CHERI builtins. */ +#if 0 +#define __CHERI_GET(__name, __type, __get, __default) \ + static inline __type \ + cheri_##__name##__get(void * __capability __cap) \ + { \ + return __IF_CAPS(__builtin_cheri_##__name##__get(__cap), __default); \ + } + +#define __CHERI_SET(__name, __type, __set) \ + static inline void *__capability cheri_##__name##__set( \ + void *__capability __cap, __type __val) { \ + return __IF_CAPS(__builtin_cheri_##__name##__set(__cap, __val), \ + (void *)__cap); \ + } + +#define __CHERI_ACCESSOR(__name, __type, __set, __get, __default) \ + __CHERI_GET(__name, __type, __get, __default) \ + __CHERI_SET(__name, __type, __set) \ + +__CHERI_GET(length, __SIZE_TYPE__, _get, __SIZE_MAX__) +__CHERI_GET(base, __SIZE_TYPE__, _get, __SIZE_MAX__) +__CHERI_ACCESSOR(offset, __SIZE_TYPE__, _set, _get, __SIZE_MAX__) +__CHERI_GET(type, cheri_type_t, _get, 0) +__CHERI_ACCESSOR(perms, cheri_perms_t, _and, _get, 0) +__CHERI_ACCESSOR(flags, cheri_flags_t, _set, _get, 0) +__CHERI_GET(tag, __cheri_bool, _get, 0) +__CHERI_GET(sealed, __cheri_bool, _get, 0) + +static inline +void * __capability cheri_offset_increment(void *__capability __cap, + __PTRDIFF_TYPE__ __offset) { + return __IF_CAPS(__builtin_cheri_offset_increment(__cap, __offset), + ((char*)__cap) + __offset); +} + +static inline +void * __capability cheri_tag_clear(void * __capability __cap) { + return __IF_CAPS(__builtin_cheri_tag_clear(__cap), (void*)__cap); +} + +static inline +void * __capability cheri_seal(void * __capability __cap, + const void * __capability __type) { + return __IF_CAPS(__builtin_cheri_seal(__cap, __type), (void*)__cap); +} + +static inline +void * __capability cheri_unseal(void * __capability __cap, + const void * __capability __type) { + return __IF_CAPS(__builtin_cheri_unseal(__cap, __type), (void*)__cap); +} + +static inline +void * __capability cheri_bounds_set(void *__capability __cap, + __SIZE_TYPE__ __bounds) { + return __IF_CAPS(__builtin_cheri_bounds_set(__cap, __bounds), (void*)__cap); +} + +static inline +__SIZE_TYPE__ cheri_round_representable_length(__SIZE_TYPE__ __length) { + return __IF_CAPS(__builtin_cheri_round_representable_length(__length), __length); +} + +static inline +__SIZE_TYPE__ cheri_round_representable_mask(__SIZE_TYPE__ __mask) { + return __IF_CAPS(__builtin_cheri_representable_alignment_mask(__mask), __mask); +} + +static inline +__SIZE_TYPE__ cheri_copy_from_high(void *__capability __cap) { + return __IF_CAPS(__builtin_cheri_copy_from_high(__cap), __SIZE_MAX__); +} + +static inline +void * __capability +cheri_copy_to_high(const void *__capability __cap, __SIZE_TYPE__ __high) { + return __IF_CAPS(__builtin_cheri_copy_to_high(__cap, __high), (void*)__cap); +} + +static inline __SIZE_TYPE__ cheri_equal_exact(const void * __capability __cap_a, + const void * __capability __cap_b) { + return __IF_CAPS(__builtin_cheri_equal_exact(__cap_a, __cap_b), 0); +} + +static inline __SIZE_TYPE__ cheri_subset_test(const void * __capability __cap_a, + const void * __capability __cap_b) { + return __IF_CAPS(__builtin_cheri_subset_test(__cap_a, __cap_b), 0); +} + +#ifndef __CHERI_PURE_CAPABILITY__ +static inline +void * __capability +cheri_cap_from_pointer(const void * __capability __cap, void *__ptr) { + return __IF_CAPS(__builtin_cheri_cap_from_pointer(__cap, __ptr), + (void *)__ptr); +} + +static inline +void * cheri_cap_to_pointer(const void * __capability __cap, + void * __capability __offset) { + return __IF_CAPS(__builtin_cheri_cap_to_pointer(__cap, __offset), + (void *)__offset); +} +#endif + +static inline +void cheri_perms_check(const void * __capability __cap, cheri_perms_t __perms) { + __IF_CAPS(__builtin_cheri_perms_check(__cap, __perms), ); +} + +static inline +void cheri_type_check(const void * __capability __cap, + const void * __capability __type) { + __IF_CAPS(__builtin_cheri_type_check(__cap, __type), ); +} + +static inline +void * __capability cheri_global_data_get(void) { + return __IF_CAPS(__builtin_cheri_global_data_get(), 0); +} + +static inline +void * __capability cheri_program_counter_get(void) { + return __IF_CAPS(__builtin_cheri_program_counter_get(), 0); +} + +/* TODO: Should these be builtins to get better diagnostics? */ + +static inline __attribute__((always_inline)) __attribute__((warn_unused_result)) +__SIZE_TYPE__ +__cheri_low_bits_get(__UINTPTR_TYPE__ ptr, __SIZE_TYPE__ mask) { + /* + * Note: we continue to use bitwise and on the uintcap value and silence the + * warning instead of using __builtin_cheri_offset_get() in case we decide + * to use a virtual-address instead offset interpretation of capabilities in + * the future. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcheri-bitwise-operations" + /* + * We mustn't return a LHS-derived capability here so we need to explicitly + * cast the result to a non-capability integer + */ + return (__SIZE_TYPE__)(ptr & mask); +#pragma clang diagnostic pop +} + +static inline __attribute__((always_inline)) __attribute__((warn_unused_result)) +__UINTPTR_TYPE__ +__cheri_low_bits_or(__UINTPTR_TYPE__ ptr, __SIZE_TYPE__ bits) { + /* + * We want to return a LHS-derived capability here so using the default + * uintcap_t semantics is fine. + */ + return ptr | bits; +} + +static inline __attribute__((always_inline)) __attribute__((warn_unused_result)) +__UINTPTR_TYPE__ +__cheri_low_bits_clear(__UINTPTR_TYPE__ ptr, __SIZE_TYPE__ bits_mask) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcheri-bitwise-operations" + /* + * We want to return a LHS-derived capability here so using the default + * uintcap_t semantics is fine. + */ + return ptr & (~bits_mask); +#pragma clang diagnostic pop +} + +#ifndef __cheri_usable_low_bits_mask +#define __cheri_usable_low_bits_mask 31 +#endif +#define __runtime_assert_sensible_low_bits(bits, mask) \ + __extension__({ \ + assert(((bits & mask) == bits) && "Bits outside mask used!"); \ + bits; \ + }) +#define __static_assert_sensible_low_bits(bits) \ + __extension__({ \ + _Static_assert(bits < (__cheri_usable_low_bits_mask + 1), \ + "Using too many low pointer bits"); \ + _Static_assert((bits & (bits + 1)) == 0, "Mask must be all ones"); \ + bits; \ + }) + +/* + * Get the low bits defined in @p mask from the capability/pointer @p ptr. + * @p mask must be a compile-time constant less than 31. + * TODO: should we allow non-constant masks? + * + * @param ptr the uintptr_t that may have low bits sets + * @param mask the mask for the low pointer bits to retrieve + * @return a size_t containing the the low bits from @p ptr + * + * Rationale: this function is needed because extracting the low bits using a + * bitwise-and operation returns a LHS-derived capability with the offset + * field set to LHS.offset & mask. This is almost certainly not what the user + * wanted since it will always compare not equal to any integer constant. + * For example lots of mutex code uses something like `if ((x & 1) == 1)` to + * detect if the lock is currently contented. This comparison always returns + * false under CHERI the LHS of the == is a valid capability with offset 3 and + * the RHS is an untagged intcap_t with offset 3. + * See https://github.com/CTSRD-CHERI/clang/issues/189 + */ +#define cheri_low_bits_get(ptr, mask) \ + __cheri_low_bits_get(ptr, __static_assert_sensible_low_bits(mask)) + +/* + * Bitwise-OR of low bits in a uintptr_t + * + * @param ptr the uintptr_t that may have low bits sets + * @param bits the value to bitwise-or with @p ptr. + * @return a uintptr_t that has the low bits @p bits + * + * @note this function is not strictly required since a plain bitwise or will + * generally give the behaviour that is expected from other platforms. + * However, we can't really make the warning "-Wcheri-bitwise-operations" + * trigger based on of the right hand side expression since it may not be a + * compile-time constant. + */ +#define cheri_low_bits_or(ptr, bits) \ + __cheri_low_bits_or(ptr, __runtime_assert_sensible_low_bits( \ + bits, __cheri_usable_low_bits_mask)) + +/* + * Set low bits in a uintptr_t + * + * @param ptr the uintptr_t that may have low bits sets + * @param mask the mask for the low pointer bits to be cleared before setting + * them to @p bits. + * @param bits the value to bitwise-or with @p ptr. + * @return a uintptr_t that has the low bits defined in @p mask set to @p bits + * + * @note this function is not strictly required since a plain bitwise or will + * generally give the behaviour that is expected from other platforms. + * However, we can't really make the warning "-Wcheri-bitwise-operations" + * trigger based on of the right hand side expression since it may not be a + * compile-time constant. + */ +#define cheri_low_bits_set(ptr, mask, bits) \ + __cheri_low_bits_or(cheri_low_bits_clear(ptr, mask), \ + __runtime_assert_sensible_low_bits(bits, mask)) + +/* + * Clear the bits in @p mask from the capability/pointer @p ptr. Mask must be + * a compile-time constant less than 31 + * + * TODO: should we allow non-constant masks? + * + * @param ptr the uintptr_t that may have low bits sets + * @param mask this is the mask for the low pointer bits, not the mask for + * the bits that should remain set. + * @return a uintptr_t that has the low bits defined in @p mask set to zeroes + * + * + */ +#define cheri_low_bits_clear(ptr, mask) \ + __cheri_low_bits_clear(ptr, __static_assert_sensible_low_bits(mask)) + +#undef __CHERI_ACCESSOR +#undef __CHERI_GET +#undef __CHERI_SET + +#endif /* if 0 (commenting out parts that GCC can't yet use). */ + +#undef __cheri_bool +#undef __IF_CAPS + +#endif /* _CHERI_H */ diff --git a/gcc/ginclude/cheriintrin.h b/gcc/ginclude/cheriintrin.h new file mode 100644 index 00000000000..9be560e5cda --- /dev/null +++ b/gcc/ginclude/cheriintrin.h @@ -0,0 +1,145 @@ +/*-------------- cheriintrin.h - CHERI intrinsics ----------------------- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2018-2020 Alex Richardson + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the + * DARPA SSITH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* LLVM header mirorred in the GCC source repo with modifications to work + within the GNU environment. Only for the GCC Morello vendor branch. */ +#ifndef __GCC_CHERI_INTRIN_H +#define __GCC_CHERI_INTRIN_H + +#ifndef __GCC_ARM_CAPABILITY_ANY +#error " should only be included when CHERI is supported" +#endif + +/* + * Provide shorter names for CHERI builtins that are portable across all + * CHERI-enabled architectures: + */ +#define cheri_address_get(x) __builtin_cheri_address_get(x) +#define cheri_address_set(x, y) __builtin_cheri_address_set((x), (y)) +#define cheri_base_get(x) __builtin_cheri_base_get(x) +#define cheri_length_get(x) __builtin_cheri_length_get(x) +#define cheri_offset_get(x) __builtin_cheri_offset_get(x) +#define cheri_offset_set(x, y) __builtin_cheri_offset_set((x), (y)) +#define cheri_tag_clear(x) __builtin_cheri_tag_clear(x) +#define cheri_tag_get(x) __builtin_cheri_tag_get(x) +#define cheri_is_valid(x) __builtin_cheri_tag_get(x) +#define cheri_is_invalid(x) (!__builtin_cheri_tag_get(x)) +#define cheri_is_equal_exact(x, y) __builtin_cheri_equal_exact((x), (y)) +#define cheri_is_subset(x, y) __builtin_cheri_subset_test((x), (y)) + +/* Bounds setting intrinsics: */ +#define cheri_representable_length(x) \ + __builtin_cheri_round_representable_length(x) +#define cheri_representable_alignment_mask(x) \ + __builtin_cheri_representable_alignment_mask(x) +#define cheri_bounds_set(x, y) __builtin_cheri_bounds_set((x), (y)) +#define cheri_bounds_set_exact(x, y) __builtin_cheri_bounds_set_exact((x), (y)) + +/* Object types, sealing and unsealing: */ +typedef long cheri_otype_t; +#if defined(__mips__) || defined(__riscv) +/* CHERI-MIPS and CHERI-RISC-V use negative numbers for hardware-interpreted + * otypes */ +#define CHERI_OTYPE_UNSEALED ((cheri_otype_t)-1) +#define CHERI_OTYPE_SENTRY ((cheri_otype_t)-2) +#elif defined(__aarch64__) +#define CHERI_OTYPE_UNSEALED ((cheri_otype_t)0) +#define CHERI_OTYPE_SENTRY ((cheri_otype_t)1) +#else +#error "Unknown architecture" +#endif +#define cheri_type_get(x) __builtin_cheri_type_get(x) +#define cheri_is_sealed(x) __builtin_cheri_sealed_get(x) +#define cheri_is_sentry(x) (__builtin_cheri_type_get(x) == CHERI_OTYPE_SENTRY) +#define cheri_is_unsealed(x) (!__builtin_cheri_sealed_get(x)) +/* TODO: builtins for indirect sentries */ +#define cheri_sentry_create(x) __builtin_cheri_seal_entry(x) +#define cheri_seal(x, y) __builtin_cheri_seal((x), (y)) +#define cheri_unseal(x, y) __builtin_cheri_unseal((x), (y)) + +/* Reconstruct capabilities from raw data: */ +#define cheri_cap_build(x, y) __builtin_cheri_cap_build((x), (y)) +#define cheri_seal_conditionally(x, y) \ + __builtin_cheri_conditional_seal((x), (y)) +#define cheri_type_copy(x, y) __builtin_cheri_cap_type_copy((x), (y)) + +/* Capability permissions: */ +typedef enum __attribute__((flag_enum, enum_extensibility(open))) { + CHERI_PERM_GLOBAL = __CHERI_CAP_PERMISSION_GLOBAL__, + CHERI_PERM_EXECUTE = __CHERI_CAP_PERMISSION_PERMIT_EXECUTE__, + CHERI_PERM_LOAD = __CHERI_CAP_PERMISSION_PERMIT_LOAD__, + CHERI_PERM_STORE = __CHERI_CAP_PERMISSION_PERMIT_STORE__, + CHERI_PERM_LOAD_CAP = __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__, + CHERI_PERM_STORE_CAP = __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__, + CHERI_PERM_STORE_LOCAL_CAP = __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__, + CHERI_PERM_SEAL = __CHERI_CAP_PERMISSION_PERMIT_SEAL__, +#if !defined(__aarch64__) + CHERI_PERM_CCALL = __CHERI_CAP_PERMISSION_PERMIT_CCALL__, +#else + ARM_CAP_PERMISSION_EXECUTIVE = __ARM_CAP_PERMISSION_EXECUTIVE__, + ARM_CAP_PERMISSION_MUTABLE_LOAD = __ARM_CAP_PERMISSION_MUTABLE_LOAD__, + ARM_CAP_PERMISSION_COMPARTMENT_ID = __ARM_CAP_PERMISSION_COMPARTMENT_ID__, + ARM_CAP_PERMISSION_BRANCH_SEALED_PAIR = __ARM_CAP_PERMISSION_BRANCH_SEALED_PAIR__, +#endif + CHERI_PERM_UNSEAL = __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__, + CHERI_PERM_SYSTEM_REGS = __CHERI_CAP_PERMISSION_ACCESS_SYSTEM_REGISTERS__, + /* TODO: architecture-dependent permissions */ +} cheri_perms_t; +#define cheri_perms_get(x) ((cheri_perms_t)(__builtin_cheri_perms_get(x))) +#define cheri_perms_and(x, y) __builtin_cheri_perms_and((x), (__SIZE_TYPE__)(y)) +#define cheri_perms_clear(x, y) \ + __builtin_cheri_perms_and((x), ~(__SIZE_TYPE__)(y)) + +/* Accessors for capability registers. Currently exposes DDC and PCC. */ +#define cheri_ddc_get() __builtin_cheri_global_data_get() +#define cheri_pcc_get() __builtin_cheri_program_counter_get() + +/* Partially portable builtins: */ +/* Note: {get,set}flags does nothing for MIPS, but can still be used. */ +#define cheri_flags_get(x) __builtin_cheri_flags_get(x) +#define cheri_flags_set(x, y) __builtin_cheri_flags_set((x), (y)) +#define cheri_tags_load(x) __builtin_cheri_cap_load_tags(x) + +/* + * Alignment builtins: Not CHERI-specific, but motivated by CHERI. + * https://clang.llvm.org/docs/LanguageExtensions.html#alignment-builtins + */ +#define cheri_align_up(x, alignment) __builtin_align_up((x), (alignment)) +#define cheri_align_down(x, alignment) __builtin_align_down((x), (alignment)) +#define cheri_is_aligned(x, alignment) __builtin_is_aligned((x), (alignment)) + +#endif /* __GCC_CHERIINTRIN_H */