1//===--- NVPTX.cpp - Implement NVPTX target feature support ---------------===//
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// This file implements NVPTX TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#include "NVPTX.h"
14#include "clang/Basic/Builtins.h"
15#include "clang/Basic/MacroBuilder.h"
16#include "clang/Basic/TargetBuiltins.h"
17#include "llvm/ADT/StringSwitch.h"
18
19using namespace clang;
20using namespace clang::targets;
21
22static constexpr int NumBuiltins =
23 clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin;
24
25#define GET_BUILTIN_STR_TABLE
26#include "clang/Basic/BuiltinsNVPTX.inc"
27#undef GET_BUILTIN_STR_TABLE
28
29static constexpr Builtin::Info BuiltinInfos[] = {
30#define GET_BUILTIN_INFOS
31#include "clang/Basic/BuiltinsNVPTX.inc"
32#undef GET_BUILTIN_INFOS
33};
34static_assert(std::size(BuiltinInfos) == NumBuiltins);
35
36const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"};
37
38NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
39 const TargetOptions &Opts,
40 unsigned TargetPointerWidth)
41 : TargetInfo(Triple) {
42 assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) &&
43 "NVPTX only supports 32- and 64-bit modes.");
44
45 PTXVersion = 32;
46 for (const StringRef Feature : Opts.FeaturesAsWritten) {
47 int PTXV;
48 if (!Feature.starts_with(Prefix: "+ptx") ||
49 Feature.drop_front(N: 4).getAsInteger(Radix: 10, Result&: PTXV))
50 continue;
51 PTXVersion = PTXV; // TODO: should it be max(PTXVersion, PTXV)?
52 }
53
54 TLSSupported = false;
55 VLASupported = false;
56 AddrSpaceMap = &NVPTXAddrSpaceMap;
57 UseAddrSpaceMapMangling = true;
58 // __bf16 is always available as a load/store only type.
59 BFloat16Width = BFloat16Align = 16;
60 BFloat16Format = &llvm::APFloat::BFloat();
61
62 // Define available target features
63 // These must be defined in sorted order!
64 NoAsmVariants = true;
65 GPU = OffloadArch::UNUSED;
66
67 // PTX supports f16 as a fundamental type.
68 HasFastHalfType = true;
69 HasFloat16 = true;
70
71 // TODO: Make shortptr a proper ABI?
72 DataLayoutString =
73 Triple.computeDataLayout(ABIName: Opts.NVPTXUseShortPointers ? "shortptr" : "");
74
75 // If possible, get a TargetInfo for our host triple, so we can match its
76 // types.
77 llvm::Triple HostTriple(Opts.HostTriple);
78 if (!HostTriple.isNVPTX())
79 HostTarget = AllocateTarget(Triple: llvm::Triple(Opts.HostTriple), Opts);
80
81 // If no host target, make some guesses about the data layout and return.
82 if (!HostTarget) {
83 LongWidth = LongAlign = TargetPointerWidth;
84 PointerWidth = PointerAlign = TargetPointerWidth;
85 switch (TargetPointerWidth) {
86 case 32:
87 SizeType = TargetInfo::UnsignedInt;
88 PtrDiffType = TargetInfo::SignedInt;
89 IntPtrType = TargetInfo::SignedInt;
90 break;
91 case 64:
92 SizeType = TargetInfo::UnsignedLong;
93 PtrDiffType = TargetInfo::SignedLong;
94 IntPtrType = TargetInfo::SignedLong;
95 break;
96 default:
97 llvm_unreachable("TargetPointerWidth must be 32 or 64");
98 }
99
100 MaxAtomicInlineWidth = TargetPointerWidth;
101 return;
102 }
103
104 // Copy properties from host target.
105 PointerWidth = HostTarget->getPointerWidth(AddrSpace: LangAS::Default);
106 PointerAlign = HostTarget->getPointerAlign(AddrSpace: LangAS::Default);
107 BoolWidth = HostTarget->getBoolWidth();
108 BoolAlign = HostTarget->getBoolAlign();
109 IntWidth = HostTarget->getIntWidth();
110 IntAlign = HostTarget->getIntAlign();
111 HalfWidth = HostTarget->getHalfWidth();
112 HalfAlign = HostTarget->getHalfAlign();
113 FloatWidth = HostTarget->getFloatWidth();
114 FloatAlign = HostTarget->getFloatAlign();
115 DoubleWidth = HostTarget->getDoubleWidth();
116 DoubleAlign = HostTarget->getDoubleAlign();
117 LongWidth = HostTarget->getLongWidth();
118 LongAlign = HostTarget->getLongAlign();
119 LongLongWidth = HostTarget->getLongLongWidth();
120 LongLongAlign = HostTarget->getLongLongAlign();
121 MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ Size: 0,
122 /* HasNonWeakDef = */ true);
123 NewAlign = HostTarget->getNewAlign();
124 DefaultAlignForAttributeAligned =
125 HostTarget->getDefaultAlignForAttributeAligned();
126 SizeType = HostTarget->getSizeType();
127 IntMaxType = HostTarget->getIntMaxType();
128 PtrDiffType = HostTarget->getPtrDiffType(AddrSpace: LangAS::Default);
129 IntPtrType = HostTarget->getIntPtrType();
130 WCharType = HostTarget->getWCharType();
131 WIntType = HostTarget->getWIntType();
132 Char16Type = HostTarget->getChar16Type();
133 Char32Type = HostTarget->getChar32Type();
134 Int64Type = HostTarget->getInt64Type();
135 SigAtomicType = HostTarget->getSigAtomicType();
136 ProcessIDType = HostTarget->getProcessIDType();
137
138 UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();
139 UseZeroLengthBitfieldAlignment = HostTarget->useZeroLengthBitfieldAlignment();
140 UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
141 ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();
142
143 // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
144 // we need those macros to be identical on host and device, because (among
145 // other things) they affect which standard library classes are defined, and
146 // we need all classes to be defined on both the host and device.
147 MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();
148
149 // Properties intentionally not copied from host:
150 // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the
151 // host/device boundary.
152 // - SuitableAlign: Not visible across the host/device boundary, and may
153 // correctly be different on host/device, e.g. if host has wider vector
154 // types than device.
155 // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same
156 // as its double type, but that's not necessarily true on the host.
157 // TODO: nvcc emits a warning when using long double on device; we should
158 // do the same.
159}
160
161ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const {
162 return llvm::ArrayRef(GCCRegNames);
163}
164
165bool NVPTXTargetInfo::hasFeature(StringRef Feature) const {
166 return llvm::StringSwitch<bool>(Feature)
167 .Cases(CaseStrings: {"ptx", "nvptx"}, Value: true)
168 .Default(Value: false);
169}
170
171void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
172 MacroBuilder &Builder) const {
173 Builder.defineMacro(Name: "__PTX__");
174 Builder.defineMacro(Name: "__NVPTX__");
175
176 // Skip setting architecture dependent macros if undefined.
177 if (!IsNVIDIAOffloadArch(A: GPU))
178 return;
179
180 if (Opts.CUDAIsDevice || Opts.OpenMPIsTargetDevice || !HostTarget) {
181 // Set __CUDA_ARCH__ for the GPU specified.
182 unsigned ArchID = CudaArchToID(Arch: GPU);
183 Builder.defineMacro(Name: "__CUDA_ARCH__", Value: llvm::Twine(ArchID));
184
185 if (IsNVIDIAAcceleratedOffloadArch(Arch: GPU))
186 Builder.defineMacro(
187 Name: "__CUDA_ARCH_FEAT_SM" + llvm::Twine(ArchID / 10) + "_ALL", Value: "1");
188 }
189}
190
191llvm::SmallVector<Builtin::InfosShard>
192NVPTXTargetInfo::getTargetBuiltins() const {
193 return {{.Strings: &BuiltinStrings, .Infos: BuiltinInfos}};
194}
195