@@ -184,6 +184,42 @@ void HandleSpirvDecorationMetadata::visitPrefetchCallInst(CallInst& I)
184184 }
185185}
186186
187+ void HandleSpirvDecorationMetadata::visit1DBlockReadCallInst (CallInst& I)
188+ {
189+ Value* ptr = I.getArgOperand (0 );
190+ auto spirvDecorations = parseSPIRVDecorationsFromMD (ptr);
191+ for (auto & [DecorationId, MDNodes] : spirvDecorations)
192+ {
193+ switch (DecorationId)
194+ {
195+ // IDecCacheControlLoadINTEL
196+ case DecorationIdCacheControlLoad:
197+ {
198+ handleCacheControlINTELFor1DBlockIO<LoadCacheControl>(I, MDNodes);
199+ break ;
200+ }
201+ }
202+ }
203+ }
204+
205+ void HandleSpirvDecorationMetadata::visit1DBlockWriteCallInst (CallInst& I)
206+ {
207+ Value* ptr = I.getArgOperand (0 );
208+ auto spirvDecorations = parseSPIRVDecorationsFromMD (ptr);
209+ for (auto & [DecorationId, MDNodes] : spirvDecorations)
210+ {
211+ switch (DecorationId)
212+ {
213+ // IDecCacheControlStoreINTEL
214+ case DecorationIdCacheControlStore:
215+ {
216+ handleCacheControlINTELFor1DBlockIO<StoreCacheControl>(I, MDNodes);
217+ break ;
218+ }
219+ }
220+ }
221+ }
222+
187223void HandleSpirvDecorationMetadata::visitCallInst (CallInst& I)
188224{
189225 Function* F = I.getCalledFunction ();
@@ -195,8 +231,12 @@ void HandleSpirvDecorationMetadata::visitCallInst(CallInst& I)
195231 " _Z[0-9]+(intel_sub_group_2d_block_write_[0-9]+b_[0-9]+r[0-9]+x[0-9]+c)" );
196232#if defined(IGC_SCALAR_USE_KHRONOS_SPIRV_TRANSLATOR)
197233 Regex patternPrefetch (" _Z[0-9]+__spirv_ocl_prefetch" );
234+ Regex pattern1DBlockRead (" _Z[0-9]+__spirv_SubgroupBlockReadINTEL" );
235+ Regex pattern1DBlockWrite (" _Z[0-9]+__spirv_SubgroupBlockWriteINTEL" );
198236#else // IGC Legacy SPIRV Translator
199237 Regex patternPrefetch (" __builtin_spirv_OpenCL_prefetch" );
238+ Regex pattern1DBlockRead (" __builtin_spirv_OpSubgroupBlockReadINTEL" );
239+ Regex pattern1DBlockWrite (" __builtin_spirv_OpSubgroupBlockWriteINTEL" );
200240#endif
201241
202242 SmallVector<StringRef, 4 > Matches;
@@ -214,6 +254,14 @@ void HandleSpirvDecorationMetadata::visitCallInst(CallInst& I)
214254 {
215255 visitPrefetchCallInst (I);
216256 }
257+ else if (pattern1DBlockRead.match (funcName, &Matches))
258+ {
259+ visit1DBlockReadCallInst (I);
260+ }
261+ else if (pattern1DBlockWrite.match (funcName, &Matches))
262+ {
263+ visit1DBlockWriteCallInst (I);
264+ }
217265}
218266
219267template <typename T>
@@ -327,3 +375,86 @@ void HandleSpirvDecorationMetadata::handleCacheControlINTELForPrefetch(llvm::Cal
327375 if (F->getNumUses () == 0 )
328376 m_BuiltinsToRemove.insert (F);
329377}
378+
379+ template <typename T>
380+ void HandleSpirvDecorationMetadata::handleCacheControlINTELFor1DBlockIO (CallInst& I, SmallPtrSetImpl<MDNode*>& MDNodes)
381+ {
382+ static_assert (std::is_same_v<T, LoadCacheControl> || std::is_same_v<T, StoreCacheControl>);
383+ CacheControlFromMDNodes cacheControl = resolveCacheControlFromMDNodes<T>(m_pCtx, MDNodes);
384+ if (cacheControl.isEmpty ) return ;
385+ if (cacheControl.isInvalid )
386+ {
387+ m_pCtx->EmitWarning (" Unsupported cache controls configuration requested. Applying default configuration." );
388+ return ;
389+ }
390+
391+ Function* F = I.getCalledFunction ();
392+ IGC_ASSERT (F);
393+
394+ Type* operationType = nullptr ;
395+ std::string funcName;
396+ if constexpr (std::is_same_v<T, LoadCacheControl>)
397+ {
398+ operationType = I.getType ();
399+ funcName = " SubgroupBlockReadINTEL" ;
400+ }
401+ else
402+ {
403+ operationType = I.getArgOperand (1 )->getType ();
404+ funcName = " SubgroupBlockWriteINTEL" ;
405+ }
406+
407+ std::string typeName;
408+ uint32_t numElements = 1 ;
409+ Type* elementType = operationType;
410+ if (auto * vecTy = dyn_cast<IGCLLVM::FixedVectorType>(operationType))
411+ {
412+ numElements = (uint32_t )vecTy->getNumElements ();
413+ elementType = vecTy->getElementType ();
414+ }
415+
416+ if (elementType->isIntegerTy ())
417+ {
418+ switch (elementType->getIntegerBitWidth ())
419+ {
420+ case 8 :
421+ typeName = " char" ;
422+ break ;
423+ case 16 :
424+ typeName = " short" ;
425+ break ;
426+ case 32 :
427+ typeName = " int" ;
428+ break ;
429+ case 64 :
430+ typeName = " long" ;
431+ break ;
432+ default :
433+ IGC_ASSERT (0 && " Unsupported integer type" );
434+ break ;
435+ }
436+ }
437+
438+ if (numElements > 1 )
439+ typeName += std::to_string (numElements);
440+
441+ SmallVector<Value*, 3 > args (I.args ());
442+ args.push_back (ConstantInt::get (Type::getInt32Ty (I.getContext ()), cacheControl.value ));
443+
444+ SmallVector<Type*, 3 > argTypes;
445+ for (const auto & arg : args)
446+ argTypes.push_back (arg->getType ());
447+
448+ FunctionType* funcTy = FunctionType::get (I.getType (), argTypes, false );
449+ std::string newFuncName = " __internal_" + funcName + " _" + typeName + " _cache_controls" ;
450+ auto newFunction = m_Module->getOrInsertFunction (newFuncName, funcTy);
451+
452+ auto newCall = CallInst::Create (newFunction, args, " " , &I);
453+ I.replaceAllUsesWith (newCall);
454+ I.eraseFromParent ();
455+ m_changed = true ;
456+
457+ // Cleanup unused function if all calls have been replaced with the internal version
458+ if (F->getNumUses () == 0 )
459+ m_BuiltinsToRemove.insert (F);
460+ }
0 commit comments