1//===-- Common internal contructs -------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIBC_SRC___SUPPORT_COMMON_H
10#define LLVM_LIBC_SRC___SUPPORT_COMMON_H
11
12#ifndef LIBC_NAMESPACE
13#error "LIBC_NAMESPACE macro is not defined."
14#endif
15
16#include "src/__support/macros/attributes.h"
17#include "src/__support/macros/config.h"
18#include "src/__support/macros/hardening.h"
19#include "src/__support/macros/properties/architectures.h"
20#include "src/__support/macros/properties/compiler.h"
21#include "src/__support/macros/properties/os.h"
22
23#if defined(__APPLE__) || (defined(LIBC_TARGET_OS_IS_WINDOWS) && \
24 defined(LIBC_TARGET_ARCH_IS_X86_32))
25#define LIBC_TARGET_USES_LEADING_UNDERSCORE
26#endif
27
28#ifndef LLVM_LIBC_FUNCTION_ATTR
29#define LLVM_LIBC_FUNCTION_ATTR
30#endif
31
32#ifndef LLVM_LIBC_VARIABLE_ATTR
33#define LLVM_LIBC_VARIABLE_ATTR
34#endif
35
36// clang-format off
37// Allow each function `func` to have extra attributes specified by defining:
38// `LLVM_LIBC_FUNCTION_ATTR_func` macro, which should always start with
39// "LLVM_LIBC_EMPTY, "
40//
41// For examples:
42// #define LLVM_LIBC_FUNCTION_ATTR_memcpy LLVM_LIBC_EMPTY, [[gnu::weak]]
43// #define LLVM_LIBC_FUNCTION_ATTR_memchr LLVM_LIBC_EMPTY, [[gnu::weak]] [[gnu::visibility("default")]]
44// clang-format on
45#define LLVM_LIBC_EMPTY
46
47#define GET_NOTHING(...) 0
48#define GET_SECOND(first, second, ...) second
49#define GET_FIFTH(first, second, third, fourth, fifth, ...) fifth
50#define EXPAND_THEN_SECOND(name) GET_SECOND(name, LLVM_LIBC_EMPTY)
51
52#define LLVM_LIBC_ATTR(name) EXPAND_THEN_SECOND(LLVM_LIBC_FUNCTION_ATTR_##name)
53
54// Export both `func` and `LIBC_NAMESPACE::func` using an alias symbol.
55// This does not work on platfors with LIBC_TARGET_USES_LEADING_UNDERSCORE
56// so there this only exports `_func`.
57#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
58#ifndef LIBC_TARGET_USES_LEADING_UNDERSCORE
59#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
60 LLVM_LIBC_ATTR(name) \
61 LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
62 __##name##_impl__ asm(c_alias); \
63 decltype(LIBC_NAMESPACE::name) name [[gnu::alias(c_alias)]]; \
64 type __##name##_impl__ arglist
65
66#define LLVM_LIBC_ADD_FUNCTION_C_ALIAS(name, c_alias) \
67 extern "C" decltype(LIBC_NAMESPACE::name) c_alias [[gnu::alias(#name)]]
68
69#else // LIBC_TARGET_USES_LEADING_UNDERSCORE
70#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
71 LLVM_LIBC_ATTR(name) \
72 LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
73 "_" c_alias); \
74 type name arglist
75
76// clang-format off
77#define LLVM_LIBC_ADD_FUNCTION_C_ALIAS(name, c_alias) \
78 asm(".text\n" \
79 ".global " "_" #c_alias "\n" \
80 ".type " "_" #c_alias ", @function\n" \
81 "_" #c_alias " = " "_" #name "\n")
82// clang-format on
83#endif // LIBC_TARGET_USES_LEADING_UNDERSCORE
84
85#else // LIBC_COPT_PUBLIC_PACKAGING
86#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
87 type name arglist
88
89#define LLVM_LIBC_ADD_FUNCTION_C_ALIAS(name, c_alias) \
90 static_assert(true, "Require semicolon.")
91
92#endif // LIBC_COPT_PUBLIC_PACKAGING
93
94#define LLVM_LIBC_FUNCTION_IMPL_3(type, name, arglist) \
95 LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, #name)
96
97// LLVM_LIBC_FUNCTION(type, name, arglist) is equivalent to
98// LLVM_LIBC_FUNCTION(type, name, arglist, #name)
99#define LLVM_LIBC_FUNCTION(...) \
100 GET_FIFTH(__VA_ARGS__, LLVM_LIBC_FUNCTION_IMPL_4, LLVM_LIBC_FUNCTION_IMPL_3, \
101 GET_NOTHING)(__VA_ARGS__)
102
103// See comment on LLVM_LIBC_FUNCTION_IMPL_4 for why this checks
104// LIBC_TARGET_USES_LEADING_UNDERSCORE.
105#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
106#ifndef LIBC_TARGET_USES_LEADING_UNDERSCORE
107#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
108 LLVM_LIBC_ATTR(name) \
109 extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) \
110 __##name##_impl__ asm(#name); \
111 extern decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
112 type __##name##_impl__
113#else // LIBC_TARGET_USES_LEADING_UNDERSCORE
114#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
115 LLVM_LIBC_ATTR(name) \
116 extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
117 "_" #name); \
118 type name
119#endif // LIBC_TARGET_USES_LEADING_UNDERSCORE
120#else // LIBC_COPT_PUBLIC_PACKAGING
121#define LLVM_LIBC_VARIABLE_IMPL(type, name) type name
122#endif // LIBC_COPT_PUBLIC_PACKAGING
123
124#define LLVM_LIBC_VARIABLE(type, name) LLVM_LIBC_VARIABLE_IMPL(type, name)
125
126#endif // LLVM_LIBC_SRC___SUPPORT_COMMON_H
127