diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 3754f57ef3ac7..66deb6fe42fcb 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -15,6 +15,8 @@ //===----------------------------------------------------------------------===// #include "SPIRVModuleAnalysis.h" +#include "MCTargetDesc/SPIRVBaseInfo.h" +#include "MCTargetDesc/SPIRVMCTargetDesc.h" #include "SPIRV.h" #include "SPIRVSubtarget.h" #include "SPIRVTargetMachine.h" @@ -504,7 +506,7 @@ void SPIRV::RequirementHandler::checkSatisfiable( for (auto Ext : AllExtensions) { if (ST.canUseExtension(Ext)) continue; - LLVM_DEBUG(dbgs() << "Extension not suported: " + LLVM_DEBUG(dbgs() << "Extension not supported: " << getSymbolicOperandMnemonic( OperandCategory::ExtensionOperand, Ext) << "\n"); @@ -523,6 +525,13 @@ void SPIRV::RequirementHandler::addAvailableCaps(const CapabilityList &ToAdd) { SPIRV::OperandCategory::CapabilityOperand, Cap)); } +void SPIRV::RequirementHandler::removeCapabilityIf( + const Capability::Capability ToRemove, + const Capability::Capability IfPresent) { + if (AvailableCaps.contains(IfPresent)) + AvailableCaps.erase(ToRemove); +} + namespace llvm { namespace SPIRV { void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) { @@ -734,6 +743,16 @@ void addInstrRequirements(const MachineInstr &MI, break; } case SPIRV::OpBitReverse: + case SPIRV::OpBitFieldInsert: + case SPIRV::OpBitFieldSExtract: + case SPIRV::OpBitFieldUExtract: + if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) { + Reqs.addCapability(SPIRV::Capability::Shader); + break; + } + Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions); + Reqs.addCapability(SPIRV::Capability::BitInstructions); + break; case SPIRV::OpTypeRuntimeArray: Reqs.addCapability(SPIRV::Capability::Shader); break; @@ -887,6 +906,12 @@ void addInstrRequirements(const MachineInstr &MI, default: break; } + + // If we require capability Shader, then we can remove the requirement for + // the BitInstructions capability, since Shader is a superset capability + // of BitInstructions. + Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions, + SPIRV::Capability::Shader); } static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h index b57a5f4c28278..9eea9ac5bda5b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h @@ -113,6 +113,10 @@ struct RequirementHandler { bool isCapabilityAvailable(Capability::Capability Cap) const { return AvailableCaps.contains(Cap); } + + // Remove capability ToRemove, but only if IfPresent is present. + void removeCapabilityIf(const Capability::Capability ToRemove, + const Capability::Capability IfPresent); }; using InstrList = SmallVector; diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp index 1bad1d8109623..e4ad805f071b9 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "SPIRVSubtarget.h" +#include "MCTargetDesc/SPIRVBaseInfo.h" #include "SPIRV.h" #include "SPIRVGlobalRegistry.h" #include "SPIRVLegalizerInfo.h" @@ -40,7 +41,11 @@ cl::list Extensions( clEnumValN(SPIRV::Extension::SPV_KHR_no_integer_wrap_decoration, "SPV_KHR_no_integer_wrap_decoration", "Adds decorations to indicate that a given instruction does " - "not cause integer wrapping"))); + "not cause integer wrapping"), + clEnumValN(SPIRV::Extension::SPV_KHR_bit_instructions, + "SPV_KHR_bit_instructions", + "This enables bit instructions to be used by SPIR-V modules " + "without requiring the Shader capability"))); // Compare version numbers, but allow 0 to mean unspecified. static bool isAtLeastVer(uint32_t Target, uint32_t VerToCompareTo) { diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td index c27d2826c0159..ab06f5308700b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td @@ -450,6 +450,7 @@ defm PhysicalStorageBufferAddressesEXT : CapabilityOperand<5347, 0, 0, [], [Shad defm CooperativeMatrixNV : CapabilityOperand<5357, 0, 0, [], [Shader]>; defm ArbitraryPrecisionIntegersINTEL : CapabilityOperand<5844, 0, 0, [SPV_INTEL_arbitrary_precision_integers], [Int8, Int16]>; defm OptNoneINTEL : CapabilityOperand<6094, 0, 0, [SPV_INTEL_optnone], []>; +defm BitInstructions : CapabilityOperand<6025, 0, 0, [SPV_KHR_bit_instructions], []>; //===----------------------------------------------------------------------===// // Multiclass used to define SourceLanguage enum values and at the same time diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_bit_instructions.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_bit_instructions.ll new file mode 100644 index 0000000000000..95395d5efb55d --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_bit_instructions.ll @@ -0,0 +1,24 @@ +; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s --spirv-extensions=SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-EXTENSION +; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-NO-EXTENSION + +; CHECK-EXTENSION: OpCapability BitInstructions +; CHECK-EXTENSION-NEXT: OpExtension "SPV_KHR_bit_instructions" +; CHECK-EXTENSION-NOT: OpCabilitity Shader +; CHECK-NO-EXTENSION: OpCapability Shader +; CHECK-NO-EXTENSION-NOT: OpCabilitity BitInstructions +; CHECK-NO-EXTENSION-NOT: OpExtension "SPV_KHR_bit_instructions" + + +; CHECK-EXTENSION: %[[#int:]] = OpTypeInt 32 +; CHECK-EXTENSION: OpBitReverse %[[#int]] +; CHECK-NO-EXTENSION: %[[#int:]] = OpTypeInt 32 +; CHECK-NO-EXTENSION: OpBitReverse %[[#int]] + +define spir_kernel void @testBitRev(i32 %a, i32 %b, i32 %c, i32 addrspace(1)* nocapture %res) local_unnamed_addr { +entry: + %call = tail call i32 @llvm.bitreverse.i32(i32 %b) + store i32 %call, i32 addrspace(1)* %res, align 4 + ret void +} + +declare i32 @llvm.bitreverse.i32(i32)