/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_COMPILER_H
#define __LINUX_COMPILER_H

#include <linux/compiler_types.h>

#ifndef __ASSEMBLY__

#ifdef __KERNEL__


void ftrace_likely_update(struct ftrace_likely_data *f, int val,
			  int expect, int is_constant);
#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
    && !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
#define likely_notrace(x)	__builtin_expect(!!(x), 1)
#define unlikely_notrace(x)	__builtin_expect(!!(x), 0)

#define __branch_check__(x, expect, is_constant) ({			\
			long ______r;					\
			static struct ftrace_likely_data		\
				__aligned(4)				\
				__section("_ftrace_annotated_branch")	\
				______f = {				\
				.data.func = __func__,			\
				.data.file = __FILE__,			\
				.data.line = __LINE__,			\
			};						\
			______r = __builtin_expect(!!(x), expect);	\
			ftrace_likely_update(&______f, ______r,		\
					     expect, is_constant);	\
			______r;					\
		})


# ifndef likely
#  define likely(x)	(__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
#  define unlikely(x)	(__branch_check__(x, 0, __builtin_constant_p(x)))
# endif

#ifdef CONFIG_PROFILE_ALL_BRANCHES

#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )

#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))

#define __trace_if_value(cond) ({			\
	static struct ftrace_branch_data		\
		__aligned(4)				\
		__section("_ftrace_branch")		\
		__if_trace = {				\
			.func = __func__,		\
			.file = __FILE__,		\
			.line = __LINE__,		\
		};					\
	(cond) ?					\
		(__if_trace.miss_hit[1]++,1) :		\
		(__if_trace.miss_hit[0]++,0);		\
})

#endif 

#else
# define likely(x)	__builtin_expect(!!(x), 1)
# define unlikely(x)	__builtin_expect(!!(x), 0)
# define likely_notrace(x)	likely(x)
# define unlikely_notrace(x)	unlikely(x)
#endif


#ifndef barrier

# define barrier() __asm__ __volatile__("": : :"memory")
#endif

#ifndef barrier_data

# define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
#endif


#ifndef barrier_before_unreachable
# define barrier_before_unreachable() do { } while (0)
#endif


#ifdef CONFIG_OBJTOOL

#define __annotate_jump_table __section(".data.rel.ro.c_jump_table")
#else 
#define __annotate_jump_table
#endif 


#define unreachable() do {		\
	barrier_before_unreachable();	\
	__builtin_unreachable();	\
} while (0)


#ifndef KENTRY
# define KENTRY(sym)						\
	extern typeof(sym) sym;					\
	static const unsigned long __kentry_##sym		\
	__used							\
	__attribute__((__section__("___kentry+" #sym)))		\
	= (unsigned long)&sym;
#endif

#ifndef RELOC_HIDE
# define RELOC_HIDE(ptr, off)					\
  ({ unsigned long __ptr;					\
     __ptr = (unsigned long) (ptr);				\
    (typeof(ptr)) (__ptr + (off)); })
#endif

#define absolute_pointer(val)	RELOC_HIDE((void *)(val), 0)

#ifndef OPTIMIZER_HIDE_VAR

#define OPTIMIZER_HIDE_VAR(var)						\
	__asm__ ("" : "=r" (var) : "0" (var))
#endif


#define __UNIQUE_ID(name)					\
	__PASTE(__UNIQUE_ID_,					\
	__PASTE(name,						\
	__PASTE(_, __COUNTER__)))


#define data_race(expr)							\
({									\
	__kcsan_disable_current();					\
	disable_context_analysis();					\
	auto __v = (expr);						\
	enable_context_analysis();					\
	__kcsan_enable_current();					\
	__v;								\
})

#ifdef __CHECKER__
#define __BUILD_BUG_ON_ZERO_MSG(e, msg, ...) (0)
#else 
#define __BUILD_BUG_ON_ZERO_MSG(e, msg, ...) ((int)sizeof(struct {_Static_assert(!(e), msg);}))
#endif 


#define __is_array(a)		(!__same_type((a), &(a)[0]))
#define __must_be_array(a)	__BUILD_BUG_ON_ZERO_MSG(!__is_array(a), \
							"must be array")

#define __is_byte_array(a)	(__is_array(a) && sizeof((a)[0]) == 1)
#define __must_be_byte_array(a)	__BUILD_BUG_ON_ZERO_MSG(!__is_byte_array(a), \
							"must be byte array")


#if __has_attribute(__nonstring__) && defined(__annotated)
#define __is_cstr(a)		(!__annotated(a, nonstring))
#define __is_noncstr(a)		(__annotated(a, nonstring))
#else
#define __is_cstr(a)		(true)
#define __is_noncstr(a)		(true)
#endif


#define __must_be_cstr(p) \
	__BUILD_BUG_ON_ZERO_MSG(!__is_cstr(p), \
				"must be C-string (NUL-terminated)")
#define __must_be_noncstr(p) \
	__BUILD_BUG_ON_ZERO_MSG(!__is_noncstr(p), \
				"must be non-C-string (not NUL-terminated)")


#if defined(USE_TYPEOF_UNQUAL)
# define TYPEOF_UNQUAL(exp) __typeof_unqual__(exp)
#else
# define TYPEOF_UNQUAL(exp) __typeof__(exp)
#endif

#endif 

#if defined(CONFIG_CFI) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)

#define KCFI_REFERENCE(sym) __ADDRESSABLE(sym)
#else
#define KCFI_REFERENCE(sym)
#endif


static inline void *offset_to_ptr(const int *off)
{
	return (void *)((unsigned long)off + *off);
}

#endif 


#define ___ADDRESSABLE(sym, __attrs)						\
	static void * __used __attrs						\
	__UNIQUE_ID(__PASTE(addressable_, sym)) = (void *)(uintptr_t)&sym;

#define __ADDRESSABLE(sym) \
	___ADDRESSABLE(sym, __section(".discard.addressable"))


#define __is_constexpr(x) \
	(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))


#define is_signed_type(type) (((type)(-1)) < (__force type)1)
#define is_unsigned_type(type) (!is_signed_type(type))


#define statically_true(x) (__builtin_constant_p(x) && (x))


#define const_true(x) __builtin_choose_expr(__is_constexpr(x), x, false)


#define prevent_tail_call_optimization()	mb()

#include <asm/rwonce.h>

#endif 
