Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "SPIRVBuiltins.h"
#include "SPIRV.h"
#include "SPIRVSubtarget.h"
#include "SPIRVUtils.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ValueTracking.h"
Expand Down Expand Up @@ -82,6 +83,16 @@ struct GroupBuiltin {
#define GET_GroupBuiltins_DECL
#define GET_GroupBuiltins_IMPL

struct IntelSubgroupsBuiltin {
StringRef Name;
uint32_t Opcode;
bool IsBlock;
bool IsWrite;
};

#define GET_IntelSubgroupsBuiltins_DECL
#define GET_IntelSubgroupsBuiltins_IMPL

struct GetBuiltin {
StringRef Name;
InstructionSet::InstructionSet Set;
Expand Down Expand Up @@ -549,6 +560,7 @@ static bool buildAtomicCompareExchangeInst(const SPIRV::IncomingCall *Call,
assert(GR->getSPIRVTypeForVReg(ObjectPtr)->getOpcode() ==
SPIRV::OpTypePointer);
unsigned ExpectedType = GR->getSPIRVTypeForVReg(ExpectedArg)->getOpcode();
(void)ExpectedType;
assert(IsCmpxchg ? ExpectedType == SPIRV::OpTypeInt
: ExpectedType == SPIRV::OpTypePointer);
assert(GR->isScalarOfType(Desired, SPIRV::OpTypeInt));
Expand Down Expand Up @@ -849,6 +861,7 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call,
if (GroupBuiltin->HasBoolArg) {
Register ConstRegister = Call->Arguments[0];
auto ArgInstruction = getDefInstrMaybeConstant(ConstRegister, MRI);
(void)ArgInstruction;
// TODO: support non-constant bool values.
assert(ArgInstruction->getOpcode() == TargetOpcode::G_CONSTANT &&
"Only constant bool value args are supported");
Expand Down Expand Up @@ -900,6 +913,67 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call,
return true;
}

static bool generateIntelSubgroupsInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
MachineFunction &MF = MIRBuilder.getMF();
const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
std::string DiagMsg = std::string(Builtin->Name) +
": the builtin requires the following SPIR-V "
"extension: SPV_INTEL_subgroups";
report_fatal_error(DiagMsg.c_str(), false);
}
const SPIRV::IntelSubgroupsBuiltin *IntelSubgroups =
SPIRV::lookupIntelSubgroupsBuiltin(Builtin->Name);
MachineRegisterInfo *MRI = MIRBuilder.getMRI();

uint32_t OpCode = IntelSubgroups->Opcode;
if (IntelSubgroups->IsBlock) {
// Minimal number or arguments set in TableGen records is 1
if (SPIRVType *Arg0Type = GR->getSPIRVTypeForVReg(Call->Arguments[0])) {
if (Arg0Type->getOpcode() == SPIRV::OpTypeImage) {
// TODO: add required validation from the specification:
// "'Image' must be an object whose type is OpTypeImage with a 'Sampled'
// operand of 0 or 2. If the 'Sampled' operand is 2, then some
// dimensions require a capability."
switch (OpCode) {
case SPIRV::OpSubgroupBlockReadINTEL:
OpCode = SPIRV::OpSubgroupImageBlockReadINTEL;
break;
case SPIRV::OpSubgroupBlockWriteINTEL:
OpCode = SPIRV::OpSubgroupImageBlockWriteINTEL;
break;
}
}
}
}

// TODO: opaque pointers types should be eventually resolved in such a way
// that validation of block read is enabled with respect to the following
// specification requirement:
// "'Result Type' may be a scalar or vector type, and its component type must
// be equal to the type pointed to by 'Ptr'."
// For example, function parameter type should not be default i8 pointer, but
// depend on the result type of the instruction where it is used as a pointer
// argument of OpSubgroupBlockReadINTEL

// Build Intel subgroups instruction
MachineInstrBuilder MIB =
IntelSubgroups->IsWrite
? MIRBuilder.buildInstr(OpCode)
: MIRBuilder.buildInstr(OpCode)
.addDef(Call->ReturnRegister)
.addUse(GR->getSPIRVTypeID(Call->ReturnType));
for (size_t i = 0; i < Call->Arguments.size(); ++i) {
MIB.addUse(Call->Arguments[i]);
MRI->setRegClass(Call->Arguments[i], &SPIRV::IDRegClass);
}

return true;
}

// These queries ask for a single size_t result for a given dimension index, e.g
// size_t get_global_id(uint dimindex). In SPIR-V, the builtins corresonding to
// these values are all vec3 types, so we need to extract the correct index or
Expand Down Expand Up @@ -1199,6 +1273,7 @@ static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call,
MIRBuilder.getMRI()->setRegClass(Image, &SPIRV::IDRegClass);
SPIRV::Dim::Dim ImageDimensionality = static_cast<SPIRV::Dim::Dim>(
GR->getSPIRVTypeForVReg(Image)->getOperand(2).getImm());
(void)ImageDimensionality;

switch (Opcode) {
case SPIRV::OpImageQuerySamples:
Expand Down Expand Up @@ -1976,6 +2051,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
return generateVectorLoadStoreInst(Call.get(), MIRBuilder, GR);
case SPIRV::LoadStore:
return generateLoadStoreInst(Call.get(), MIRBuilder, GR);
case SPIRV::IntelSubgroups:
return generateIntelSubgroupsInst(Call.get(), MIRBuilder, GR);
}
return false;
}
Expand Down Expand Up @@ -2119,6 +2196,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
for (unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) {
unsigned IntParameter = 0;
bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter);
(void)ValidLiteral;
assert(ValidLiteral &&
"Invalid format of SPIR-V builtin parameter literal!");
IntParameters.push_back(IntParameter);
Expand Down
58 changes: 57 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVBuiltins.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def Enqueue : BuiltinGroup;
def AsyncCopy : BuiltinGroup;
def VectorLoadStore : BuiltinGroup;
def LoadStore : BuiltinGroup;
def IntelSubgroups : BuiltinGroup;

