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/properties/architectures.h"
19#include "src/__support/macros/properties/compiler.h"
20
21#ifndef LLVM_LIBC_FUNCTION_ATTR
22#define LLVM_LIBC_FUNCTION_ATTR
23#endif
24
25#ifndef LLVM_LIBC_VARIABLE_ATTR
26#define LLVM_LIBC_VARIABLE_ATTR
27#endif
28
29// clang-format off
30// Allow each function `func` to have extra attributes specified by defining:
31// `LLVM_LIBC_FUNCTION_ATTR_func` macro, which should always start with
32// "LLVM_LIBC_EMPTY, "
33//
34// For examples:
35// #define LLVM_LIBC_FUNCTION_ATTR_memcpy LLVM_LIBC_EMPTY, [[gnu::weak]]
36// #define LLVM_LIBC_FUNCTION_ATTR_memchr LLVM_LIBC_EMPTY, [[gnu::weak]] [[gnu::visibility("default")]]
37// clang-format on
38#define LLVM_LIBC_EMPTY
39
40#define GET_NOTHING(...) 0
41#define GET_SECOND(first, second, ...) second
42#define GET_FIFTH(first, second, third, fourth, fifth, ...) fifth
43#define EXPAND_THEN_SECOND(name) GET_SECOND(name, LLVM_LIBC_EMPTY)
44
45#define LLVM_LIBC_ATTR(name) EXPAND_THEN_SECOND(LLVM_LIBC_FUNCTION_ATTR_##name)
46
47// At the moment, [[gnu::alias()]] is not supported on MacOS, and it is needed
48// to cleanly export and alias the C++ symbol `LIBC_NAMESPACE::func` with the C
49// symbol `func`. So for public packaging on MacOS, we will only export the C
50// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`.
51#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
52#ifndef __APPLE__
53#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
54 LLVM_LIBC_ATTR(name) \
55 LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
56 __##name##_impl__ asm(c_alias); \
57 decltype(LIBC_NAMESPACE::name) name [[gnu::alias(c_alias)]]; \
58 type __##name##_impl__ arglist
59#else // __APPLE__
60#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
61 LLVM_LIBC_ATTR(name) \
62 LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
63 "_" c_alias); \
64 type name arglist
65#endif // __APPLE__
66
67#else // LIBC_COPT_PUBLIC_PACKAGING
68#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
69 type name arglist
70#endif // LIBC_COPT_PUBLIC_PACKAGING
71
72#define LLVM_LIBC_FUNCTION_IMPL_3(type, name, arglist) \
73 LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, #name)
74
75// LLVM_LIBC_FUNCTION(type, name, arglist) is equivalent to
76// LLVM_LIBC_FUNCTION(type, name, arglist, #name)
77#define LLVM_LIBC_FUNCTION(...) \
78 GET_FIFTH(__VA_ARGS__, LLVM_LIBC_FUNCTION_IMPL_4, LLVM_LIBC_FUNCTION_IMPL_3, \
79 GET_NOTHING)(__VA_ARGS__)
80
81// At the moment, [[gnu::alias()]] is not supported on MacOS, and it is needed
82// to cleanly export and alias the C++ symbol `LIBC_NAMESPACE::func` with the C
83// symbol `func`. So for public packaging on MacOS, we will only export the C
84// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`.
85#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
86#ifndef __APPLE__
87#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
88 LLVM_LIBC_ATTR(name) \
89 extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) \
90 __##name##_impl__ asm(#name); \
91 extern decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
92 type __##name##_impl__
93#else // __APPLE__
94#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
95 LLVM_LIBC_ATTR(name) \
96 extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
97 "_" #name); \
98 type name
99#endif // __APPLE__
100#else // LIBC_COPT_PUBLIC_PACKAGING
101#define LLVM_LIBC_VARIABLE_IMPL(type, name) type name
102#endif // LIBC_COPT_PUBLIC_PACKAGING
103
104#define LLVM_LIBC_VARIABLE(type, name) LLVM_LIBC_VARIABLE_IMPL(type, name)
105
106#endif // LLVM_LIBC_SRC___SUPPORT_COMMON_H
107