xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp (revision df122fc734ce002632f3bfe8a5fc5010349dba16)
1 //===-- SPIRVSubtarget.cpp - SPIR-V Subtarget Information ------*- 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 // This file implements the SPIR-V specific subclass of TargetSubtargetInfo.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "SPIRVSubtarget.h"
14 #include "SPIRV.h"
15 #include "SPIRVCommandLine.h"
16 #include "SPIRVGlobalRegistry.h"
17 #include "SPIRVLegalizerInfo.h"
18 #include "SPIRVRegisterBankInfo.h"
19 #include "SPIRVTargetMachine.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/TargetParser/Host.h"
22 
23 using namespace llvm;
24 
25 #define DEBUG_TYPE "spirv-subtarget"
26 
27 #define GET_SUBTARGETINFO_TARGET_DESC
28 #define GET_SUBTARGETINFO_CTOR
29 #include "SPIRVGenSubtargetInfo.inc"
30 
31 static cl::opt<bool>
32     SPVTranslatorCompat("translator-compatibility-mode",
33                         cl::desc("SPIR-V Translator compatibility mode"),
34                         cl::Optional, cl::init(false));
35 
36 static cl::opt<std::set<SPIRV::Extension::Extension>, false,
37                SPIRVExtensionsParser>
38     Extensions("spirv-ext",
39                cl::desc("Specify list of enabled SPIR-V extensions"));
40 
41 // Provides access to the cl::opt<...> `Extensions` variable from outside of the
42 // module.
43 void SPIRVSubtarget::addExtensionsToClOpt(
44     const std::set<SPIRV::Extension::Extension> &AllowList) {
45   Extensions.insert(AllowList.begin(), AllowList.end());
46 }
47 
48 // Compare version numbers, but allow 0 to mean unspecified.
49 static bool isAtLeastVer(VersionTuple Target, VersionTuple VerToCompareTo) {
50   return Target.empty() || Target >= VerToCompareTo;
51 }
52 
53 SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU,
54                                const std::string &FS,
55                                const SPIRVTargetMachine &TM)
56     : SPIRVGenSubtargetInfo(TT, CPU, /*TuneCPU=*/CPU, FS),
57       PointerSize(TM.getPointerSizeInBits(/* AS= */ 0)), InstrInfo(),
58       FrameLowering(initSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
59       TargetTriple(TT) {
60   switch (TT.getSubArch()) {
61   case Triple::SPIRVSubArch_v10:
62     SPIRVVersion = VersionTuple(1, 0);
63     break;
64   case Triple::SPIRVSubArch_v11:
65     SPIRVVersion = VersionTuple(1, 1);
66     break;
67   case Triple::SPIRVSubArch_v12:
68     SPIRVVersion = VersionTuple(1, 2);
69     break;
70   case Triple::SPIRVSubArch_v13:
71     SPIRVVersion = VersionTuple(1, 3);
72     break;
73   case Triple::SPIRVSubArch_v14:
74   default:
75     SPIRVVersion = VersionTuple(1, 4);
76     break;
77   case Triple::SPIRVSubArch_v15:
78     SPIRVVersion = VersionTuple(1, 5);
79     break;
80   case Triple::SPIRVSubArch_v16:
81     SPIRVVersion = VersionTuple(1, 6);
82     break;
83   }
84   OpenCLVersion = VersionTuple(2, 2);
85 
86   // The order of initialization is important.
87   initAvailableExtensions(Extensions);
88   initAvailableExtInstSets();
89 
90   GR = std::make_unique<SPIRVGlobalRegistry>(PointerSize);
91   CallLoweringInfo = std::make_unique<SPIRVCallLowering>(TLInfo, GR.get());
92   InlineAsmInfo = std::make_unique<SPIRVInlineAsmLowering>(TLInfo);
93   Legalizer = std::make_unique<SPIRVLegalizerInfo>(*this);
94   RegBankInfo = std::make_unique<SPIRVRegisterBankInfo>();
95   InstSelector.reset(
96       createSPIRVInstructionSelector(TM, *this, *RegBankInfo.get()));
97 }
98 
99 SPIRVSubtarget &SPIRVSubtarget::initSubtargetDependencies(StringRef CPU,
100                                                           StringRef FS) {
101   ParseSubtargetFeatures(CPU, /*TuneCPU=*/CPU, FS);
102   return *this;
103 }
104 
105 bool SPIRVSubtarget::canUseExtension(SPIRV::Extension::Extension E) const {
106   return AvailableExtensions.contains(E);
107 }
108 
109 bool SPIRVSubtarget::canUseExtInstSet(
110     SPIRV::InstructionSet::InstructionSet E) const {
111   return AvailableExtInstSets.contains(E);
112 }
113 
114 SPIRV::InstructionSet::InstructionSet
115 SPIRVSubtarget::getPreferredInstructionSet() const {
116   if (isOpenCLEnv())
117     return SPIRV::InstructionSet::OpenCL_std;
118   else
119     return SPIRV::InstructionSet::GLSL_std_450;
120 }
121 
122 bool SPIRVSubtarget::isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const {
123   return isAtLeastVer(SPIRVVersion, VerToCompareTo);
124 }
125 
126 bool SPIRVSubtarget::isAtLeastOpenCLVer(VersionTuple VerToCompareTo) const {
127   if (!isOpenCLEnv())
128     return false;
129   return isAtLeastVer(OpenCLVersion, VerToCompareTo);
130 }
131 
132 // If the SPIR-V version is >= 1.4 we can call OpPtrEqual and OpPtrNotEqual.
133 // In SPIR-V Translator compatibility mode this feature is not available.
134 bool SPIRVSubtarget::canDirectlyComparePointers() const {
135   return !SPVTranslatorCompat && isAtLeastVer(SPIRVVersion, VersionTuple(1, 4));
136 }
137 
138 void SPIRVSubtarget::accountForAMDShaderTrinaryMinmax() {
139   if (canUseExtension(
140           SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) {
141     AvailableExtInstSets.insert(
142         SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax);
143   }
144 }
145 
146 // TODO: use command line args for this rather than just defaults.
147 // Must have called initAvailableExtensions first.
148 void SPIRVSubtarget::initAvailableExtInstSets() {
149   AvailableExtInstSets.clear();
150   if (!isOpenCLEnv())
151     AvailableExtInstSets.insert(SPIRV::InstructionSet::GLSL_std_450);
152   else
153     AvailableExtInstSets.insert(SPIRV::InstructionSet::OpenCL_std);
154 
155   // Handle extended instruction sets from extensions.
156   accountForAMDShaderTrinaryMinmax();
157 }
158 
159 // Set available extensions after SPIRVSubtarget is created.
160 void SPIRVSubtarget::initAvailableExtensions(
161     const std::set<SPIRV::Extension::Extension> &AllowedExtIds) {
162   AvailableExtensions.clear();
163   AvailableExtensions.insert(AllowedExtIds.begin(), AllowedExtIds.end());
164 
165   accountForAMDShaderTrinaryMinmax();
166 }
167