//===----------------------------------------------------------------------===//
// Class defining a demangled builtin record. The information in the record
Expand Down Expand Up @@ -625,7 +626,7 @@ def GroupBuiltins : GenericTable {
"IsBallotFindBit", "IsLogical", "NoGroupOperation", "HasBoolArg"];
}

// Function to lookup native builtins by their name and set.
// Function to lookup group builtins by their name and set.
def lookupGroupBuiltin : SearchIndex {
let Table = GroupBuiltins;
let Key = ["Name"];
Expand Down Expand Up @@ -871,6 +872,61 @@ defm : DemangledGroupBuiltin<"group_non_uniform_scan_inclusive_logical_xors", Wo
defm : DemangledGroupBuiltin<"group_non_uniform_scan_exclusive_logical_xors", WorkOrSub, OpGroupNonUniformLogicalXor>;
defm : DemangledGroupBuiltin<"group_clustered_reduce_logical_xor", WorkOrSub, OpGroupNonUniformLogicalXor>;

//===----------------------------------------------------------------------===//
// Class defining a sub group builtin that should be translated into a
// SPIR-V instruction using the SPV_INTEL_subgroups extension.
//
// name is the demangled name of the given builtin.
// opcode specifies the SPIR-V operation code of the generated instruction.
//===----------------------------------------------------------------------===//
class IntelSubgroupsBuiltin<string name, Op operation> {
string Name = name;
Op Opcode = operation;
bit IsBlock = !or(!eq(operation, OpSubgroupBlockReadINTEL),
!eq(operation, OpSubgroupBlockWriteINTEL));
bit IsWrite = !eq(operation, OpSubgroupBlockWriteINTEL);
}

// Table gathering all the Intel sub group builtins.
def IntelSubgroupsBuiltins : GenericTable {
let FilterClass = "IntelSubgroupsBuiltin";
let Fields = ["Name", "Opcode", "IsBlock", "IsWrite"];
}

// Function to lookup group builtins by their name and set.
def lookupIntelSubgroupsBuiltin : SearchIndex {
let Table = IntelSubgroupsBuiltins;
let Key = ["Name"];
}

// Multiclass used to define incoming builtin records for the SPV_INTEL_subgroups extension
// and corresponding work/sub group builtin records.
multiclass DemangledIntelSubgroupsBuiltin<string name, bits<8> minNumArgs, bits<8> maxNumArgs, Op operation> {
def : DemangledBuiltin<!strconcat("intel_sub_group_", name), OpenCL_std, IntelSubgroups, minNumArgs, maxNumArgs>;
def : IntelSubgroupsBuiltin<!strconcat("intel_sub_group_", name), operation>;
}

// cl_intel_subgroups
defm : DemangledIntelSubgroupsBuiltin<"shuffle", 2, 2, OpSubgroupShuffleINTEL>;
defm : DemangledIntelSubgroupsBuiltin<"shuffle_down", 3, 3, OpSubgroupShuffleDownINTEL>;
defm : DemangledIntelSubgroupsBuiltin<"shuffle_up", 3, 3, OpSubgroupShuffleUpINTEL>;
defm : DemangledIntelSubgroupsBuiltin<"shuffle_xor", 2, 2, OpSubgroupShuffleXorINTEL>;
foreach i = ["", "2", "4", "8"] in {
// cl_intel_subgroups
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_read", i), 1, 2, OpSubgroupBlockReadINTEL>;
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_write", i), 2, 3, OpSubgroupBlockWriteINTEL>;
// cl_intel_subgroups_short
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_read_ui", i), 1, 2, OpSubgroupBlockReadINTEL>;
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_write_ui", i), 2, 3, OpSubgroupBlockWriteINTEL>;
}
// cl_intel_subgroups_char, cl_intel_subgroups_short, cl_intel_subgroups_long
foreach i = ["", "2", "4", "8", "16"] in {
foreach j = ["c", "s", "l"] in {
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_read_u", j, i), 1, 2, OpSubgroupBlockReadINTEL>;
defm : DemangledIntelSubgroupsBuiltin<!strconcat("block_write_u", j, i), 2, 3, OpSubgroupBlockWriteINTEL>;
}
}
// OpSubgroupImageBlockReadINTEL and OpSubgroupImageBlockWriteINTEL are to be resolved later on (in code)

//===----------------------------------------------------------------------===//
// Class defining a get builtin record used for lowering builtin calls such as
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -761,3 +761,21 @@ def OpGroupNonUniformBitwiseXor: OpGroupNUGroup<"BitwiseXor", 361>;
def OpGroupNonUniformLogicalAnd: OpGroupNUGroup<"LogicalAnd", 362>;
def OpGroupNonUniformLogicalOr: OpGroupNUGroup<"LogicalOr", 363>;
def OpGroupNonUniformLogicalXor: OpGroupNUGroup<"LogicalXor", 364>;

// 3.49.21. Group and Subgroup Instructions
def OpSubgroupShuffleINTEL: Op<5571, (outs ID:$res), (ins TYPE:$type, ID:$data, ID:$invocationId),
"$res = OpSubgroupShuffleINTEL $type $data $invocationId">;
def OpSubgroupShuffleDownINTEL: Op<5572, (outs ID:$res), (ins TYPE:$type, ID:$current, ID:$next, ID:$delta),
"$res = OpSubgroupShuffleDownINTEL $type $current $next $delta">;
def OpSubgroupShuffleUpINTEL: Op<5573, (outs ID:$res), (ins TYPE:$type, ID:$previous, ID:$current, ID:$delta),
"$res = OpSubgroupShuffleUpINTEL $type $previous $current $delta">;
def OpSubgroupShuffleXorINTEL: Op<5574, (outs ID:$res), (ins TYPE:$type, ID:$data, ID:$value),
"$res = OpSubgroupShuffleXorINTEL $type $data $value">;
def OpSubgroupBlockReadINTEL: Op<5575, (outs ID:$res), (ins TYPE:$type, ID:$ptr),
"$res = OpSubgroupBlockReadINTEL $type $ptr">;
def OpSubgroupBlockWriteINTEL: Op<5576, (outs), (ins ID:$ptr, ID:$data),
"OpSubgroupBlockWriteINTEL $ptr $data">;
def OpSubgroupImageBlockReadINTEL: Op<5577, (outs ID:$res), (ins TYPE:$type, ID:$image, ID:$coordinate),
"$res = OpSubgroupImageBlockReadINTEL $type $image $coordinate">;
def OpSubgroupImageBlockWriteINTEL: Op<5578, (outs), (ins ID:$image, ID:$coordinate, ID:$data),
"OpSubgroupImageBlockWriteINTEL $image $coordinate $data">;
23 changes: 23 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,29 @@ void addInstrRequirements(const MachineInstr &MI,
case SPIRV::OpGroupNonUniformBallotFindMSB:
Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
break;
case SPIRV::OpSubgroupShuffleINTEL:
case SPIRV::OpSubgroupShuffleDownINTEL:
case SPIRV::OpSubgroupShuffleUpINTEL:
case SPIRV::OpSubgroupShuffleXorINTEL:
if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
}
break;
case SPIRV::OpSubgroupBlockReadINTEL:
case SPIRV::OpSubgroupBlockWriteINTEL:
if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
}
break;
case SPIRV::OpSubgroupImageBlockReadINTEL:
case SPIRV::OpSubgroupImageBlockWriteINTEL:
if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
}
break;
case SPIRV::OpAssumeTrueKHR:
case SPIRV::OpExpectKHR:
if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ cl::list<SPIRV::Extension::Extension> Extensions(
clEnumValN(SPIRV::Extension::SPV_INTEL_optnone, "SPV_INTEL_optnone",
"Adds OptNoneINTEL value for Function Control mask that "
"indicates a request to not optimize the function"),
clEnumValN(SPIRV::Extension::SPV_INTEL_subgroups, "SPV_INTEL_subgroups",
"Allows work items in a subgroup to share data without the "
"use of local memory and work group barriers, and to "
"utilize specialized hardware to load and store blocks of "
"data from images or buffers."),
clEnumValN(SPIRV::Extension::SPV_KHR_no_integer_wrap_decoration,
"SPV_KHR_no_integer_wrap_decoration",
"Adds decorations to indicate that a given instruction does "
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,9 @@ defm InputAttachmentArrayNonUniformIndexingEXT : CapabilityOperand<5310, 0, 0, [
defm UniformTexelBufferArrayNonUniformIndexingEXT : CapabilityOperand<5311, 0, 0, [], [SampledBuffer, ShaderNonUniformEXT]>;
defm StorageTexelBufferArrayNonUniformIndexingEXT : CapabilityOperand<5312, 0, 0, [], [ImageBuffer, ShaderNonUniformEXT]>;
defm RayTracingNV : CapabilityOperand<5340, 0, 0, [], [Shader]>;
defm SubgroupShuffleINTEL : CapabilityOperand<5568, 0, 0, [], []>;
defm SubgroupBufferBlockIOINTEL : CapabilityOperand<5569, 0, 0, [], []>;
defm SubgroupImageBlockIOINTEL : CapabilityOperand<5570, 0, 0, [], []>;
defm SubgroupShuffleINTEL : CapabilityOperand<5568, 0, 0, [SPV_INTEL_subgroups], []>;
defm SubgroupBufferBlockIOINTEL : CapabilityOperand<5569, 0, 0, [SPV_INTEL_subgroups], []>;
defm SubgroupImageBlockIOINTEL : CapabilityOperand<5570, 0, 0, [SPV_INTEL_subgroups], []>;
defm SubgroupImageMediaBlockIOINTEL : CapabilityOperand<5579, 0, 0, [], []>;
defm SubgroupAvcMotionEstimationINTEL : CapabilityOperand<5696, 0, 0, [], []>;
defm SubgroupAvcMotionEstimationIntraINTEL : CapabilityOperand<5697, 0, 0, [], []>;
Expand Down
Loading