Steven Perron 0fb1057e40
[SPIRV] Filter disallowed extensions for env (#150051)
Not all SPIR-V extensions are allows in every environment. When we use
the `-spirv-ext=all` option, the backend currently believes that all
extensions can be used.

This commit filters out the extensions on the command line to remove
those that are not known to be allowed for the current environment.

Alternatives considered: I considered modifying the
SPIRVExtensionsParser::parse to use a different list of extensions for
"all" depending on the target triple. However that does not work because
the target triple is not available, and cannot be made available in a
reasonable way.

Fixes #147717

---------

Co-authored-by: Victor Lomuller <victor@codeplay.com>
2025-08-18 18:33:58 +00:00

266 lines
8.6 KiB
C++

//===-- SPIRVBaseInfo.cpp - Top level SPIRV definitions ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation for helper mnemonic lookup functions,
// versioning/capabilities/extensions getters for symbolic/named operands used
// in various SPIR-V instructions.
//
//===----------------------------------------------------------------------===//
#include "SPIRVBaseInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
namespace SPIRV {
struct SymbolicOperand {
OperandCategory::OperandCategory Category;
uint32_t Value;
StringRef Mnemonic;
uint32_t MinVersion;
uint32_t MaxVersion;
};
struct ExtensionEntry {
OperandCategory::OperandCategory Category;
uint32_t Value;
Extension::Extension ReqExtension;
};
struct CapabilityEntry {
OperandCategory::OperandCategory Category;
uint32_t Value;
Capability::Capability ReqCapability;
};
struct EnvironmentEntry {
OperandCategory::OperandCategory Category;
uint32_t Value;
Environment::Environment AllowedEnvironment;
};
using namespace OperandCategory;
using namespace Extension;
using namespace Environment;
using namespace Capability;
using namespace InstructionSet;
#define GET_SymbolicOperands_DECL
#define GET_SymbolicOperands_IMPL
#define GET_ExtensionEntries_DECL
#define GET_ExtensionEntries_IMPL
#define GET_CapabilityEntries_DECL
#define GET_CapabilityEntries_IMPL
#define GET_EnvironmentEntries_DECL
#define GET_EnvironmentEntries_IMPL
#define GET_ExtendedBuiltins_DECL
#define GET_ExtendedBuiltins_IMPL
#include "SPIRVGenTables.inc"
} // namespace SPIRV
std::string
getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category,
int32_t Value) {
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
// Value that encodes just one enum value.
if (Lookup)
return Lookup->Mnemonic.str();
if (Category != SPIRV::OperandCategory::ImageOperandOperand &&
Category != SPIRV::OperandCategory::FPFastMathModeOperand &&
Category != SPIRV::OperandCategory::SelectionControlOperand &&
Category != SPIRV::OperandCategory::LoopControlOperand &&
Category != SPIRV::OperandCategory::FunctionControlOperand &&
Category != SPIRV::OperandCategory::MemorySemanticsOperand &&
Category != SPIRV::OperandCategory::MemoryOperandOperand &&
Category != SPIRV::OperandCategory::KernelProfilingInfoOperand &&
Category != SPIRV::OperandCategory::SpecConstantOpOperandsOperand)
return "UNKNOWN";
// Value that encodes many enum values (one bit per enum value).
std::string Name;
std::string Separator;
const SPIRV::SymbolicOperand *EnumValueInCategory =
SPIRV::lookupSymbolicOperandByCategory(Category);
auto TableEnd = ArrayRef(SPIRV::SymbolicOperands).end();
while (EnumValueInCategory && EnumValueInCategory->Category == Category) {
if ((EnumValueInCategory->Value != 0) &&
(Value & EnumValueInCategory->Value)) {
Name += Separator + EnumValueInCategory->Mnemonic.str();
Separator = "|";
}
if (++EnumValueInCategory == TableEnd)
break;
}
return Name;
}
VersionTuple
getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category,
uint32_t Value) {
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
if (Lookup)
return VersionTuple(Lookup->MinVersion / 10, Lookup->MinVersion % 10);
return VersionTuple(0);
}
VersionTuple
getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category,
uint32_t Value) {
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
if (Lookup)
return VersionTuple(Lookup->MaxVersion / 10, Lookup->MaxVersion % 10);
return VersionTuple();
}
CapabilityList
getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category,
uint32_t Value) {
CapabilityList Capabilities;
const SPIRV::CapabilityEntry *Capability =
SPIRV::lookupCapabilityByCategoryAndValue(Category, Value);
auto TableEnd = ArrayRef(SPIRV::CapabilityEntries).end();
while (Capability && Capability->Category == Category &&
Capability->Value == Value) {
Capabilities.push_back(
static_cast<SPIRV::Capability::Capability>(Capability->ReqCapability));
if (++Capability == TableEnd)
break;
}
return Capabilities;
}
EnvironmentList getSymbolicOperandAllowedEnvironments(
SPIRV::OperandCategory::OperandCategory Category, uint32_t Value) {
EnvironmentList Environments;
const SPIRV::EnvironmentEntry *Environment =
SPIRV::lookupEnvironmentByCategoryAndValue(Category, Value);
auto TableEnd = ArrayRef(SPIRV::EnvironmentEntries).end();
while (Environment && Environment->Category == Category &&
Environment->Value == Value) {
Environments.push_back(static_cast<SPIRV::Environment::Environment>(
Environment->AllowedEnvironment));
if (++Environment == TableEnd)
break;
}
return Environments;
}
CapabilityList
getCapabilitiesEnabledByExtension(SPIRV::Extension::Extension Extension) {
const SPIRV::ExtensionEntry *Entry =
SPIRV::lookupSymbolicOperandsEnabledByExtension(
Extension, SPIRV::OperandCategory::CapabilityOperand);
CapabilityList Capabilities;
auto TableEnd = ArrayRef(SPIRV::ExtensionEntries).end();
while (Entry &&
Entry->Category == SPIRV::OperandCategory::CapabilityOperand) {
// Some capabilities' codes might go not in order.
if (Entry->ReqExtension == Extension)
Capabilities.push_back(
static_cast<SPIRV::Capability::Capability>(Entry->Value));
if (++Entry == TableEnd)
break;
}
return Capabilities;
}
ExtensionList
getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category,
uint32_t Value) {
const SPIRV::ExtensionEntry *Extension =
SPIRV::lookupExtensionByCategoryAndValue(Category, Value);
ExtensionList Extensions;
auto TableEnd = ArrayRef(SPIRV::ExtensionEntries).end();
while (Extension && Extension->Category == Category &&
Extension->Value == Value) {
Extensions.push_back(
static_cast<SPIRV::Extension::Extension>(Extension->ReqExtension));
if (++Extension == TableEnd)
break;
}
return Extensions;
}
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue) {
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndValue(
SPIRV::OperandCategory::BuiltInOperand, BuiltInValue);
if (Lookup)
return "__spirv_BuiltIn" + Lookup->Mnemonic.str();
return "UNKNOWN_BUILTIN";
}
bool getSpirvBuiltInIdByName(llvm::StringRef Name,
SPIRV::BuiltIn::BuiltIn &BI) {
const std::string Prefix = "__spirv_BuiltIn";
if (!Name.starts_with(Prefix))
return false;
const SPIRV::SymbolicOperand *Lookup =
SPIRV::lookupSymbolicOperandByCategoryAndMnemonic(
SPIRV::OperandCategory::BuiltInOperand,
Name.drop_front(Prefix.length()));
if (!Lookup)
return false;
BI = static_cast<SPIRV::BuiltIn::BuiltIn>(Lookup->Value);
return true;
}
std::string getExtInstSetName(SPIRV::InstructionSet::InstructionSet Set) {
switch (Set) {
case SPIRV::InstructionSet::OpenCL_std:
return "OpenCL.std";
case SPIRV::InstructionSet::GLSL_std_450:
return "GLSL.std.450";
case SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100:
return "NonSemantic.Shader.DebugInfo.100";
case SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax:
return "SPV_AMD_shader_trinary_minmax";
}
return "UNKNOWN_EXT_INST_SET";
}
SPIRV::InstructionSet::InstructionSet
getExtInstSetFromString(std::string SetName) {
for (auto Set :
{SPIRV::InstructionSet::GLSL_std_450, SPIRV::InstructionSet::OpenCL_std,
SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100}) {
if (SetName == getExtInstSetName(Set))
return Set;
}
llvm_unreachable("UNKNOWN_EXT_INST_SET");
}
std::string getExtInstName(SPIRV::InstructionSet::InstructionSet Set,
uint32_t InstructionNumber) {
const SPIRV::ExtendedBuiltin *Lookup =
SPIRV::lookupExtendedBuiltinBySetAndNumber(Set, InstructionNumber);
if (!Lookup)
return "UNKNOWN_EXT_INST";
return Lookup->Name.str();
}
} // namespace llvm