1//===--- TargetUtils.cpp - Shared target-specific AST queries ---*- 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#include "clang/CodeGenUtils/TargetUtils.h"
10#include "clang/AST/Attr.h"
11#include "clang/AST/Decl.h"
12#include "clang/AST/Type.h"
13#include "clang/Basic/AddressSpaces.h"
14#include "clang/Basic/Builtins.h"
15#include "clang/Basic/TargetBuiltins.h"
16#include "clang/Basic/TargetInfo.h"
17#include "llvm/ADT/APFloat.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/TargetParser/Triple.h"
20
21namespace clang::CodeGenUtils {
22
23//===----------------------------------------------------------------------===//
24// Library builtins (PowerPC64 and AIX)
25//===----------------------------------------------------------------------===//
26
27StringRef getTargetBuiltinLibFunctionName(unsigned BuiltinID,
28 const TargetInfo &Target) {
29 const llvm::Triple &Triple = Target.getTriple();
30
31 // TODO: This mutation should also be applied to other targets other than
32 // PPC, after backend supports IEEE 128-bit style libcalls.
33 if (Triple.isPPC64() &&
34 &Target.getLongDoubleFormat() == &llvm::APFloat::IEEEquad()) {
35 // TODO: This list should be expanded or refactored after all
36 // GCC-compatible std libcall builtins are implemented.
37 static const llvm::SmallDenseMap<unsigned, StringRef, 64> F128Builtins{
38 {Builtin::BI__builtin___fprintf_chk, "__fprintf_chkieee128"},
39 {Builtin::BI__builtin___printf_chk, "__printf_chkieee128"},
40 {Builtin::BI__builtin___snprintf_chk, "__snprintf_chkieee128"},
41 {Builtin::BI__builtin___sprintf_chk, "__sprintf_chkieee128"},
42 {Builtin::BI__builtin___vfprintf_chk, "__vfprintf_chkieee128"},
43 {Builtin::BI__builtin___vprintf_chk, "__vprintf_chkieee128"},
44 {Builtin::BI__builtin___vsnprintf_chk, "__vsnprintf_chkieee128"},
45 {Builtin::BI__builtin___vsprintf_chk, "__vsprintf_chkieee128"},
46 {Builtin::BI__builtin_fprintf, "__fprintfieee128"},
47 {Builtin::BI__builtin_printf, "__printfieee128"},
48 {Builtin::BI__builtin_snprintf, "__snprintfieee128"},
49 {Builtin::BI__builtin_sprintf, "__sprintfieee128"},
50 {Builtin::BI__builtin_vfprintf, "__vfprintfieee128"},
51 {Builtin::BI__builtin_vprintf, "__vprintfieee128"},
52 {Builtin::BI__builtin_vsnprintf, "__vsnprintfieee128"},
53 {Builtin::BI__builtin_vsprintf, "__vsprintfieee128"},
54 {Builtin::BI__builtin_fscanf, "__fscanfieee128"},
55 {Builtin::BI__builtin_scanf, "__scanfieee128"},
56 {Builtin::BI__builtin_sscanf, "__sscanfieee128"},
57 {Builtin::BI__builtin_vfscanf, "__vfscanfieee128"},
58 {Builtin::BI__builtin_vscanf, "__vscanfieee128"},
59 {Builtin::BI__builtin_vsscanf, "__vsscanfieee128"},
60 {Builtin::BI__builtin_nexttowardf128, "__nexttowardieee128"},
61 };
62 return F128Builtins.lookup(Val: BuiltinID);
63 }
64
65 // The AIX library functions frexpl, ldexpl, and modfl are for 128-bit
66 // IBM 'long double' (i.e. __ibm128). Map to the 'double' versions
67 // if it is 64-bit 'long double' mode.
68 if (Triple.isOSAIX() &&
69 &Target.getLongDoubleFormat() == &llvm::APFloat::IEEEdouble()) {
70 static const llvm::SmallDenseMap<unsigned, StringRef, 4>
71 AIXLongDouble64Builtins{
72 {Builtin::BI__builtin_frexpl, "frexp"},
73 {Builtin::BI__builtin_ldexpl, "ldexp"},
74 {Builtin::BI__builtin_modfl, "modf"},
75 };
76 return AIXLongDouble64Builtins.lookup(Val: BuiltinID);
77 }
78
79 return StringRef();
80}
81
82//===----------------------------------------------------------------------===//
83// Arm and AArch64
84//===----------------------------------------------------------------------===//
85
86static bool isStreamingCompatible(const FunctionDecl *F) {
87 if (const auto *T = F->getType()->getAs<FunctionProtoType>())
88 return T->getAArch64SMEAttributes() &
89 FunctionType::SME_PStateSMCompatibleMask;
90 return false;
91}
92
93ArmSMEInlinability getArmSMEInlinability(const FunctionDecl *Caller,
94 const FunctionDecl *Callee) {
95 bool CallerIsStreaming =
96 IsArmStreamingFunction(FD: Caller, /*IncludeLocallyStreaming=*/true);
97 bool CalleeIsStreaming =
98 IsArmStreamingFunction(FD: Callee, /*IncludeLocallyStreaming=*/true);
99 bool CallerIsStreamingCompatible = isStreamingCompatible(F: Caller);
100 bool CalleeIsStreamingCompatible = isStreamingCompatible(F: Callee);
101
102 ArmSMEInlinability Inlinability = ArmSMEInlinability::Ok;
103
104 if (!CalleeIsStreamingCompatible &&
105 (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) {
106 if (CalleeIsStreaming)
107 Inlinability |= ArmSMEInlinability::ErrorIncompatibleStreamingModes;
108 else
109 Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
110 }
111 if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) {
112 if (NewAttr->isNewZA())
113 Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
114 if (NewAttr->isNewZT0())
115 Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
116 }
117
118 return Inlinability;
119}
120
121bool hasExtraNeonArgument(unsigned BuiltinID) {
122 // Required by the headers included below, but not in this particular
123 // function.
124 [[maybe_unused]] int PtrArgNum = -1;
125 [[maybe_unused]] bool HasConstPtr = false;
126
127 // The mask encodes the type. We don't care about the actual value. Instead,
128 // we just check whether its been set.
129 uint64_t mask = 0;
130 switch (BuiltinID) {
131#define GET_NEON_OVERLOAD_CHECK
132#include "clang/Basic/arm_fp16.inc"
133#include "clang/Basic/arm_neon.inc"
134#undef GET_NEON_OVERLOAD_CHECK
135 // Non-neon builtins for controling VFP that take extra argument for
136 // discriminating the type.
137 case ARM::BI__builtin_arm_vcvtr_f:
138 case ARM::BI__builtin_arm_vcvtr_d:
139 mask = 1;
140 }
141
142 return mask != 0;
143}
144
145bool isAAPCS(const TargetInfo &TargetInfo) {
146 return TargetInfo.getABI().starts_with(Prefix: "aapcs");
147}
148
149//===----------------------------------------------------------------------===//
150// AMDGPU
151//===----------------------------------------------------------------------===//
152
153bool requiresAMDGPUProtectedVisibility(const Decl *D,
154 bool HasHiddenVisibility) {
155 if (!HasHiddenVisibility)
156 return false;
157
158 return !D->hasAttr<OMPDeclareTargetDeclAttr>() &&
159 (D->hasAttr<DeviceKernelAttr>() ||
160 (isa<FunctionDecl>(Val: D) && D->hasAttr<CUDAGlobalAttr>()) ||
161 (isa<VarDecl>(Val: D) &&
162 (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
163 cast<VarDecl>(Val: D)->getType()->isCUDADeviceBuiltinSurfaceType() ||
164 cast<VarDecl>(Val: D)->getType()->isCUDADeviceBuiltinTextureType())));
165}
166
167//===----------------------------------------------------------------------===//
168// SPIR-V
169//===----------------------------------------------------------------------===//
170
171bool spirNullPointerNeedsGenericCast(QualType QT, const llvm::Triple &Triple) {
172 // LLVM address space of the SPIR-V CodeSectionINTEL storage class.
173 constexpr unsigned SPIRVCodeSectionINTELAddrSpace = 9;
174 LangAS AS = QT->getUnqualifiedDesugaredType()->isNullPtrType()
175 ? LangAS::Default
176 : QT->getPointeeType().getAddressSpace();
177 if (AS == LangAS::Default || AS == LangAS::opencl_generic ||
178 AS == LangAS::opencl_constant)
179 return false;
180 // As per SPV_INTEL_function_pointers, it is illegal to addrspacecast
181 // function pointers to/from the generic AS.
182 return !(Triple.isSPIRV() && isTargetAddressSpace(AS) &&
183 toTargetAddressSpace(AS) == SPIRVCodeSectionINTELAddrSpace);
184}
185
186} // namespace clang::CodeGenUtils
187