Skip to content

Commit

Permalink
[Backport to 15] Relax OpenCL extended instruction restrictions (Khro…
Browse files Browse the repository at this point in the history
…nosGroup#1755)

* [Backport to 15] Relax OpenCL extended instruction restrictions (KhronosGroup#1724)

When VectorAnyINTEL capability is enabled, OpenCL extended instructions
are able to work on vector types with any number of components greater
then or equal to 2.

* [Backport to 15] Translate LLVM intrinsics into native_* OpenCL instructions (KhronosGroup#1729)

When an intrinsic function is called with `afn` flag, it's allowed to
substitute an approximate calculations. So the translator can emit
native versions of OpenCL extended instructions.

Co-authored-by: Victor Mustya <[email protected]>
  • Loading branch information
stanleygambarin and vmustya authored Dec 8, 2022
1 parent 54b5801 commit 78ad93b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 25 deletions.
6 changes: 4 additions & 2 deletions lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1829,7 +1829,8 @@ bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM) {
Ty = VecTy->getElementType();
}
if ((!Ty->isFloatTy() && !Ty->isDoubleTy() && !Ty->isHalfTy()) ||
((NumElems > 4) && (NumElems != 8) && (NumElems != 16))) {
(!BM->hasCapability(CapabilityVectorAnyINTEL) &&
((NumElems > 4) && (NumElems != 8) && (NumElems != 16)))) {
BM->SPIRVCK(
false, InvalidFunctionCall, II->getCalledOperand()->getName().str());
return false;
Expand All @@ -1844,7 +1845,8 @@ bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM) {
Ty = VecTy->getElementType();
}
if ((!Ty->isIntegerTy()) ||
((NumElems > 4) && (NumElems != 8) && (NumElems != 16))) {
(!BM->hasCapability(CapabilityVectorAnyINTEL) &&
((NumElems > 4) && (NumElems != 8) && (NumElems != 16)))) {
BM->SPIRVCK(
false, InvalidFunctionCall, II->getCalledOperand()->getName().str());
}
Expand Down
77 changes: 55 additions & 22 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ void transAliasingMemAccess(SPIRVModule *BM, MDNode *AliasingListMD,
std::vector<uint32_t> &MemoryAccess,
SPIRVWord MemAccessMask) {
if (!BM->isAllowedToUseExtension(
ExtensionID::SPV_INTEL_memory_access_aliasing))
ExtensionID::SPV_INTEL_memory_access_aliasing))
return;
auto *MemAliasList = addMemAliasingINTELInstructions(BM, AliasingListMD);
if (!MemAliasList)
Expand Down Expand Up @@ -2543,20 +2543,17 @@ bool LLVMToSPIRVBase::transAlign(Value *V, SPIRVValue *BV) {
void LLVMToSPIRVBase::transMemAliasingINTELDecorations(Instruction *Inst,
SPIRVValue *BV) {
if (!BM->isAllowedToUseExtension(
ExtensionID::SPV_INTEL_memory_access_aliasing))
ExtensionID::SPV_INTEL_memory_access_aliasing))
return;
if (MDNode *AliasingListMD =
Inst->getMetadata(LLVMContext::MD_alias_scope)) {
auto *MemAliasList =
addMemAliasingINTELInstructions(BM, AliasingListMD);
if (MDNode *AliasingListMD = Inst->getMetadata(LLVMContext::MD_alias_scope)) {
auto *MemAliasList = addMemAliasingINTELInstructions(BM, AliasingListMD);
if (!MemAliasList)
return;
BV->addDecorate(new SPIRVDecorateId(DecorationAliasScopeINTEL, BV,
MemAliasList->getId()));
}
if (MDNode *AliasingListMD = Inst->getMetadata(LLVMContext::MD_noalias)) {
auto *MemAliasList =
addMemAliasingINTELInstructions(BM, AliasingListMD);
auto *MemAliasList = addMemAliasingINTELInstructions(BM, AliasingListMD);
if (!MemAliasList)
return;
BV->addDecorate(
Expand Down Expand Up @@ -3318,6 +3315,38 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) {
}
}

static SPIRVWord getNativeBuiltinIdForIntrinsic(Intrinsic::ID IID) {
switch (IID) {
case Intrinsic::cos:
return OpenCLLIB::Native_cos;
case Intrinsic::exp:
return OpenCLLIB::Native_exp;
case Intrinsic::exp2:
return OpenCLLIB::Native_exp2;
case Intrinsic::log:
return OpenCLLIB::Native_log;
case Intrinsic::log10:
return OpenCLLIB::Native_log10;
case Intrinsic::log2:
return OpenCLLIB::Native_log2;
case Intrinsic::sin:
return OpenCLLIB::Native_sin;
case Intrinsic::sqrt:
return OpenCLLIB::Native_sqrt;
default:
return getBuiltinIdForIntrinsic(IID);
}
}

static bool allowsApproxFunction(IntrinsicInst *II) {
auto *Ty = II->getType();
// OpenCL native_* built-ins only support single precision data type
return II->hasApproxFunc() &&
(Ty->isFloatTy() ||
(Ty->isVectorTy() &&
cast<VectorType>(Ty)->getElementType()->isFloatTy()));
}

SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
SPIRVBasicBlock *BB) {
auto GetMemoryAccess = [](MemIntrinsic *MI) -> std::vector<SPIRVWord> {
Expand All @@ -3342,7 +3371,8 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
// LLVM intrinsics with known translation to SPIR-V are handled here. They
// also must be registered at isKnownIntrinsic function in order to make
// -spirv-allow-unknown-intrinsics work correctly.
switch (II->getIntrinsicID()) {
auto IID = II->getIntrinsicID();
switch (IID) {
case Intrinsic::assume: {
// llvm.assume translation is currently supported only within
// SPV_KHR_expect_assume extension, ignore it otherwise, since it's
Expand Down Expand Up @@ -3379,7 +3409,9 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
case Intrinsic::trunc: {
if (!checkTypeForSPIRVExtendedInstLowering(II, BM))
break;
SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID());
const SPIRVWord ExtOp = allowsApproxFunction(II)
? getNativeBuiltinIdForIntrinsic(IID)
: getBuiltinIdForIntrinsic(IID);
SPIRVType *STy = transType(II->getType());
std::vector<SPIRVValue *> Ops(1, transValue(II->getArgOperand(0), BB));
return BM->addExtInst(STy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
Expand All @@ -3395,7 +3427,9 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
case Intrinsic::minnum: {
if (!checkTypeForSPIRVExtendedInstLowering(II, BM))
break;
SPIRVWord ExtOp = getBuiltinIdForIntrinsic(II->getIntrinsicID());
const SPIRVWord ExtOp = allowsApproxFunction(II)
? getNativeBuiltinIdForIntrinsic(IID)
: getBuiltinIdForIntrinsic(IID);
SPIRVType *STy = transType(II->getType());
std::vector<SPIRVValue *> Ops{transValue(II->getArgOperand(0), BB),
transValue(II->getArgOperand(1), BB)};
Expand All @@ -3410,13 +3444,12 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
SPIRVValue *FirstArgVal = transValue(II->getArgOperand(0), BB);
SPIRVValue *SecondArgVal = transValue(II->getArgOperand(1), BB);

Op OC = (II->getIntrinsicID() == Intrinsic::smin)
? OpSLessThan
: ((II->getIntrinsicID() == Intrinsic::smax)
? OpSGreaterThan
: ((II->getIntrinsicID() == Intrinsic::umin)
? OpULessThan
: OpUGreaterThan));
const Op OC =
(IID == Intrinsic::smin)
? OpSLessThan
: ((IID == Intrinsic::smax)
? OpSGreaterThan
: ((IID == Intrinsic::umin) ? OpULessThan : OpUGreaterThan));
if (auto *VecTy = dyn_cast<VectorType>(II->getArgOperand(0)->getType()))
BoolTy = VectorType::get(BoolTy, VecTy->getElementCount());
SPIRVValue *Cmp =
Expand Down Expand Up @@ -3451,8 +3484,8 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
}
case Intrinsic::ctlz:
case Intrinsic::cttz: {
SPIRVWord ExtOp = II->getIntrinsicID() == Intrinsic::ctlz ? OpenCLLIB::Clz
: OpenCLLIB::Ctz;
const SPIRVWord ExtOp =
IID == Intrinsic::ctlz ? OpenCLLIB::Clz : OpenCLLIB::Ctz;
SPIRVType *Ty = transType(II->getType());
std::vector<SPIRVValue *> Ops(1, transValue(II->getArgOperand(0), BB));
return BM->addExtInst(Ty, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops,
Expand Down Expand Up @@ -3904,8 +3937,8 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
else
// Other LLVM intrinsics shouldn't get to SPIRV, because they
// can't be represented in SPIRV or aren't implemented yet.
BM->SPIRVCK(
false, InvalidFunctionCall, II->getCalledOperand()->getName().str());
BM->SPIRVCK(false, InvalidFunctionCall,
II->getCalledOperand()->getName().str());
}
return nullptr;
}
Expand Down
5 changes: 4 additions & 1 deletion test/llvm-intrinsics/sqrt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ entry:
%0 = call float @llvm.sqrt.f32(float 0x40091EB860000000)
%1 = call double @llvm.sqrt.f64(double 2.710000e+00)
%2 = call <4 x double> @llvm.sqrt.v4f64(<4 x double> <double 5.000000e-01, double 2.000000e-01, double 3.000000e-01, double 4.000000e-01>)
%3 = call afn float @llvm.sqrt.f32(float 0x40091EB860000000)
%4 = call afn double @llvm.sqrt.f64(double 2.710000e+00)
; CHECK: ExtInst [[Float]] {{[0-9]+}} [[ExtInstSetId]] sqrt [[FloatArg]]
; CHECK: ExtInst [[Double]] {{[0-9]+}} [[ExtInstSetId]] sqrt [[DoubleArg]]
; CHECK: ExtInst [[Double4]] {{[0-9]+}} [[ExtInstSetId]] sqrt [[Double4Arg]]
; CHECK: ExtInst [[Float]] {{[0-9]+}} [[ExtInstSetId]] native_sqrt [[FloatArg]]
; CHECK: ExtInst [[Double]] {{[0-9]+}} [[ExtInstSetId]] sqrt [[DoubleArg]]
ret void
}

Expand All @@ -43,4 +47,3 @@ attributes #1 = { nounwind readnone speculatable willreturn }

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git b89131cdda5871731a9139664aef2b70c6d72bbd)"}

42 changes: 42 additions & 0 deletions test/lower-non-standard-vec-intrinsic-with-ext.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
; RUN: llvm-as %s -o %t.bc
; RUN: not llvm-spirv -s %t.bc
; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_vector_compute %t.bc
; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s

; CHECK: ExtInstImport [[ExtInstSetId:[0-9]+]] "OpenCL.std"
; CHECK: TypeFloat [[Float:[0-9]+]] 32
; CHECK: TypeVector [[Float5:[0-9]+]] [[Float]] 5

; ModuleID = 'lower-non-standard-vec-with-ext'
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64-unknown-unknown"

@Id = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32

declare <5 x float> @llvm.sqrt.f32(<5 x float> %x)

; Function Attrs: convergent norecurse
define dso_local spir_func <5 x float> @test_sqrt(<5 x float> %src) local_unnamed_addr #0 !sycl_explicit_simd !4 !intel_reqd_sub_group_size !6 {
entry:
%res = call <5 x float> @llvm.sqrt.f32(<5 x float> %src)
; CHECK: ExtInst [[Float5]] {{[0-9]+}} [[ExtInstSetId]] sqrt
ret <5 x float> %res
}

attributes #0 = { convergent norecurse "frame-pointer"="all" "min-legal-vector-width"="256" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="lower-external-funcs-with-z.cpp" }

!llvm.module.flags = !{!0, !1}
!opencl.spir.version = !{!2}
!spirv.Source = !{!3}
!opencl.used.extensions = !{!4}
!opencl.used.optional.core.features = !{!4}
!opencl.compiler.options = !{!4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"frame-pointer", i32 2}
!2 = !{i32 1, i32 2}
!3 = !{i32 0, i32 100000}
!4 = !{}
!5 = !{!"Compiler"}
!6 = !{i32 1}

0 comments on commit 78ad93b

Please sign in to comment.