diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h index 0c58c47d2a..950ca69981 100644 --- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -4604,5 +4604,60 @@ class SPIRVFmaKHRInstBase : public SPIRVInstTemplateBase { typedef SPIRVInstTemplate SPIRVFmaKHR; +class SPIRVTernaryBitwiseFunctionINTELInst : public SPIRVInstTemplateBase { +public: + void validate() const override { + SPIRVInstruction::validate(); + SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog(); + std::string InstName = "BitwiseFunctionINTEL"; + + const SPIRVType *ResTy = this->getType(); + SPVErrLog.checkError( + ResTy->isTypeInt() || (ResTy->isTypeVector() && + ResTy->getVectorComponentType()->isTypeInt()), + SPIRVEC_InvalidInstruction, + InstName + "\nResult type must be an integer scalar or vector.\n"); + + auto CommonArgCheck = [this, ResTy, &InstName, + &SPVErrLog](size_t ArgI, const char *ArgPlacement) { + SPIRVValue *Arg = + const_cast(this)->getOperand( + ArgI); + SPVErrLog.checkError( + Arg->getType() == ResTy, SPIRVEC_InvalidInstruction, + InstName + "\n" + ArgPlacement + + " argument must be the same as the result type.\n"); + }; + + CommonArgCheck(0, "First"); + CommonArgCheck(1, "Second"); + CommonArgCheck(2, "Third"); + + SPIRVValue *LUTIndexArg = + const_cast(this)->getOperand(3); + const SPIRVType *LUTIndexArgTy = LUTIndexArg->getType(); + SPVErrLog.checkError( + LUTIndexArgTy->isTypeInt(32), SPIRVEC_InvalidInstruction, + InstName + "\nFourth argument must be a 32-bit integer scalar.\n"); + SPVErrLog.checkError( + isConstantOpCode(LUTIndexArg->getOpCode()), SPIRVEC_InvalidInstruction, + InstName + "\nFourth argument must be constant instruction.\n"); + } + + std::optional getRequiredExtension() const override { + return ExtensionID::SPV_INTEL_ternary_bitwise_function; + } + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityTernaryBitwiseFunctionINTEL); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate \ + SPIRV##x##INTEL; +_SPIRV_OP(BitwiseFunction, true, 7) +#undef _SPIRV_OP + } // namespace SPIRV #endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index e808a4502d..f4cd55fe65 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -655,6 +655,7 @@ template <> inline void SPIRVMap::init() { add(CapabilitySubgroupMatrixMultiplyAccumulateINTEL, "SubgroupMatrixMultiplyAccumulateINTEL"); add(CapabilityFMAKHR, "FMAKHR"); + add(CapabilityTernaryBitwiseFunctionINTEL, "TernaryBitwiseFunctionINTEL"); // From spirv_internal.hpp add(internal::CapabilityTokenTypeINTEL, "TokenTypeINTEL"); add(internal::CapabilityJointMatrixINTEL, "JointMatrixINTEL"); diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h index 7f9d362c12..139de222c5 100644 --- a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -587,6 +587,7 @@ _SPIRV_OP(SpecConstantTargetINTEL, 6251) _SPIRV_OP(SpecConstantArchitectureINTEL, 6252) _SPIRV_OP(SpecConstantCapabilitiesINTEL, 6253) _SPIRV_OP(ConditionalCopyObjectINTEL, 6254) +_SPIRV_OP(BitwiseFunctionINTEL, 6242) _SPIRV_OP(GroupIMulKHR, 6401) _SPIRV_OP(GroupFMulKHR, 6402) _SPIRV_OP(GroupBitwiseAndKHR, 6403) diff --git a/test/extensions/INTEL/SPV_INTEL_ternary_bitwise_function/bitwise_function.ll b/test/extensions/INTEL/SPV_INTEL_ternary_bitwise_function/bitwise_function.ll new file mode 100644 index 0000000000..d5b087b370 --- /dev/null +++ b/test/extensions/INTEL/SPV_INTEL_ternary_bitwise_function/bitwise_function.ll @@ -0,0 +1,78 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_ternary_bitwise_function -o %t.spv +; RUN: llvm-spirv %t.spv --to-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +; CHECK-ERROR: RequiresExtension: Feature requires the following SPIR-V extension: +; CHECK-ERROR-NEXT: SPV_INTEL_ternary_bitwise_function + +; CHECK-SPIRV-NOT: Name [[#]] "_Z28__spirv_BitwiseFunctionINTELiiij" +; CHECK-SPIRV-NOT: Name [[#]] "_Z28__spirv_BitwiseFunctionINTELDv4_iS_S_j" + +; CHECK-SPIRV-DAG: Capability TernaryBitwiseFunctionINTEL +; CHECK-SPIRV-DAG: Extension "SPV_INTEL_ternary_bitwise_function" + +; CHECK-SPIRV-DAG: TypeInt [[#TYPEINT:]] 32 0 +; CHECK-SPIRV-DAG: TypeVector [[#TYPEINTVEC4:]] [[#TYPEINT]] 4 +; CHECK-SPIRV-DAG: Constant [[#TYPEINT]] [[#ScalarLUT:]] 24 +; CHECK-SPIRV-DAG: Constant [[#TYPEINT]] [[#VecLUT:]] 42 + +; CHECK-SPIRV: Load [[#TYPEINT]] [[#ScalarA:]] +; CHECK-SPIRV: Load [[#TYPEINT]] [[#ScalarB:]] +; CHECK-SPIRV: Load [[#TYPEINT]] [[#ScalarC:]] +; CHECK-SPIRV: BitwiseFunctionINTEL [[#TYPEINT]] {{.*}} [[#ScalarA]] [[#ScalarB]] [[#ScalarC]] [[#ScalarLUT]] +; CHECK-SPIRV: Load [[#TYPEINTVEC4]] [[#VecA:]] +; CHECK-SPIRV: Load [[#TYPEINTVEC4]] [[#VecB:]] +; CHECK-SPIRV: Load [[#TYPEINTVEC4]] [[#VecC:]] +; CHECK-SPIRV: BitwiseFunctionINTEL [[#TYPEINTVEC4]] {{.*}} [[#VecA]] [[#VecB]] [[#VecC]] [[#VecLUT]] + +; CHECK-LLVM: %[[ScalarA:.*]] = load i32, ptr +; CHECK-LLVM: %[[ScalarB:.*]] = load i32, ptr +; CHECK-LLVM: %[[ScalarC:.*]] = load i32, ptr +; CHECK-LLVM: call spir_func i32 @_Z28__spirv_BitwiseFunctionINTELiiii(i32 %[[ScalarA]], i32 %[[ScalarB]], i32 %[[ScalarC]], i32 24) +; CHECK-LLVM: %[[VecA:.*]] = load <4 x i32>, ptr +; CHECK-LLVM: %[[VecB:.*]] = load <4 x i32>, ptr +; CHECK-LLVM: %[[VecC:.*]] = load <4 x i32>, ptr +; CHECK-LLVM: call spir_func <4 x i32> @_Z28__spirv_BitwiseFunctionINTELDv4_iS_S_i(<4 x i32> %[[VecA]], <4 x i32> %[[VecB]], <4 x i32> %[[VecC]], i32 42) + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir" + +; Function Attrs: nounwind readnone +define spir_kernel void @fooScalar() { +entry: + %argA = alloca i32 + %argB = alloca i32 + %argC = alloca i32 + %A = load i32, ptr %argA + %B = load i32, ptr %argB + %C = load i32, ptr %argC + %res = call spir_func i32 @_Z28__spirv_BitwiseFunctionINTELiiii(i32 %A, i32 %B, i32 %C, i32 24) + ret void +} + +; Function Attrs: nounwind readnone +define spir_kernel void @fooVec() { +entry: + %argA = alloca <4 x i32> + %argB = alloca <4 x i32> + %argC = alloca <4 x i32> + %A = load <4 x i32>, ptr %argA + %B = load <4 x i32>, ptr %argB + %C = load <4 x i32>, ptr %argC + %res = call spir_func <4 x i32> @_Z28__spirv_BitwiseFunctionINTELDv4_iS_S_i(<4 x i32> %A, <4 x i32> %B, <4 x i32> %C, i32 42) + ret void +} + +declare dso_local spir_func i32 @_Z28__spirv_BitwiseFunctionINTELiiii(i32, i32, i32, i32) +declare dso_local spir_func <4 x i32> @_Z28__spirv_BitwiseFunctionINTELDv4_iS_S_i(<4 x i32>, <4 x i32>, <4 x i32>, i32) + +!llvm.module.flags = !{!0} +!opencl.spir.version = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, i32 2}