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