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 | // Compare version numbers, but allow 0 to mean unspecified. |
42 | static bool isAtLeastVer(VersionTuple Target, VersionTuple VerToCompareTo) { |
43 | return Target.empty() || Target >= VerToCompareTo; |
44 | } |
45 | |
46 | SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, |
47 | const std::string &FS, |
48 | const SPIRVTargetMachine &TM) |
49 | : SPIRVGenSubtargetInfo(TT, CPU, /*TuneCPU=*/CPU, FS), |
50 | PointerSize(TM.getPointerSizeInBits(/* AS= */ 0)), InstrInfo(), |
51 | FrameLowering(initSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), |
52 | TargetTriple(TT) { |
53 | switch (TT.getSubArch()) { |
54 | case Triple::SPIRVSubArch_v10: |
55 | SPIRVVersion = VersionTuple(1, 0); |
56 | break; |
57 | case Triple::SPIRVSubArch_v11: |
58 | SPIRVVersion = VersionTuple(1, 1); |
59 | break; |
60 | case Triple::SPIRVSubArch_v12: |
61 | SPIRVVersion = VersionTuple(1, 2); |
62 | break; |
63 | case Triple::SPIRVSubArch_v13: |
64 | SPIRVVersion = VersionTuple(1, 3); |
65 | break; |
66 | case Triple::SPIRVSubArch_v14: |
67 | default: |
68 | SPIRVVersion = VersionTuple(1, 4); |
69 | break; |
70 | case Triple::SPIRVSubArch_v15: |
71 | SPIRVVersion = VersionTuple(1, 5); |
72 | break; |
73 | case Triple::SPIRVSubArch_v16: |
74 | SPIRVVersion = VersionTuple(1, 6); |
75 | break; |
76 | } |
77 | OpenCLVersion = VersionTuple(2, 2); |
78 | |
79 | // The order of initialization is important. |
80 | initAvailableExtensions(); |
81 | initAvailableExtInstSets(); |
82 | |
83 | GR = std::make_unique<SPIRVGlobalRegistry>(PointerSize); |
84 | CallLoweringInfo = std::make_unique<SPIRVCallLowering>(TLInfo, GR.get()); |
85 | Legalizer = std::make_unique<SPIRVLegalizerInfo>(*this); |
86 | RegBankInfo = std::make_unique<SPIRVRegisterBankInfo>(); |
87 | InstSelector.reset( |
88 | createSPIRVInstructionSelector(TM, *this, *RegBankInfo.get())); |
89 | } |
90 | |
91 | SPIRVSubtarget &SPIRVSubtarget::initSubtargetDependencies(StringRef CPU, |
92 | StringRef FS) { |
93 | ParseSubtargetFeatures(CPU, /*TuneCPU=*/CPU, FS); |
94 | return *this; |
95 | } |
96 | |
97 | bool SPIRVSubtarget::canUseExtension(SPIRV::Extension::Extension E) const { |
98 | return AvailableExtensions.contains(E); |
99 | } |
100 | |
101 | bool SPIRVSubtarget::canUseExtInstSet( |
102 | SPIRV::InstructionSet::InstructionSet E) const { |
103 | return AvailableExtInstSets.contains(E); |
104 | } |
105 | |
106 | bool SPIRVSubtarget::isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const { |
107 | return isAtLeastVer(Target: SPIRVVersion, VerToCompareTo); |
108 | } |
109 | |
110 | bool SPIRVSubtarget::isAtLeastOpenCLVer(VersionTuple VerToCompareTo) const { |
111 | if (!isOpenCLEnv()) |
112 | return false; |
113 | return isAtLeastVer(Target: OpenCLVersion, VerToCompareTo); |
114 | } |
115 | |
116 | // If the SPIR-V version is >= 1.4 we can call OpPtrEqual and OpPtrNotEqual. |
117 | // In SPIR-V Translator compatibility mode this feature is not available. |
118 | bool SPIRVSubtarget::canDirectlyComparePointers() const { |
119 | return !SPVTranslatorCompat && isAtLeastVer(Target: SPIRVVersion, VerToCompareTo: VersionTuple(1, 4)); |
120 | } |
121 | |
122 | void SPIRVSubtarget::initAvailableExtensions() { |
123 | AvailableExtensions.clear(); |
124 | if (!isOpenCLEnv()) |
125 | return; |
126 | |
127 | AvailableExtensions.insert(Extensions.begin(), Extensions.end()); |
128 | } |
129 | |
130 | // TODO: use command line args for this rather than just defaults. |
131 | // Must have called initAvailableExtensions first. |
132 | void SPIRVSubtarget::initAvailableExtInstSets() { |
133 | AvailableExtInstSets.clear(); |
134 | if (!isOpenCLEnv()) |
135 | AvailableExtInstSets.insert(SPIRV::InstructionSet::GLSL_std_450); |
136 | else |
137 | AvailableExtInstSets.insert(SPIRV::InstructionSet::OpenCL_std); |
138 | |
139 | // Handle extended instruction sets from extensions. |
140 | if (canUseExtension( |
141 | SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) { |
142 | AvailableExtInstSets.insert( |
143 | SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax); |
144 | } |
145 | } |
146 | |