@@ -69,6 +69,8 @@ class SYCLLowerESIMDLegacyPass : public ModulePass {
69
69
};
70
70
} // namespace
71
71
72
+ constexpr char ATTR_DOUBLE_GRF[] = " esimd-double-grf" ;
73
+
72
74
char SYCLLowerESIMDLegacyPass::ID = 0 ;
73
75
INITIALIZE_PASS (SYCLLowerESIMDLegacyPass, " LowerESIMD" ,
74
76
" Lower constructs specific to Close To Metal" , false , false )
@@ -899,52 +901,30 @@ static inline llvm::Metadata *getMD(llvm::Value *V) {
899
901
return llvm::ValueAsMetadata::get (V);
900
902
}
901
903
902
- // / Updates genx.kernels metadata attribute \p MD for the given function \p F.
903
- // / The value of the attribute is updated only if the new value \p NewVal is
904
- // / bigger than what is already stored in the attribute.
905
- // TODO: 1) In general this function is supposed to handle intrinsics
906
- // translated into kernel's metadata. So, the primary/intended usage model is
907
- // when such intrinsics are called from kernels.
908
- // 2) For now such intrinsics are also handled in functions directly called
909
- // from kernels and being translate into those caller-kernel meeven though such
910
- // behaviour is not fully specified/documented.
911
- // 3) This code (or the code in FE) must verify that slm_init or other such
912
- // intrinsic is not called from another module because kernels in that other
913
- // module would not get updated meta data attributes.
914
- static void updateGenXMDNodes (llvm::Function *F, genx::KernelMDOp MD,
915
- uint64_t NewVal) {
916
- llvm::NamedMDNode *GenXKernelMD =
917
- F->getParent ()->getNamedMetadata (GENX_KERNEL_METADATA);
918
- assert (GenXKernelMD && " invalid genx.kernels metadata" );
904
+ static bool isESIMDKernel (const Function &F) {
905
+ return (F.getCallingConv () == CallingConv::SPIR_KERNEL) &&
906
+ (F.getMetadata (" sycl_explicit_simd" ) != nullptr );
907
+ }
919
908
909
+ template <class CallGraphNodeF >
910
+ static void traverseCallgraphUp (llvm::Function *F, CallGraphNodeF ApplyF) {
920
911
SmallPtrSet<Function *, 32 > FunctionsVisited;
921
912
SmallVector<Function *, 32 > Worklist{F};
913
+
922
914
while (!Worklist.empty ()) {
923
915
Function *CurF = Worklist.pop_back_val ();
924
916
FunctionsVisited.insert (CurF);
925
-
926
- // Update the meta data attribute for the current function.
927
- for (auto Node : GenXKernelMD->operands ()) {
928
- if (Node->getNumOperands () <= MD ||
929
- getVal (Node->getOperand (genx::KernelMDOp::FunctionRef)) != CurF)
930
- continue ;
931
-
932
- llvm::Value *Old = getVal (Node->getOperand (MD));
933
- uint64_t OldVal = cast<llvm::ConstantInt>(Old)->getZExtValue ();
934
- if (OldVal < NewVal) {
935
- llvm::Value *New = llvm::ConstantInt::get (Old->getType (), NewVal);
936
- Node->replaceOperandWith (MD, getMD (New));
937
- }
938
- }
917
+ // Apply the action function.
918
+ ApplyF (CurF);
939
919
940
920
// Update all callers as well.
941
921
for (auto It = CurF->use_begin (); It != CurF->use_end (); It++) {
942
922
auto FCall = It->getUser ();
943
923
if (!isa<CallInst>(FCall))
944
924
llvm::report_fatal_error (
945
925
llvm::Twine (__FILE__ " " ) +
946
- " Found an intrinsic violating assumption on usage from a kernel or "
947
- " a func directly called from a kernel " );
926
+ " Function use other than call detected while traversing call \n "
927
+ " graph starting from kernel property mark-up intrinsic. " );
948
928
949
929
auto FCaller = cast<CallInst>(FCall)->getFunction ();
950
930
if (!FunctionsVisited.count (FCaller))
@@ -953,6 +933,68 @@ static void updateGenXMDNodes(llvm::Function *F, genx::KernelMDOp MD,
953
933
}
954
934
}
955
935
936
+ // A functor which updates ESIMD kernel's uint64_t metadata in case it is less
937
+ // than the given one. Used in callgraph traversal to update nbarriers or SLM
938
+ // size metadata. Update is performed by the '()' operator and happens only
939
+ // when given function matches one of the kernels - thus, only reachable kernels
940
+ // are updated.
941
+ // TODO: 1) In general this function is supposed to handle intrinsics
942
+ // translated into kernel's metadata. So, the primary/intended usage model is
943
+ // when such intrinsics are called from kernels.
944
+ // 2) For now such intrinsics are also handled in functions directly called
945
+ // from kernels and being translate into those caller-kernel meeven though such
946
+ // behaviour is not fully specified/documented.
947
+ // 3) This code (or the code in FE) must verify that slm_init or other such
948
+ // intrinsic is not called from another module because kernels in that other
949
+ // module would not get updated meta data attributes.
950
+ struct UpdateUint64MetaDataToMaxValue {
951
+ Module &M;
952
+ // The uint64_t metadata key to update.
953
+ genx::KernelMDOp Key;
954
+ // The new metadata value. Must be greater than the old for update to happen.
955
+ uint64_t NewVal;
956
+ // Pre-selected nodes from GENX_KERNEL_METADATA which can only potentially be
957
+ // updated.
958
+ SmallVector<MDNode *, 4 > CandidatesToUpdate;
959
+
960
+ UpdateUint64MetaDataToMaxValue (Module &M, genx::KernelMDOp Key,
961
+ uint64_t NewVal)
962
+ : M(M), Key(Key), NewVal(NewVal) {
963
+ // Pre-select nodes for update to do less work in the '()' operator.
964
+ llvm::NamedMDNode *GenXKernelMD = M.getNamedMetadata (GENX_KERNEL_METADATA);
965
+ assert (GenXKernelMD && " invalid genx.kernels metadata" );
966
+ for (auto Node : GenXKernelMD->operands ()) {
967
+ if (Node->getNumOperands () <= (unsigned )Key) {
968
+ continue ;
969
+ }
970
+ llvm::Value *Old = getVal (Node->getOperand (Key));
971
+ uint64_t OldVal = cast<llvm::ConstantInt>(Old)->getZExtValue ();
972
+
973
+ if (OldVal < NewVal) {
974
+ CandidatesToUpdate.push_back (Node);
975
+ }
976
+ }
977
+ }
978
+
979
+ void operator ()(Function *F) {
980
+ // Update the meta data attribute for the current function.
981
+ for (auto Node : CandidatesToUpdate) {
982
+ assert (Node->getNumOperands () > (unsigned )Key);
983
+
984
+ if (getVal (Node->getOperand (genx::KernelMDOp::FunctionRef)) != F) {
985
+ continue ;
986
+ }
987
+ llvm::Value *Old = getVal (Node->getOperand (Key));
988
+ #ifndef _NDEBUG
989
+ uint64_t OldVal = cast<llvm::ConstantInt>(Old)->getZExtValue ();
990
+ assert (OldVal < NewVal);
991
+ #endif // _NDEBUG
992
+ llvm::Value *New = llvm::ConstantInt::get (Old->getType (), NewVal);
993
+ Node->replaceOperandWith (Key, getMD (New));
994
+ }
995
+ }
996
+ };
997
+
956
998
// This function sets/updates VCSLMSize attribute to the kernels
957
999
// calling this intrinsic initializing SLM memory.
958
1000
static void translateSLMInit (CallInst &CI) {
@@ -964,7 +1006,9 @@ static void translateSLMInit(CallInst &CI) {
964
1006
965
1007
uint64_t NewVal = cast<llvm::ConstantInt>(ArgV)->getZExtValue ();
966
1008
assert (NewVal != 0 && " zero slm bytes being requested" );
967
- updateGenXMDNodes (F, genx::KernelMDOp::SLMSize, NewVal);
1009
+ UpdateUint64MetaDataToMaxValue SetMaxSLMSize{
1010
+ *F->getParent (), genx::KernelMDOp::SLMSize, NewVal};
1011
+ traverseCallgraphUp (F, SetMaxSLMSize);
968
1012
}
969
1013
970
1014
// This function sets/updates VCNamedBarrierCount attribute to the kernels
@@ -979,7 +1023,9 @@ static void translateNbarrierInit(CallInst &CI) {
979
1023
980
1024
auto NewVal = cast<llvm::ConstantInt>(ArgV)->getZExtValue ();
981
1025
assert (NewVal != 0 && " zero named barrier count being requested" );
982
- updateGenXMDNodes (F, genx::KernelMDOp::NBarrierCnt, NewVal);
1026
+ UpdateUint64MetaDataToMaxValue SetMaxNBarrierCnt{
1027
+ *F->getParent (), genx::KernelMDOp::NBarrierCnt, NewVal};
1028
+ traverseCallgraphUp (F, SetMaxNBarrierCnt);
983
1029
}
984
1030
985
1031
static void translatePackMask (CallInst &CI) {
@@ -1099,6 +1145,33 @@ static void translateGetSurfaceIndex(CallInst &CI) {
1099
1145
CI.replaceAllUsesWith (SI);
1100
1146
}
1101
1147
1148
+ // Kernel property identifiers. Should match ones in
1149
+ // sycl/include/sycl/ext/intel/experimental/esimd/kernel_properties.hpp
1150
+ enum property_ids { use_double_grf = 0 };
1151
+
1152
+ static void translateSetKernelProperties (CallInst &CI) {
1153
+ auto F = CI.getFunction ();
1154
+ auto *ArgV = CI.getArgOperand (0 );
1155
+ if (!isa<ConstantInt>(ArgV))
1156
+ llvm::report_fatal_error (
1157
+ llvm::Twine (__FILE__ " " ) +
1158
+ " integral constant is expected for set_kernel_properties" );
1159
+ uint64_t PropID = cast<llvm::ConstantInt>(ArgV)->getZExtValue ();
1160
+
1161
+ switch (PropID) {
1162
+ case property_ids::use_double_grf:
1163
+ traverseCallgraphUp (F, [](Function *GraphNode) {
1164
+ if (!isESIMDKernel (*GraphNode)) {
1165
+ return ;
1166
+ }
1167
+ GraphNode->addFnAttr (ATTR_DOUBLE_GRF);
1168
+ });
1169
+ break ;
1170
+ default :
1171
+ assert (false && " Invalid property id" );
1172
+ }
1173
+ }
1174
+
1102
1175
// Newly created GenX intrinsic might have different return type than expected.
1103
1176
// This helper function creates cast operation from GenX intrinsic return type
1104
1177
// to currently expected. Returns pointer to created cast instruction if it
@@ -1514,8 +1587,7 @@ void generateKernelMetadata(Module &M) {
1514
1587
1515
1588
for (auto &F : M.functions ()) {
1516
1589
// Skip non-SIMD kernels.
1517
- if (F.getCallingConv () != CallingConv::SPIR_KERNEL ||
1518
- F.getMetadata (" sycl_explicit_simd" ) == nullptr )
1590
+ if (!isESIMDKernel (F))
1519
1591
continue ;
1520
1592
1521
1593
// Metadata node containing N i32s, where N is the number of kernel
@@ -1708,15 +1780,14 @@ size_t SYCLLowerESIMDPass::runOnFunction(Function &F,
1708
1780
1709
1781
// process ESIMD builtins that go through special handling instead of
1710
1782
// the translation procedure
1711
- // TODO FIXME slm_init should be made top-level __esimd_slm_init
1783
+
1712
1784
if (Name.startswith (" __esimd_slm_init" ) &&
1713
1785
isa<ConstantInt>(CI->getArgOperand (0 ))) {
1714
1786
// tag the kernel with meta-data SLMSize, and remove this builtin
1715
1787
translateSLMInit (*CI);
1716
1788
ToErase.push_back (CI);
1717
1789
continue ;
1718
1790
}
1719
-
1720
1791
if (Name.startswith (" __esimd_nbarrier_init" )) {
1721
1792
translateNbarrierInit (*CI);
1722
1793
ToErase.push_back (CI);
@@ -1748,12 +1819,16 @@ size_t SYCLLowerESIMDPass::runOnFunction(Function &F,
1748
1819
continue ;
1749
1820
}
1750
1821
}
1751
-
1752
1822
if (Name.startswith (" __esimd_get_surface_index" )) {
1753
1823
translateGetSurfaceIndex (*CI);
1754
1824
ToErase.push_back (CI);
1755
1825
continue ;
1756
1826
}
1827
+ if (Name.startswith (" __esimd_set_kernel_properties" )) {
1828
+ translateSetKernelProperties (*CI);
1829
+ ToErase.push_back (CI);
1830
+ continue ;
1831
+ }
1757
1832
1758
1833
if (Name.empty () || !Name.startswith (ESIMD_INTRIN_PREF1))
1759
1834
continue ;
0 commit comments