Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement SPV_INTEL_token_type extension
Browse files Browse the repository at this point in the history
This extension adds a type-declaration instruction OpTypeTokenINTEL,
which is an analog of LLVM's type token. This type specifies IDs of
entry points and exit points of certain IL constructs, for example it
can be useful for exception handling representation in IL.

Spec: intel/llvm#3788

Signed-off-by: Dmitry Sidorov <dmitry.sidorov@intel.com>
MrSidims committed May 27, 2021
1 parent c62ef5e commit afb07fe
Showing 13 changed files with 136 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/LLVMSPIRVExtensions.inc
Original file line number Diff line number Diff line change
@@ -37,3 +37,4 @@ EXT(SPV_INTEL_loop_fuse)
EXT(SPV_INTEL_long_constant_composite)
EXT(SPV_INTEL_optnone)
EXT(SPV_INTEL_memory_access_aliasing)
EXT(SPV_INTEL_token_type)
4 changes: 3 additions & 1 deletion lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
@@ -470,7 +470,7 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) {

SPIRVDBG(spvdbgs() << "[transType] " << *T << " -> ";)
T->validate();
switch (T->getOpCode()) {
switch (static_cast<SPIRVWord>(T->getOpCode())) {
case OpTypeVoid:
return mapType(T, Type::getVoidTy(*Context));
case OpTypeBool:
@@ -482,6 +482,8 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) {
case OpTypeArray:
return mapType(T, ArrayType::get(transType(T->getArrayElementType()),
T->getArrayLength()));
case internal::OpTypeTokenINTEL:
return mapType(T, Type::getTokenTy(*Context));
case OpTypePointer:
return mapType(
T, PointerType::get(
10 changes: 10 additions & 0 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
@@ -293,6 +293,16 @@ SPIRVType *LLVMToSPIRVBase::transType(Type *T) {
if (T->isFloatingPointTy())
return mapType(T, BM->addFloatType(T->getPrimitiveSizeInBits()));

if (T->isTokenTy()) {
BM->getErrorLog().checkError(
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_token_type),
SPIRVEC_RequiresExtension,
"SPV_INTEL_token_type\n"
"NOTE: LLVM module contains token type, which doesn't have analogs in "
"SPIR-V without extensions");
return mapType(T, BM->addTokenTypeINTEL());
}

// A pointer to image or pipe type in LLVM is translated to a SPIRV
// (non-pointer) image or pipe type.
if (T->isPointerTy()) {
2 changes: 2 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVErrorEnum.h
Original file line number Diff line number Diff line change
@@ -17,3 +17,5 @@ _SPIRV_OP(InvalidInstruction, "Can't translate llvm instruction:\n")
_SPIRV_OP(InvalidWordCount,
"Can't encode instruction with word count greater than 65535:\n")
_SPIRV_OP(Requires1_1, "Feature requires SPIR-V 1.1 or greater:")
_SPIRV_OP(RequiresExtension,
"Feature requires the following SPIR-V extension:\n")
5 changes: 5 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVModule.cpp
Original file line number Diff line number Diff line change
@@ -253,6 +253,7 @@ class SPIRVModuleImpl : public SPIRVModule {
SPIRVTypeVmeImageINTEL *addVmeImageINTELType(SPIRVTypeImage *T) override;
SPIRVTypeBufferSurfaceINTEL *
addBufferSurfaceINTELType(SPIRVAccessQualifierKind Access) override;
SPIRVTypeTokenINTEL *addTokenTypeINTEL() override;

// Constant creation functions
SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *) override;
@@ -946,6 +947,10 @@ SPIRVType *SPIRVModuleImpl::addSubgroupAvcINTELType(Op TheOpCode) {
return addType(new SPIRVTypeSubgroupAvcINTEL(TheOpCode, this, getId()));
}

SPIRVTypeTokenINTEL *SPIRVModuleImpl::addTokenTypeINTEL() {
return addType(new SPIRVTypeTokenINTEL(this, getId()));
}

SPIRVFunction *SPIRVModuleImpl::addFunction(SPIRVFunction *Func) {
FuncVec.push_back(add(Func));
return Func;
2 changes: 2 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVModule.h
Original file line number Diff line number Diff line change
@@ -94,6 +94,7 @@ class SPIRVAsmTargetINTEL;
class SPIRVAsmINTEL;
class SPIRVAsmCallINTEL;
class SPIRVTypeBufferSurfaceINTEL;
class SPIRVTypeTokenINTEL;

typedef SPIRVBasicBlock SPIRVLabel;
struct SPIRVTypeImageDescriptor;
@@ -250,6 +251,7 @@ class SPIRVModule {
virtual SPIRVTypeVmeImageINTEL *addVmeImageINTELType(SPIRVTypeImage *) = 0;
virtual SPIRVTypeBufferSurfaceINTEL *
addBufferSurfaceINTELType(SPIRVAccessQualifierKind Access) = 0;
virtual SPIRVTypeTokenINTEL *addTokenTypeINTEL() = 0;

// Constants creation functions
virtual SPIRVValue *
1 change: 1 addition & 0 deletions lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
Original file line number Diff line number Diff line change
@@ -520,6 +520,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
add(internal::CapabilityOptNoneINTEL, "OptNoneINTEL");
add(internal::CapabilityMemoryAccessAliasingINTEL,
"MemoryAccessAliasingINTEL");
add(internal::CapabilityTokenTypeINTEL, "TokenTypeINTEL");
}
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)

2 changes: 1 addition & 1 deletion lib/SPIRV/libSPIRV/SPIRVOpCode.h
Original file line number Diff line number Diff line change
@@ -210,7 +210,7 @@ inline bool isTypeOpCode(Op OpCode) {
unsigned OC = OpCode;
return (OpTypeVoid <= OC && OC <= OpTypePipe) || OC == OpTypePipeStorage ||
isSubgroupAvcINTELTypeOpCode(OpCode) || OC == OpTypeVmeImageINTEL ||
isVCOpCode(OpCode);
isVCOpCode(OpCode) || OC == internal::OpTypeTokenINTEL;
}

inline bool isSpecConstantOpCode(Op OpCode) {
1 change: 1 addition & 0 deletions lib/SPIRV/libSPIRV/SPIRVOpCodeEnumInternal.h
Original file line number Diff line number Diff line change
@@ -4,3 +4,4 @@ _SPIRV_OP_INTERNAL(Forward, internal::OpForward)
_SPIRV_OP_INTERNAL(AliasDomainDeclINTEL, internal::OpAliasDomainDeclINTEL)
_SPIRV_OP_INTERNAL(AliasScopeDeclINTEL, internal::OpAliasScopeDeclINTEL)
_SPIRV_OP_INTERNAL(AliasScopeListDeclINTEL, internal::OpAliasScopeListDeclINTEL)
_SPIRV_OP_INTERNAL(TypeTokenINTEL, internal::OpTypeTokenINTEL)
21 changes: 21 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVType.h
Original file line number Diff line number Diff line change
@@ -1036,5 +1036,26 @@ _SPIRV_OP(AvcImeDualReferenceStreamin)
_SPIRV_OP(AvcRefResult)
_SPIRV_OP(AvcSicResult)
#undef _SPIRV_OP

class SPIRVTypeTokenINTEL : public SPIRVType {
public:
// Complete constructor
SPIRVTypeTokenINTEL(SPIRVModule *M, SPIRVId TheId)
: SPIRVType(M, 2, internal::OpTypeTokenINTEL, TheId) {}
// Incomplete constructor
SPIRVTypeTokenINTEL() : SPIRVType(internal::OpTypeTokenINTEL) {}

SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityTokenTypeINTEL);
}

llvm::Optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_token_type;
}

protected:
_SPIRV_DEF_ENCDEC1(Id)
};

} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVTYPE_H
7 changes: 6 additions & 1 deletion lib/SPIRV/libSPIRV/spirv_internal.hpp
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ enum InternalOp {
IOpAliasDomainDeclINTEL = 5911,
IOpAliasScopeDeclINTEL = 5912,
IOpAliasScopeListDeclINTEL = 5913,
IOpTypeTokenINTEL = 6113,
IOpPrev = OpMax - 2,
IOpForward
};
@@ -49,7 +50,8 @@ enum InternalDecoration {

enum InternalCapability {
ICapMemoryAccessAliasingINTEL = 5910,
ICapOptNoneINTEL = 6094
ICapOptNoneINTEL = 6094,
ICapTokenTypeINTEL = 6112
};

enum InternalFunctionControlMask { IFunctionControlOptNoneINTELMask = 0x10000 };
@@ -67,6 +69,7 @@ constexpr Op OpAliasDomainDeclINTEL = static_cast<Op>(IOpAliasDomainDeclINTEL);
constexpr Op OpAliasScopeDeclINTEL = static_cast<Op>(IOpAliasScopeDeclINTEL);
constexpr Op OpAliasScopeListDeclINTEL =
static_cast<Op>(IOpAliasScopeListDeclINTEL);
constexpr Op OpTypeTokenINTEL = static_cast<Op>(IOpTypeTokenINTEL);

constexpr Decoration DecorationAliasScopeINTEL =
static_cast<Decoration>(IDecAliasScopeINTEL );
@@ -77,6 +80,8 @@ constexpr Capability CapabilityOptNoneINTEL =
static_cast<Capability>(ICapOptNoneINTEL);
constexpr Capability CapabilityMemoryAccessAliasingINTEL =
static_cast<Capability>(ICapMemoryAccessAliasingINTEL);
constexpr Capability CapabilityTokenTypeINTEL =
static_cast<Capability>(ICapTokenTypeINTEL);

constexpr FunctionControlMask FunctionControlOptNoneINTELMask =
static_cast<FunctionControlMask>(IFunctionControlOptNoneINTELMask);
39 changes: 39 additions & 0 deletions test/negative/feature_requires_extension.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; Check whether the translator reports an error for a module with token type
; if SPV_INTEL_token_type extension is not used.

; RUN: llvm-as < %s -o %t.bc
; RUN: not llvm-spirv %t.bc 2>&1 --spirv-allow-unknown-intrinsics | FileCheck %s

; CHECK: RequiresExtension: Feature requires the following SPIR-V extension:
; CHECK-NEXT: SPV_INTEL_token_type
; CHECK-NEXT: NOTE: LLVM module contains token type, which doesn't have analogs
; CHECK-SAME: in SPIR-V without extensions

; ModuleID = 'token.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024"
target triple = "spir-unknown-unknown"

declare token @llvm.tokenfoo()

; Function Attrs: nounwind
define spir_kernel void @foo() #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !2 !kernel_arg_type !2 !kernel_arg_type_qual !2 !kernel_arg_base_type !2 {
entry:
%tok = call token @llvm.tokenfoo()
ret void
}

attributes #0 = { nounwind }

!spirv.MemoryModel = !{!0}
!opencl.enable.FP_CONTRACT = !{}
!spirv.Source = !{!1}
!opencl.spir.version = !{!0}
!opencl.ocl.version = !{!0}
!opencl.used.extensions = !{!2}
!opencl.used.optional.core.features = !{!2}
!spirv.Generator = !{!3}

!0 = !{i32 1, i32 2}
!1 = !{i32 3, i32 102000}
!2 = !{}
!3 = !{i16 6, i16 14}
44 changes: 44 additions & 0 deletions test/transcoding/SPV_INTEL_token_type/token_type_intel.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
; RUN: llvm-as < %s -o %t.bc
; RUN: llvm-spirv %t.bc -o %t.spv --spirv-allow-unknown-intrinsics --spirv-ext=+SPV_INTEL_token_type
; RUN: llvm-spirv %t.spv -to-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM

; CHECK-SPIRV: Capability TokenTypeINTEL
; CHECK-SPIRV: Extension "SPV_INTEL_token_type"
; CHECK-SPIRV: Name [[#FUN:]] "llvm.tokenfoo"
; CHECK-SPIRV: TypeTokenINTEL [[#TYPE:]]
; CHECK-SPIRV: TypeFunction [[#FUN_TYPE:]] [[#TYPE]]
; CHECK-SPIRV: Function {{.*}} [[#FUN]] {{.*}} [[#FUN_TYPE]]


; ModuleID = 'token.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024"
target triple = "spir-unknown-unknown"

; CHECK-LLVM: declare token @llvm.tokenfoo()
declare token @llvm.tokenfoo()

; Function Attrs: nounwind
define spir_kernel void @foo() #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !2 !kernel_arg_type !2 !kernel_arg_type_qual !2 !kernel_arg_base_type !2 {
entry:
; CHECK-LLVM: call token @llvm.tokenfoo()
%tok = call token @llvm.tokenfoo()
ret void
}

attributes #0 = { nounwind }

!spirv.MemoryModel = !{!0}
!opencl.enable.FP_CONTRACT = !{}
!spirv.Source = !{!1}
!opencl.spir.version = !{!0}
!opencl.ocl.version = !{!0}
!opencl.used.extensions = !{!2}
!opencl.used.optional.core.features = !{!2}
!spirv.Generator = !{!3}

!0 = !{i32 1, i32 2}
!1 = !{i32 3, i32 102000}
!2 = !{}
!3 = !{i16 6, i16 14}

0 comments on commit afb07fe

Please sign in to comment.