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/TargetBuiltins.h"
15#include "clang/Basic/TargetInfo.h"
16#include "llvm/TargetParser/Triple.h"
17
18namespace clang::CodeGenUtils {
19
20//===----------------------------------------------------------------------===//
21// Arm and AArch64
22//===----------------------------------------------------------------------===//
23
24static bool isStreamingCompatible(const FunctionDecl *F) {
25 if (const auto *T = F->getType()->getAs<FunctionProtoType>())
26 return T->getAArch64SMEAttributes() &
27 FunctionType::SME_PStateSMCompatibleMask;
28 return false;
29}
30
31ArmSMEInlinability getArmSMEInlinability(const FunctionDecl *Caller,
32 const FunctionDecl *Callee) {
33 bool CallerIsStreaming =
34 IsArmStreamingFunction(FD: Caller, /*IncludeLocallyStreaming=*/true);
35 bool CalleeIsStreaming =
36 IsArmStreamingFunction(FD: Callee, /*IncludeLocallyStreaming=*/true);
37 bool CallerIsStreamingCompatible = isStreamingCompatible(F: Caller);
38 bool CalleeIsStreamingCompatible = isStreamingCompatible(F: Callee);
39
40 ArmSMEInlinability Inlinability = ArmSMEInlinability::Ok;
41
42 if (!CalleeIsStreamingCompatible &&
43 (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) {
44 if (CalleeIsStreaming)
45 Inlinability |= ArmSMEInlinability::ErrorIncompatibleStreamingModes;
46 else
47 Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
48 }
49 if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) {
50 if (NewAttr->isNewZA())
51 Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
52 if (NewAttr->isNewZT0())
53 Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
54 }
55
56 return Inlinability;
57}
58
59bool hasExtraNeonArgument(unsigned BuiltinID) {
60 // Required by the headers included below, but not in this particular
61 // function.
62 [[maybe_unused]] int PtrArgNum = -1;
63 [[maybe_unused]] bool HasConstPtr = false;
64
65 // The mask encodes the type. We don't care about the actual value. Instead,
66 // we just check whether its been set.
67 uint64_t mask = 0;
68 switch (BuiltinID) {
69#define GET_NEON_OVERLOAD_CHECK
70#include "clang/Basic/arm_fp16.inc"
71#include "clang/Basic/arm_neon.inc"
72#undef GET_NEON_OVERLOAD_CHECK
73 // Non-neon builtins for controling VFP that take extra argument for
74 // discriminating the type.
75 case ARM::BI__builtin_arm_vcvtr_f:
76 case ARM::BI__builtin_arm_vcvtr_d:
77 mask = 1;
78 }
79
80 return mask != 0;
81}
82
83bool isAAPCS(const TargetInfo &TargetInfo) {
84 return TargetInfo.getABI().starts_with(Prefix: "aapcs");
85}
86
87//===----------------------------------------------------------------------===//
88// AMDGPU
89//===----------------------------------------------------------------------===//
90
91bool requiresAMDGPUProtectedVisibility(const Decl *D,
92 bool HasHiddenVisibility) {
93 if (!HasHiddenVisibility)
94 return false;
95
96 return !D->hasAttr<OMPDeclareTargetDeclAttr>() &&
97 (D->hasAttr<DeviceKernelAttr>() ||
98 (isa<FunctionDecl>(Val: D) && D->hasAttr<CUDAGlobalAttr>()) ||
99 (isa<VarDecl>(Val: D) &&
100 (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
101 cast<VarDecl>(Val: D)->getType()->isCUDADeviceBuiltinSurfaceType() ||
102 cast<VarDecl>(Val: D)->getType()->isCUDADeviceBuiltinTextureType())));
103}
104
105//===----------------------------------------------------------------------===//
106// SPIR-V
107//===----------------------------------------------------------------------===//
108
109bool spirNullPointerNeedsGenericCast(QualType QT, const llvm::Triple &Triple) {
110 // LLVM address space of the SPIR-V CodeSectionINTEL storage class.
111 constexpr unsigned SPIRVCodeSectionINTELAddrSpace = 9;
112 LangAS AS = QT->getUnqualifiedDesugaredType()->isNullPtrType()
113 ? LangAS::Default
114 : QT->getPointeeType().getAddressSpace();
115 if (AS == LangAS::Default || AS == LangAS::opencl_generic ||
116 AS == LangAS::opencl_constant)
117 return false;
118 // As per SPV_INTEL_function_pointers, it is illegal to addrspacecast
119 // function pointers to/from the generic AS.
120 return !(Triple.isSPIRV() && isTargetAddressSpace(AS) &&
121 toTargetAddressSpace(AS) == SPIRVCodeSectionINTELAddrSpace);
122}
123
124} // namespace clang::CodeGenUtils
125