1 //===- LLVMSPIRVOpts.h - Specify options for translation --------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // Copyright (c) 2019 Intel Corporation. All rights reserved.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal with the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // Redistributions of source code must retain the above copyright notice,
18 // this list of conditions and the following disclaimers.
19 // Redistributions in binary form must reproduce the above copyright notice,
20 // this list of conditions and the following disclaimers in the documentation
21 // and/or other materials provided with the distribution.
22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
23 // contributors may be used to endorse or promote products derived from this
24 // Software without specific prior written permission.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
31 // THE SOFTWARE.
32 //
33 //===----------------------------------------------------------------------===//
34 /// \file LLVMSPIRVOpts.h
35 ///
36 /// This files declares helper classes to handle SPIR-V versions and extensions.
37 ///
38 //===----------------------------------------------------------------------===//
39 #ifndef SPIRV_LLVMSPIRVOPTS_H
40 #define SPIRV_LLVMSPIRVOPTS_H
41 
42 #include <llvm/ADT/Optional.h>
43 #include <llvm/ADT/SmallVector.h>
44 #include <llvm/ADT/StringRef.h>
45 
46 #include <cassert>
47 #include <cstdint>
48 #include <map>
49 #include <unordered_map>
50 
51 namespace llvm {
52 class IntrinsicInst;
53 } // namespace llvm
54 
55 namespace SPIRV {
56 
57 enum class VersionNumber : uint32_t {
58   // See section 2.3 of SPIR-V spec: Physical Layout of a SPIR_V Module and
59   // Instruction
60   SPIRV_1_0 = 0x00010000,
61   SPIRV_1_1 = 0x00010100,
62   SPIRV_1_2 = 0x00010200,
63   SPIRV_1_3 = 0x00010300,
64   SPIRV_1_4 = 0x00010400,
65   // TODO: populate this enum with the latest versions (up to 1.5) once
66   // translator get support of corresponding features
67   MinimumVersion = SPIRV_1_0,
68   MaximumVersion = SPIRV_1_4
69 };
70 
71 enum class ExtensionID : uint32_t {
72   First,
73 #define EXT(X) X,
74 #include "LLVMSPIRVExtensions.inc"
75 #undef EXT
76   Last,
77 };
78 
79 enum class BIsRepresentation : uint32_t { OpenCL12, OpenCL20, SPIRVFriendlyIR };
80 
81 enum class FPContractMode : uint32_t { On, Off, Fast };
82 
83 enum class DebugInfoEIS : uint32_t { SPIRV_Debug, OpenCL_DebugInfo_100 };
84 
85 /// \brief Helper class to manage SPIR-V translation
86 class TranslatorOpts {
87 public:
88   using ExtensionsStatusMap = std::map<ExtensionID, bool>;
89   using ArgList = llvm::SmallVector<llvm::StringRef, 4>;
90 
91   TranslatorOpts() = default;
92 
93   TranslatorOpts(VersionNumber Max, const ExtensionsStatusMap &Map = {})
MaxVersion(Max)94       : MaxVersion(Max), ExtStatusMap(Map) {}
95 
isAllowedToUseVersion(VersionNumber RequestedVersion)96   bool isAllowedToUseVersion(VersionNumber RequestedVersion) const {
97     return RequestedVersion <= MaxVersion;
98   }
99 
isAllowedToUseExtension(ExtensionID Extension)100   bool isAllowedToUseExtension(ExtensionID Extension) const {
101     auto I = ExtStatusMap.find(Extension);
102     if (ExtStatusMap.end() == I)
103       return false;
104 
105     return I->second;
106   }
107 
getMaxVersion()108   VersionNumber getMaxVersion() const { return MaxVersion; }
109 
isGenArgNameMDEnabled()110   bool isGenArgNameMDEnabled() const { return GenKernelArgNameMD; }
111 
isSPIRVMemToRegEnabled()112   bool isSPIRVMemToRegEnabled() const { return SPIRVMemToReg; }
113 
setMemToRegEnabled(bool Mem2Reg)114   void setMemToRegEnabled(bool Mem2Reg) { SPIRVMemToReg = Mem2Reg; }
115 
setGenKernelArgNameMDEnabled(bool ArgNameMD)116   void setGenKernelArgNameMDEnabled(bool ArgNameMD) {
117     GenKernelArgNameMD = ArgNameMD;
118   }
119 
enableAllExtensions()120   void enableAllExtensions() {
121 #define EXT(X) ExtStatusMap[ExtensionID::X] = true;
122 #include "LLVMSPIRVExtensions.inc"
123 #undef EXT
124   }
125 
enableGenArgNameMD()126   void enableGenArgNameMD() { GenKernelArgNameMD = true; }
127 
setSpecConst(uint32_t SpecId,uint64_t SpecValue)128   void setSpecConst(uint32_t SpecId, uint64_t SpecValue) {
129     ExternalSpecialization[SpecId] = SpecValue;
130   }
131 
getSpecializationConstant(uint32_t SpecId,uint64_t & Value)132   bool getSpecializationConstant(uint32_t SpecId, uint64_t &Value) const {
133     auto It = ExternalSpecialization.find(SpecId);
134     if (It == ExternalSpecialization.end())
135       return false;
136     Value = It->second;
137     return true;
138   }
139 
setDesiredBIsRepresentation(BIsRepresentation Value)140   void setDesiredBIsRepresentation(BIsRepresentation Value) {
141     DesiredRepresentationOfBIs = Value;
142   }
143 
getDesiredBIsRepresentation()144   BIsRepresentation getDesiredBIsRepresentation() const {
145     return DesiredRepresentationOfBIs;
146   }
147 
setFPContractMode(FPContractMode Mode)148   void setFPContractMode(FPContractMode Mode) { FPCMode = Mode; }
149 
getFPContractMode()150   FPContractMode getFPContractMode() const { return FPCMode; }
151 
152   bool isUnknownIntrinsicAllowed(llvm::IntrinsicInst *II) const noexcept;
153   bool isSPIRVAllowUnknownIntrinsicsEnabled() const noexcept;
154   void setSPIRVAllowUnknownIntrinsics(ArgList IntrinsicPrefixList) noexcept;
155 
allowExtraDIExpressions()156   bool allowExtraDIExpressions() const noexcept {
157     return AllowExtraDIExpressions;
158   }
159 
setAllowExtraDIExpressionsEnabled(bool Allow)160   void setAllowExtraDIExpressionsEnabled(bool Allow) noexcept {
161     AllowExtraDIExpressions = Allow;
162   }
163 
getDebugInfoEIS()164   DebugInfoEIS getDebugInfoEIS() const { return DebugInfoVersion; }
165 
setDebugInfoEIS(DebugInfoEIS EIS)166   void setDebugInfoEIS(DebugInfoEIS EIS) { DebugInfoVersion = EIS; }
167 
shouldReplaceLLVMFmulAddWithOpenCLMad()168   bool shouldReplaceLLVMFmulAddWithOpenCLMad() const noexcept {
169     return ReplaceLLVMFmulAddWithOpenCLMad;
170   }
171 
setReplaceLLVMFmulAddWithOpenCLMad(bool Value)172   void setReplaceLLVMFmulAddWithOpenCLMad(bool Value) noexcept {
173     ReplaceLLVMFmulAddWithOpenCLMad = Value;
174   }
175 
shouldPreserveOCLKernelArgTypeMetadataThroughString()176   bool shouldPreserveOCLKernelArgTypeMetadataThroughString() const noexcept {
177     return PreserveOCLKernelArgTypeMetadataThroughString;
178   }
179 
setPreserveOCLKernelArgTypeMetadataThroughString(bool Value)180   void setPreserveOCLKernelArgTypeMetadataThroughString(bool Value) noexcept {
181     PreserveOCLKernelArgTypeMetadataThroughString = Value;
182   }
183 
184 private:
185   // Common translation options
186   VersionNumber MaxVersion = VersionNumber::MaximumVersion;
187   ExtensionsStatusMap ExtStatusMap;
188   // SPIRVMemToReg option affects LLVM IR regularization phase
189   bool SPIRVMemToReg = false;
190   // SPIR-V to LLVM translation options
191   bool GenKernelArgNameMD = false;
192   std::unordered_map<uint32_t, uint64_t> ExternalSpecialization;
193   // Representation of built-ins, which should be used while translating from
194   // SPIR-V to back to LLVM IR
195   BIsRepresentation DesiredRepresentationOfBIs = BIsRepresentation::OpenCL12;
196   // Controls floating point contraction.
197   //
198   // - FPContractMode::On allows to choose a mode according to
199   //   presence of fused LLVM intrinsics
200   //
201   // - FPContractMode::Off disables contratction for all entry points
202   //
203   // - FPContractMode::Fast allows *all* operations to be contracted
204   //   for all entry points
205   FPContractMode FPCMode = FPContractMode::On;
206 
207   // Unknown LLVM intrinsics will be translated as external function calls in
208   // SPIR-V
209   llvm::Optional<ArgList> SPIRVAllowUnknownIntrinsics{};
210 
211   // Enable support for extra DIExpression opcodes not listed in the SPIR-V
212   // DebugInfo specification.
213   bool AllowExtraDIExpressions = false;
214 
215   DebugInfoEIS DebugInfoVersion = DebugInfoEIS::OpenCL_DebugInfo_100;
216 
217   // Controls whether llvm.fmuladd.* should be replaced with mad from OpenCL
218   // extended instruction set or with a simple fmul + fadd
219   bool ReplaceLLVMFmulAddWithOpenCLMad = true;
220 
221   // Add a workaround to preserve OpenCL kernel_arg_type and
222   // kernel_arg_type_qual metadata through OpString
223   bool PreserveOCLKernelArgTypeMetadataThroughString = false;
224 };
225 
226 } // namespace SPIRV
227 
228 #endif // SPIRV_LLVMSPIRVOPTS_H
229