|
13 | 13 |
|
14 | 14 | #include "SPIRVBuiltins.h" |
15 | 15 | #include "SPIRV.h" |
| 16 | +#include "SPIRVSubtarget.h" |
16 | 17 | #include "SPIRVUtils.h" |
17 | 18 | #include "llvm/ADT/StringExtras.h" |
18 | 19 | #include "llvm/Analysis/ValueTracking.h" |
@@ -82,6 +83,16 @@ struct GroupBuiltin { |
82 | 83 | #define GET_GroupBuiltins_DECL |
83 | 84 | #define GET_GroupBuiltins_IMPL |
84 | 85 |
|
| 86 | +struct IntelSubgroupsBuiltin { |
| 87 | + StringRef Name; |
| 88 | + uint32_t Opcode; |
| 89 | + bool IsBlock; |
| 90 | + bool IsWrite; |
| 91 | +}; |
| 92 | + |
| 93 | +#define GET_IntelSubgroupsBuiltins_DECL |
| 94 | +#define GET_IntelSubgroupsBuiltins_IMPL |
| 95 | + |
85 | 96 | struct GetBuiltin { |
86 | 97 | StringRef Name; |
87 | 98 | InstructionSet::InstructionSet Set; |
@@ -549,6 +560,7 @@ static bool buildAtomicCompareExchangeInst(const SPIRV::IncomingCall *Call, |
549 | 560 | assert(GR->getSPIRVTypeForVReg(ObjectPtr)->getOpcode() == |
550 | 561 | SPIRV::OpTypePointer); |
551 | 562 | unsigned ExpectedType = GR->getSPIRVTypeForVReg(ExpectedArg)->getOpcode(); |
| 563 | + (void)ExpectedType; |
552 | 564 | assert(IsCmpxchg ? ExpectedType == SPIRV::OpTypeInt |
553 | 565 | : ExpectedType == SPIRV::OpTypePointer); |
554 | 566 | assert(GR->isScalarOfType(Desired, SPIRV::OpTypeInt)); |
@@ -849,6 +861,7 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call, |
849 | 861 | if (GroupBuiltin->HasBoolArg) { |
850 | 862 | Register ConstRegister = Call->Arguments[0]; |
851 | 863 | auto ArgInstruction = getDefInstrMaybeConstant(ConstRegister, MRI); |
| 864 | + (void)ArgInstruction; |
852 | 865 | // TODO: support non-constant bool values. |
853 | 866 | assert(ArgInstruction->getOpcode() == TargetOpcode::G_CONSTANT && |
854 | 867 | "Only constant bool value args are supported"); |
@@ -900,6 +913,67 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call, |
900 | 913 | return true; |
901 | 914 | } |
902 | 915 |
|
| 916 | +static bool generateIntelSubgroupsInst(const SPIRV::IncomingCall *Call, |
| 917 | + MachineIRBuilder &MIRBuilder, |
| 918 | + SPIRVGlobalRegistry *GR) { |
| 919 | + const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; |
| 920 | + MachineFunction &MF = MIRBuilder.getMF(); |
| 921 | + const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); |
| 922 | + if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) { |
| 923 | + std::string DiagMsg = std::string(Builtin->Name) + |
| 924 | + ": the builtin requires the following SPIR-V " |
| 925 | + "extension: SPV_INTEL_subgroups"; |
| 926 | + report_fatal_error(DiagMsg.c_str(), false); |
| 927 | + } |
| 928 | + const SPIRV::IntelSubgroupsBuiltin *IntelSubgroups = |
| 929 | + SPIRV::lookupIntelSubgroupsBuiltin(Builtin->Name); |
| 930 | + MachineRegisterInfo *MRI = MIRBuilder.getMRI(); |
| 931 | + |
| 932 | + uint32_t OpCode = IntelSubgroups->Opcode; |
| 933 | + if (IntelSubgroups->IsBlock) { |
| 934 | + // Minimal number or arguments set in TableGen records is 1 |
| 935 | + if (SPIRVType *Arg0Type = GR->getSPIRVTypeForVReg(Call->Arguments[0])) { |
| 936 | + if (Arg0Type->getOpcode() == SPIRV::OpTypeImage) { |
| 937 | + // TODO: add required validation from the specification: |
| 938 | + // "'Image' must be an object whose type is OpTypeImage with a 'Sampled' |
| 939 | + // operand of 0 or 2. If the 'Sampled' operand is 2, then some |
| 940 | + // dimensions require a capability." |
| 941 | + switch (OpCode) { |
| 942 | + case SPIRV::OpSubgroupBlockReadINTEL: |
| 943 | + OpCode = SPIRV::OpSubgroupImageBlockReadINTEL; |
| 944 | + break; |
| 945 | + case SPIRV::OpSubgroupBlockWriteINTEL: |
| 946 | + OpCode = SPIRV::OpSubgroupImageBlockWriteINTEL; |
| 947 | + break; |
| 948 | + } |
| 949 | + } |
| 950 | + } |
| 951 | + } |
| 952 | + |
| 953 | + // TODO: opaque pointers types should be eventually resolved in such a way |
| 954 | + // that validation of block read is enabled with respect to the following |
| 955 | + // specification requirement: |
| 956 | + // "'Result Type' may be a scalar or vector type, and its component type must |
| 957 | + // be equal to the type pointed to by 'Ptr'." |
| 958 | + // For example, function parameter type should not be default i8 pointer, but |
| 959 | + // depend on the result type of the instruction where it is used as a pointer |
| 960 | + // argument of OpSubgroupBlockReadINTEL |
| 961 | + |
| 962 | + // Build Intel subgroups instruction |
| 963 | + MachineInstrBuilder MIB = |
| 964 | + IntelSubgroups->IsWrite |
| 965 | + ? MIRBuilder.buildInstr(OpCode) |
| 966 | + : MIRBuilder.buildInstr(OpCode) |
| 967 | + .addDef(Call->ReturnRegister) |
| 968 | + .addUse(GR->getSPIRVTypeID(Call->ReturnType)); |
| 969 | + for (size_t i = 0; i < Call->Arguments.size(); ++i) { |
| 970 | + MIB.addUse(Call->Arguments[i]); |
| 971 | + MRI->setRegClass(Call->Arguments[i], &SPIRV::IDRegClass); |
| 972 | + } |
| 973 | + |
| 974 | + return true; |
| 975 | +} |
| 976 | + |
903 | 977 | // These queries ask for a single size_t result for a given dimension index, e.g |
904 | 978 | // size_t get_global_id(uint dimindex). In SPIR-V, the builtins corresonding to |
905 | 979 | // these values are all vec3 types, so we need to extract the correct index or |
@@ -1199,6 +1273,7 @@ static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call, |
1199 | 1273 | MIRBuilder.getMRI()->setRegClass(Image, &SPIRV::IDRegClass); |
1200 | 1274 | SPIRV::Dim::Dim ImageDimensionality = static_cast<SPIRV::Dim::Dim>( |
1201 | 1275 | GR->getSPIRVTypeForVReg(Image)->getOperand(2).getImm()); |
| 1276 | + (void)ImageDimensionality; |
1202 | 1277 |
|
1203 | 1278 | switch (Opcode) { |
1204 | 1279 | case SPIRV::OpImageQuerySamples: |
@@ -1976,6 +2051,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall, |
1976 | 2051 | return generateVectorLoadStoreInst(Call.get(), MIRBuilder, GR); |
1977 | 2052 | case SPIRV::LoadStore: |
1978 | 2053 | return generateLoadStoreInst(Call.get(), MIRBuilder, GR); |
| 2054 | + case SPIRV::IntelSubgroups: |
| 2055 | + return generateIntelSubgroupsInst(Call.get(), MIRBuilder, GR); |
1979 | 2056 | } |
1980 | 2057 | return false; |
1981 | 2058 | } |
@@ -2119,6 +2196,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName, |
2119 | 2196 | for (unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) { |
2120 | 2197 | unsigned IntParameter = 0; |
2121 | 2198 | bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter); |
| 2199 | + (void)ValidLiteral; |
2122 | 2200 | assert(ValidLiteral && |
2123 | 2201 | "Invalid format of SPIR-V builtin parameter literal!"); |
2124 | 2202 | IntParameters.push_back(IntParameter); |
|
0 commit comments