mirror-llvm-project/clang/lib/Basic/Targets/NVPTX.h
Matt Arsenault 3c3a18e239
clang: Store vendor GPU kinds in OffloadArch instead of re-listing GPUs (#213362)
OffloadArch was a flat enum that hand-duplicated every AMDGPU and NVPTX
target, plus a few edge cases. This was yet another place that needed
updating every time a new target is added, which should now be avoided.
Replace with a tagged union-like scheme.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply@anthropic.com>
2026-08-01 06:14:04 +00:00

205 lines
6.8 KiB
C++

//===--- NVPTX.h - Declare NVPTX target feature support ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares NVPTX TargetInfo objects.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
#define LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
#include "clang/Basic/Cuda.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/NVPTXAddrSpace.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
namespace clang {
namespace targets {
static constexpr LangASMap NVPTXAddrSpaceMap = {
{LangAS::opencl_global, 1},
{LangAS::opencl_local, 3},
{LangAS::opencl_constant, 4},
// FIXME: generic has to be added to the target
{LangAS::opencl_generic, 0},
{LangAS::opencl_global_device, 1},
{LangAS::opencl_global_host, 1},
{LangAS::cuda_device, 1},
{LangAS::cuda_constant, 4},
{LangAS::cuda_shared, 3},
{LangAS::sycl_global, 1},
{LangAS::sycl_global_device, 1},
{LangAS::sycl_global_host, 1},
{LangAS::sycl_local, 3},
};
/// The DWARF address class. Taken from
/// https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf
static const int NVPTXDWARFAddrSpaceMap[] = {
-1, // Default, opencl_private or opencl_generic - not defined
5, // opencl_global
-1,
8, // opencl_local or cuda_shared
4, // opencl_constant or cuda_constant
};
class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
static const char *const GCCRegNames[];
OffloadArch GPU;
uint32_t PTXVersion;
std::unique_ptr<TargetInfo> HostTarget;
public:
NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts,
unsigned TargetPointerWidth);
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
bool isCLZForZeroUndef() const override { return false; }
bool
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
StringRef CPU,
const std::vector<std::string> &FeaturesVec) const override {
if (!GPU.isUnused())
Features[OffloadArchToString(GPU)] = true;
// Only add PTX feature if explicitly requested. Otherwise, let the backend
// use the minimum required PTX version for the target SM.
if (PTXVersion != 0)
Features["ptx" + std::to_string(PTXVersion)] = true;
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
}
bool hasFeature(StringRef Feature) const override;
virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override {
// The generic address space AS(0) is a superset of all the other address
// spaces used by the backend target.
return A == B ||
((A == LangAS::Default ||
(isTargetAddressSpace(A) &&
toTargetAddressSpace(A) ==
llvm::NVPTXAS::ADDRESS_SPACE_GENERIC)) &&
isTargetAddressSpace(B) &&
toTargetAddressSpace(B) >= llvm::NVPTXAS::ADDRESS_SPACE_GENERIC &&
toTargetAddressSpace(B) <= llvm::NVPTXAS::ADDRESS_SPACE_LOCAL &&
toTargetAddressSpace(B) != 2);
}
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
// No aliases.
return {};
}
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default:
return false;
case 'c':
case 'h':
case 'r':
case 'l':
case 'f':
case 'd':
case 'q':
Info.setAllowsRegister();
return true;
}
}
std::string_view getClobbers() const override {
// FIXME: Is this really right?
return "";
}
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
bool isValidCPUName(StringRef Name) const override {
return !StringToOffloadArch(Name).isUnknown();
}
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
fillValidOffloadArchList(Values);
}
bool setCPU(StringRef Name) override {
GPU = StringToOffloadArch(Name);
return !GPU.isUnknown();
}
void setSupportedOpenCLOpts() override {
auto &Opts = getSupportedOpenCLOpts();
Opts["cl_clang_storage_class_specifiers"] = true;
Opts["__cl_clang_function_pointers"] = true;
Opts["__cl_clang_variadic_functions"] = true;
Opts["__cl_clang_function_scope_local_variables"] = true;
Opts["__cl_clang_non_portable_kernel_param_types"] = true;
Opts["__cl_clang_bitfields"] = true;
Opts["cl_khr_fp64"] = true;
Opts["__opencl_c_fp64"] = true;
Opts["cl_khr_byte_addressable_store"] = true;
Opts["cl_khr_global_int32_base_atomics"] = true;
Opts["cl_khr_global_int32_extended_atomics"] = true;
Opts["cl_khr_local_int32_base_atomics"] = true;
Opts["cl_khr_local_int32_extended_atomics"] = true;
Opts["__opencl_c_images"] = true;
Opts["__opencl_c_3d_image_writes"] = true;
Opts["cl_khr_3d_image_writes"] = true;
Opts["__opencl_c_generic_address_space"] = true;
}
const llvm::omp::GV &getGridValue() const override {
return llvm::omp::NVPTXGridValues;
}
/// \returns If a target requires an address within a target specific address
/// space \p AddressSpace to be converted in order to be used, then return the
/// corresponding target specific DWARF address space.
///
/// \returns Otherwise return std::nullopt and no conversion will be emitted
/// in the DWARF.
std::optional<unsigned>
getDWARFAddressSpace(unsigned AddressSpace) const override {
if (AddressSpace >= std::size(NVPTXDWARFAddrSpaceMap) ||
NVPTXDWARFAddrSpaceMap[AddressSpace] < 0)
return std::nullopt;
return NVPTXDWARFAddrSpaceMap[AddressSpace];
}
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
// CUDA compilations support all of the host's calling conventions.
//
// TODO: We should warn if you apply a non-default CC to anything other than
// a host function.
if (HostTarget)
return HostTarget->checkCallingConvention(CC);
return CC == CC_DeviceKernel ? CCCR_OK : CCCR_Warning;
}
bool hasBitIntType() const override { return true; }
bool hasBFloat16Type() const override { return true; }
OffloadArch getGPU() const { return GPU; }
};
} // namespace targets
} // namespace clang
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H