are translated for image types, but they should be encoded in LLVM IR type name
rather than function metadata.
-Function parameter and global variable decoration through metadata
+Function parameter, instruction and global variable decoration through metadata
------------------------------------------------------------------
-Both function parameters and global variables can be decorated using LLVM
+Function parameters, instructions and global variables can be decorated using LLVM
metadata through the metadata names ``spirv.ParameterDecorations`` and
``spirv.Decorations`` respectively. ``spirv.ParameterDecorations`` must be tied
to the kernel function while ``spirv.Decorations`` is tied directly to the
-global variable.
+instruction or global variable.
A "decoration-node" is a metadata node consisting of one or more operands. The
first operand is an integer literal representing the SPIR-V decoration
references to decoration-lists, where N is the number of arguments of the
function the metadata is tied to.
-``spirv.Decorations`` example:
+``spirv.Decorations`` applied on a global variable example:
.. code-block:: llvm
decorates a global variable ``v`` with ``Constant`` and ``LinkageAttributes``
with extra operands ``"v"`` and ``Export`` in SPIR-V.
+``spirv.Decorations`` applied on an instruction example:
+
+.. code-block:: llvm
+
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %b, i64 1, !spirv.Decorations !1
+ ...
+ !1 = !{!2}
+ !2 = !{i32 6442, i32 1, i32 2} ; {CacheControlLoadINTEL, CacheLevel=1, Cached}
+
+decorates getelementptr instruction with CacheControlLoadINTEL decoration with
+extra operands ``i32 1`` and ``i32 2``.
+
``spirv.ParameterDecorations`` example:
.. code-block:: llvm
EXT(SPV_INTEL_tensor_float32_conversion) // TODO: to remove old extension
EXT(SPV_INTEL_tensor_float32_rounding)
EXT(SPV_EXT_relaxed_printf_string_address_space)
+EXT(SPV_INTEL_cache_controls)
return MDNode::get(*Context, MDs);
}
-void SPIRVToLLVM::transVarDecorationsToMetadata(SPIRVValue *BV, Value *V) {
- if (!BV->isVariable())
+void SPIRVToLLVM::transDecorationsToMetadata(SPIRVValue *BV, Value *V) {
+ if (!BV->isVariable() && !BV->isInst())
return;
- if (auto *GV = dyn_cast<GlobalVariable>(V)) {
+ auto SetDecorationsMetadata = [&](auto V) {
std::vector<SPIRVDecorate const *> Decorates = BV->getDecorations();
if (!Decorates.empty()) {
MDNode *MDList = transDecorationsToMetadataList(Context, Decorates);
- GV->setMetadata(SPIRV_MD_DECORATIONS, MDList);
+ V->setMetadata(SPIRV_MD_DECORATIONS, MDList);
}
- }
+ };
+
+ if (auto *GV = dyn_cast<GlobalVariable>(V))
+ SetDecorationsMetadata(GV);
+ else if (auto *I = dyn_cast<Instruction>(V))
+ SetDecorationsMetadata(I);
}
bool SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) {
// Decoration metadata is only enabled in SPIR-V friendly mode
if (BM->getDesiredBIsRepresentation() == BIsRepresentation::SPIRVFriendlyIR)
- transVarDecorationsToMetadata(BV, V);
+ transDecorationsToMetadata(BV, V);
DbgTran->transDbgInfo(BV, V);
return true;
SmallVectorImpl<Function *> &Funcs);
void transIntelFPGADecorations(SPIRVValue *BV, Value *V);
void transMemAliasingINTELDecorations(SPIRVValue *BV, Value *V);
- void transVarDecorationsToMetadata(SPIRVValue *BV, Value *V);
+ void transDecorationsToMetadata(SPIRVValue *BV, Value *V);
void transFunctionDecorationsToMetadata(SPIRVFunction *BF, Function *F);
void
transFunctionPointerCallArgumentAttributes(SPIRVValue *BV, CallInst *CI,
new SPIRVDecorateImplementInCSRINTEL(Target, Value->getZExtValue()));
break;
}
+ case spv::internal::DecorationCacheControlLoadINTEL: {
+ ErrLog.checkError(
+ NumOperands == 3, SPIRVEC_InvalidLlvmModule,
+ "CacheControlLoadINTEL requires exactly 2 extra operands");
+ auto *CacheLevel =
+ mdconst::dyn_extract<ConstantInt>(DecoMD->getOperand(1));
+ auto *CacheControl =
+ mdconst::dyn_extract<ConstantInt>(DecoMD->getOperand(2));
+ ErrLog.checkError(CacheLevel, SPIRVEC_InvalidLlvmModule,
+ "CacheControlLoadINTEL cache level operand is required "
+ "to be an integer");
+ ErrLog.checkError(CacheControl, SPIRVEC_InvalidLlvmModule,
+ "CacheControlLoadINTEL cache control operand is "
+ "required to be an integer");
+
+ Target->addDecorate(new SPIRVDecorateCacheControlLoadINTEL(
+ Target, CacheLevel->getZExtValue(),
+ static_cast<internal::LoadCacheControlINTEL>(
+ CacheControl->getZExtValue())));
+ break;
+ }
+ case spv::internal::DecorationCacheControlStoreINTEL: {
+ ErrLog.checkError(
+ NumOperands == 3, SPIRVEC_InvalidLlvmModule,
+ "CacheControlStoreINTEL requires exactly 2 extra operands");
+ auto *CacheLevel =
+ mdconst::dyn_extract<ConstantInt>(DecoMD->getOperand(1));
+ auto *CacheControl =
+ mdconst::dyn_extract<ConstantInt>(DecoMD->getOperand(2));
+ ErrLog.checkError(CacheLevel, SPIRVEC_InvalidLlvmModule,
+ "CacheControlStoreINTEL cache level operand is "
+ "required to be an integer");
+ ErrLog.checkError(CacheControl, SPIRVEC_InvalidLlvmModule,
+ "CacheControlStoreINTEL cache control operand is "
+ "required to be an integer");
+
+ Target->addDecorate(new SPIRVDecorateCacheControlStoreINTEL(
+ Target, CacheLevel->getZExtValue(),
+ static_cast<internal::StoreCacheControlINTEL>(
+ CacheControl->getZExtValue())));
+ break;
+ }
default: {
if (NumOperands == 1) {
Target->addDecorate(new SPIRVDecorate(DecoKind, Target));
BV->setFPFastMathMode(M);
}
}
- if (Instruction *Inst = dyn_cast<Instruction>(V))
+ if (Instruction *Inst = dyn_cast<Instruction>(V)) {
if (shouldTryToAddMemAliasingDecoration(Inst))
transMemAliasingINTELDecorations(Inst, BV);
+ if (auto *IDecoMD = Inst->getMetadata(SPIRV_MD_DECORATIONS))
+ transMetadataDecorations(IDecoMD, BV);
+ }
if (auto *CI = dyn_cast<CallInst>(V)) {
auto OC = BV->getOpCode();
case internal::DecorationInitModeINTEL:
case internal::DecorationImplementInCSRINTEL:
return ExtensionID::SPV_INTEL_global_variable_decorations;
+ case internal::DecorationCacheControlLoadINTEL:
+ case internal::DecorationCacheControlStoreINTEL:
+ return ExtensionID::SPV_INTEL_cache_controls;
default:
return {};
}
Value){};
};
+class SPIRVDecorateCacheControlLoadINTEL : public SPIRVDecorate {
+public:
+ // Complete constructor for SPIRVDecorateCacheControlLoadINTEL
+ SPIRVDecorateCacheControlLoadINTEL(
+ SPIRVEntry *TheTarget, SPIRVWord CacheLevel,
+ spv::internal::LoadCacheControlINTEL CacheControl)
+ : SPIRVDecorate(spv::internal::DecorationCacheControlLoadINTEL, TheTarget,
+ CacheLevel, static_cast<SPIRVWord>(CacheControl)){};
+
+ SPIRVWord getCacheLevel() const { return Literals.at(0); };
+ spv::internal::LoadCacheControlINTEL getCacheControl() const {
+ return static_cast<spv::internal::LoadCacheControlINTEL>(Literals.at(1));
+ };
+};
+
+class SPIRVDecorateCacheControlStoreINTEL : public SPIRVDecorate {
+public:
+ // Complete constructor for SPIRVDecorateCacheControlStoreINTEL
+ SPIRVDecorateCacheControlStoreINTEL(
+ SPIRVEntry *TheTarget, SPIRVWord CacheLevel,
+ spv::internal::StoreCacheControlINTEL CacheControl)
+ : SPIRVDecorate(spv::internal::DecorationCacheControlStoreINTEL,
+ TheTarget, CacheLevel,
+ static_cast<SPIRVWord>(CacheControl)){};
+
+ SPIRVWord getCacheLevel() const { return Literals.at(0); };
+ spv::internal::StoreCacheControlINTEL getCacheControl() const {
+ return static_cast<spv::internal::StoreCacheControlINTEL>(Literals.at(1));
+ };
+};
+
} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVDECORATE_H
{internal::CapabilityGlobalVariableDecorationsINTEL});
ADD_VEC_INIT(internal::DecorationArgumentAttributeINTEL,
{CapabilityFunctionPointersINTEL});
+ ADD_VEC_INIT(internal::DecorationCacheControlLoadINTEL,
+ {internal::CapabilityCacheControlsINTEL});
+ ADD_VEC_INIT(internal::DecorationCacheControlStoreINTEL,
+ {internal::CapabilityCacheControlsINTEL});
}
template <> inline void SPIRVMap<BuiltIn, SPIRVCapVec>::init() {
add(internal::DecorationInitModeINTEL, "InitModeINTEL");
add(internal::DecorationImplementInCSRINTEL, "ImplementInCSRINTEL");
add(internal::DecorationArgumentAttributeINTEL, "ArgumentAttributeINTEL");
+ add(internal::DecorationCacheControlLoadINTEL, "CacheControlLoadINTEL");
+ add(internal::DecorationCacheControlStoreINTEL, "CacheControlStoreINTEL");
add(DecorationMax, "Max");
}
add(internal::CapabilityMaskedGatherScatterINTEL, "MaskedGatherScatterINTEL");
add(internal::CapabilityTensorFloat32RoundingINTEL,
"TensorFloat32RoundingINTEL");
+ add(internal::CapabilityCacheControlsINTEL, "CacheControlsINTEL");
}
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)
IDecHostAccessINTEL = 6147,
IDecInitModeINTEL = 6148,
IDecImplementInCSRINTEL = 6149,
- IDecArgumentAttributeINTEL = 6409
+ IDecArgumentAttributeINTEL = 6409,
+ IDecCacheControlLoadINTEL = 6442,
+ IDecCacheControlStoreINTEL = 6443
};
enum InternalCapability {
ICapGlobalVariableDecorationsINTEL = 6146,
ICapabilityComplexFloatMulDivINTEL = 6414,
ICapabilityTensorFloat32RoundingINTEL = 6425,
- ICapabilityMaskedGatherScatterINTEL = 6427
+ ICapabilityMaskedGatherScatterINTEL = 6427,
+ ICapabilityCacheControlsINTEL = 6441
};
enum InternalFunctionControlMask { IFunctionControlOptNoneINTELMask = 0x10000 };
IBuiltInGlobalHWThreadIDINTEL = 6136,
};
+enum class LoadCacheControlINTEL {
+ Uncached = 0,
+ Cached = 1,
+ Streaming = 2,
+ InvalidateAfterRead = 3,
+ ConstCached = 4
+};
+
+enum class StoreCacheControlINTEL {
+ Uncached = 0,
+ WriteThrough = 1,
+ WriteBack = 2,
+ Streaming = 3
+};
+
#define _SPIRV_OP(x, y) constexpr x x##y = static_cast<x>(I##x##y);
_SPIRV_OP(Capability, JointMatrixINTEL)
_SPIRV_OP(Op, TypeJointMatrixINTEL)
_SPIRV_OP(Capability, TensorFloat32RoundingINTEL)
_SPIRV_OP(Op, RoundFToTF32INTEL)
+
+_SPIRV_OP(Capability, CacheControlsINTEL)
#undef _SPIRV_OP
constexpr SourceLanguage SourceLanguagePython =
static_cast<Decoration>(IDecImplementInCSRINTEL);
constexpr Decoration DecorationArgumentAttributeINTEL =
static_cast<Decoration>(IDecArgumentAttributeINTEL);
+constexpr Decoration DecorationCacheControlLoadINTEL =
+ static_cast<Decoration>(IDecCacheControlLoadINTEL);
+constexpr Decoration DecorationCacheControlStoreINTEL =
+ static_cast<Decoration>(IDecCacheControlStoreINTEL);
constexpr Capability CapabilityFastCompositeINTEL =
static_cast<Capability>(ICapFastCompositeINTEL);
--- /dev/null
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls %t.bc -o %t.spv
+; RUN: llvm-spirv -r %t.spv --spirv-target-env=SPV-IR -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM
+
+; CHECK-SPIRV-DAG: Load {{[0-9]+}} {{[0-9]+}} [[LoadPtr:[0-9]+]]
+; CHECK-SPIRV-DAG: Store [[StorePtr:[0-9]+]]
+
+; CHECK-SPIRV-DAG: Decorate [[LoadPtr]] CacheControlLoadINTEL 0 1
+; CHECK-SPIRV-DAG: Decorate [[LoadPtr]] CacheControlLoadINTEL 1 1
+; CHECK-SPIRV-DAG: Decorate [[StorePtr]] CacheControlStoreINTEL 0 1
+; CHECK-SPIRV-DAG: Decorate [[StorePtr]] CacheControlStoreINTEL 1 2
+
+; CHECK-LLVM: %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %buffer, i64 1, !spirv.Decorations [[LoadMD:![0-9]+]]
+; CHECK-LLVM: load i32, i32 addrspace(1)* %arrayidx, align 4
+
+; CHECK-LLVM: %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %buffer, i64 0, !spirv.Decorations [[StoreMD:![0-9]+]]
+; CHECK-LLVM: store i32 %0, i32 addrspace(1)* %arrayidx1, align 4
+
+; CHECK-LLVM: [[LoadMD]] = !{[[CC0:![0-9]+]], [[CC1:![0-9]+]]}
+; CHECK-LLVM: [[CC0]] = !{i32 6442, i32 0, i32 1}
+; CHECK-LLVM: [[CC1]] = !{i32 6442, i32 1, i32 1}
+
+; CHECK-LLVM: [[StoreMD]] = !{[[CC2:![0-9]+]], [[CC3:![0-9]+]]}
+; CHECK-LLVM: [[CC2]] = !{i32 6443, i32 0, i32 1}
+; CHECK-LLVM: [[CC3]] = !{i32 6443, i32 1, i32 2}
+
+target triple = "spir64-unknown-unknown"
+
+define spir_kernel void @test(i32 addrspace(1)* %buffer) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %buffer, i64 1, !spirv.Decorations !3
+ %0 = load i32, i32 addrspace(1)* %arrayidx, align 4
+ %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %buffer, i64 0, !spirv.Decorations !6
+ store i32 %0, i32 addrspace(1)* %arrayidx1, align 4
+ ret void
+}
+
+!spirv.MemoryModel = !{!0}
+!spirv.Source = !{!1}
+!opencl.spir.version = !{!2}
+!opencl.ocl.version = !{!2}
+
+!0 = !{i32 2, i32 2}
+!1 = !{i32 3, i32 102000}
+!2 = !{i32 1, i32 2}
+!3 = !{!4, !5}
+!4 = !{i32 6442, i32 0, i32 1} ; {CacheControlLoadINTEL, CacheLevel=0, Cached}
+!5 = !{i32 6442, i32 1, i32 1} ; {CacheControlLoadINTEL, CacheLevel=1, Cached}
+!6 = !{!7, !8}
+!7 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
+!8 = !{i32 6443, i32 1, i32 2} ; {CacheControlStoreINTEL, CacheLevel=1, WriteBack}
--- /dev/null
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls %t.bc -o %t.spv
+; RUN: llvm-spirv -r %t.spv --spirv-target-env=SPV-IR -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM
+
+; CHECK-SPIRV-DAG: Store [[StorePtr:[0-9]+]]
+
+; CHECK-SPIRV-DAG: Decorate [[StorePtr]] CacheControlStoreINTEL 0 1
+; CHECK-SPIRV-DAG: Decorate [[StorePtr]] CacheControlStoreINTEL 1 3
+
+; CHECK-LLVM: @p = common addrspace(1) global i32 0, align 4, !spirv.Decorations [[GlobalMD:![0-9]+]]
+; CHECK-LLVM: store i32 0, i32 addrspace(1)* @p, align 4
+
+; CHECK-LLVM-DAG: [[CC0:![0-9]+]] = !{i32 6443, i32 0, i32 1}
+; CHECK-LLVM-DAG: [[CC1:![0-9]+]] = !{i32 6443, i32 1, i32 3}
+; CHECK-LLVM-DAG: [[GlobalMD]] = {{.*}}[[CC0]]{{.*}}[[CC1]]
+
+target triple = "spir64-unknown-unknown"
+
+@p = common addrspace(1) global i32 0, align 4, !spirv.Decorations !3
+
+define spir_kernel void @test() {
+entry:
+ store i32 0, i32 addrspace(1)* @p, align 4
+ ret void
+}
+
+!spirv.MemoryModel = !{!0}
+!spirv.Source = !{!1}
+!opencl.spir.version = !{!2}
+!opencl.ocl.version = !{!2}
+
+!0 = !{i32 2, i32 2}
+!1 = !{i32 3, i32 102000}
+!2 = !{i32 1, i32 2}
+!3 = !{!4, !5}
+!4 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
+!5 = !{i32 6443, i32 1, i32 3} ; {CacheControlStoreINTEL, CacheLevel=1, Streaming}
--- /dev/null
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv --spirv-ext=+SPV_INTEL_cache_controls %t.bc -o %t.spv
+; RUN: llvm-spirv -r %t.spv --spirv-target-env=SPV-IR -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM
+
+; CHECK-SPIRV: Decorate {{[0-9]+}} CacheControlLoadINTEL 0 0
+; CHECK-SPIRV: Decorate {{[0-9]+}} CacheControlStoreINTEL 0 1
+
+target triple = "spir64-unknown-unknown"
+
+; CHECK-LLVM: spir_kernel {{.*}} !spirv.ParameterDecorations [[ParamDecID:![0-9]+]]
+define spir_kernel void @test(i32 addrspace(1)* %dummy, i32 addrspace(1)* %buffer) !spirv.ParameterDecorations !3 {
+entry:
+ %0 = load i32, i32 addrspace(1)* %buffer, align 4
+ store i32 %0, i32 addrspace(1)* %buffer, align 4
+ ret void
+}
+
+!spirv.MemoryModel = !{!0}
+!spirv.Source = !{!1}
+!opencl.spir.version = !{!2}
+!opencl.ocl.version = !{!2}
+
+!0 = !{i32 2, i32 2}
+!1 = !{i32 3, i32 102000}
+!2 = !{i32 1, i32 2}
+!3 = !{!4, !5}
+!4 = !{}
+!5 = !{!6, !7}
+; CHECK-LLVM: [[ParamDecID]] = !{!{{[0-9]+}}, [[BufferDecID:![0-9]+]]}
+; CHECK-LLVM: [[BufferDecID]] = !{[[StoreDecID:![0-9]+]], [[LoadDecID:![0-9]+]]}
+; CHECK-LLVM: [[StoreDecID]] = !{i32 6442, i32 0, i32 0}
+; CHECK-LLVM: [[LoadDecID]] = !{i32 6443, i32 0, i32 1}
+!6 = !{i32 6442, i32 0, i32 0} ; {CacheControlLoadINTEL, CacheLevel=0, Uncached}
+!7 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}