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