@@ -233,10 +233,14 @@ class MTLPipelineState : public offloadtest::PipelineState {
233233 std::string Name;
234234 IRRootSignaturePtr RootSig;
235235 std::unique_ptr<MTLTopLevelArgumentBuffer> ArgBuffer;
236- IRShaderReflectionPtr Reflection;
237236 MTL ::ComputePipelineState *ComputePipeline = nullptr ;
238237 MTL ::RenderPipelineState *RenderPipeline = nullptr ;
239238
239+ // Compute pipeline only state. Threadgroup size comes from numthreads() in
240+ // the HLSL source and is captured from shader reflection at pipeline
241+ // creation, so dispatch() doesn't need to re-query reflection each time.
242+ MTL ::Size ThreadsPerGroup = MTL ::Size(1 , 1 , 1 );
243+
240244 // Rasterization pipeline only state.
241245 // These are part of the pipeline in DX and VK, but dynamic state in Metal.
242246 // To have a shared API we store these here and set the state when the
@@ -246,11 +250,11 @@ class MTLPipelineState : public offloadtest::PipelineState {
246250
247251 MTLPipelineState (llvm::StringRef Name, IRRootSignaturePtr RootSig,
248252 std::unique_ptr<MTLTopLevelArgumentBuffer> ArgBuffer,
249- IRShaderReflectionPtr Reflection ,
250- MTL ::ComputePipelineState *ComputePipeline )
253+ MTL ::ComputePipelineState *ComputePipeline ,
254+ MTL ::Size ThreadsPerGroup )
251255 : offloadtest::PipelineState(GPUAPI ::Metal), Name(Name),
252256 RootSig(std::move(RootSig)), ArgBuffer(std::move(ArgBuffer)),
253- Reflection(std::move(Reflection)), ComputePipeline(ComputePipeline ) {}
257+ ComputePipeline(ComputePipeline), ThreadsPerGroup(ThreadsPerGroup ) {}
254258
255259 MTLPipelineState (llvm::StringRef Name, IRRootSignaturePtr RootSig,
256260 std::unique_ptr<MTLTopLevelArgumentBuffer> ArgBuffer,
@@ -416,11 +420,6 @@ class MTLComputeEncoder : public offloadtest::ComputeEncoder {
416420 MTL ::ComputeCommandEncoder *ComputeEnc = nullptr ;
417421 MTL ::BlitCommandEncoder *BlitEnc = nullptr ;
418422
419- // / Threadgroup size from shader reflection (the numthreads() attribute
420- // / persisted in the transpiled Metallib). Must be set via
421- // / setThreadGroupSize() before dispatching.
422- MTL ::Size ThreadsPerGroup = {1 , 1 , 1 };
423-
424423 // / Accumulated barrier scope from commands recorded since the last barrier.
425424 MTL ::BarrierScope PendingScope = MTL ::BarrierScope(0 );
426425
@@ -477,13 +476,6 @@ class MTLComputeEncoder : public offloadtest::ComputeEncoder {
477476
478477 MTL ::ComputeCommandEncoder *getNative () const { return ComputeEnc; }
479478
480- // / Set the threadgroup size for subsequent dispatch calls. The values must
481- // / come from shader reflection (the numthreads() attribute in the HLSL
482- // / source, persisted in the transpiled Metallib).
483- void setThreadGroupSize (NS ::UInteger X, NS ::UInteger Y, NS ::UInteger Z) {
484- ThreadsPerGroup = MTL::Size (X, Y, Z);
485- }
486-
487479 MTL ::CommandEncoder *getActiveEncoder () const {
488480 if (ComputeEnc)
489481 return ComputeEnc;
@@ -507,18 +499,26 @@ class MTLComputeEncoder : public offloadtest::ComputeEncoder {
507499 NS::String::string (Label.data(), NS::UTF8StringEncoding));
508500 }
509501
510- llvm::Error dispatch (uint32_t GroupCountX, uint32_t GroupCountY,
502+ llvm::Error dispatch (const offloadtest::PipelineState &PSO ,
503+ uint32_t GroupCountX, uint32_t GroupCountY,
511504 uint32_t GroupCountZ) override {
505+ const auto &MTLPSO = llvm::cast<MTLPipelineState>(PSO );
506+ if (!MTLPSO .ComputePipeline )
507+ return llvm::createStringError (
508+ std::errc::invalid_argument,
509+ " PipelineState bound to dispatch() is not a compute pipeline." );
512510 if (auto Err = ensureComputeEncoder ())
513511 return Err;
514512 flushBarrier ();
515513 insertDebugSignpost (llvm::formatv (" Dispatch [{0},{1},{2}]" , GroupCountX,
516514 GroupCountY, GroupCountZ)
517515 .str ());
518- const MTL ::Size GridSize (ThreadsPerGroup.width * GroupCountX,
519- ThreadsPerGroup.height * GroupCountY,
520- ThreadsPerGroup.depth * GroupCountZ);
521- ComputeEnc->dispatchThreads (GridSize, ThreadsPerGroup);
516+ ComputeEnc->setComputePipelineState (MTLPSO .ComputePipeline );
517+
518+ const MTL ::Size GridSize (MTLPSO .ThreadsPerGroup .width * GroupCountX,
519+ MTLPSO .ThreadsPerGroup .height * GroupCountY,
520+ MTLPSO .ThreadsPerGroup .depth * GroupCountZ);
521+ ComputeEnc->dispatchThreads (GridSize, MTLPSO .ThreadsPerGroup );
522522 addBarrierScope (MTL ::BarrierScopeBuffers | MTL ::BarrierScopeTextures);
523523 return llvm::Error::success ();
524524 }
@@ -1255,7 +1255,6 @@ class MTLDevice : public offloadtest::Device {
12551255 MTL ::ComputeCommandEncoder *NativeEncoder = Encoder.getNative ();
12561256
12571257 const auto &PS = llvm::cast<MTLPipelineState>(IS .Pipeline .get ());
1258- NativeEncoder->setComputePipelineState (PS ->ComputePipeline );
12591258 MTLGPUDescriptorHandle Handle = {};
12601259 if (IS .DescHeap ) {
12611260 IS .DescHeap ->bind (NativeEncoder);
@@ -1275,21 +1274,8 @@ class MTLDevice : public offloadtest::Device {
12751274 MTL ::ResourceUsageRead |
12761275 MTL ::ResourceUsageWrite);
12771276
1278- NS ::UInteger TGS [3 ] = {PS ->ComputePipeline ->maxTotalThreadsPerThreadgroup (),
1279- 1 , 1 };
1280- if (PS ->Reflection ) {
1281- IRVersionedCSInfo Info;
1282- if (IRShaderReflectionCopyComputeInfo (PS ->Reflection .get (),
1283- IRReflectionVersion_1_0, &Info)) {
1284- TGS [0 ] = Info.info_1_0 .tg_size [0 ];
1285- TGS [1 ] = Info.info_1_0 .tg_size [1 ];
1286- TGS [2 ] = Info.info_1_0 .tg_size [2 ];
1287- }
1288- IRShaderReflectionReleaseComputeInfo (&Info);
1289- }
1290- Encoder.setThreadGroupSize (TGS [0 ], TGS [1 ], TGS [2 ]);
1291-
1292- if (auto Err = Encoder.dispatch (P.DispatchParameters .DispatchGroupCount [0 ],
1277+ if (auto Err = Encoder.dispatch (*IS .Pipeline .get (),
1278+ P.DispatchParameters .DispatchGroupCount [0 ],
12931279 P.DispatchParameters .DispatchGroupCount [1 ],
12941280 P.DispatchParameters .DispatchGroupCount [2 ]))
12951281 return Err;
@@ -1542,9 +1528,21 @@ class MTLDevice : public offloadtest::Device {
15421528 if (Error)
15431529 return toError (Error);
15441530
1545- return std::make_unique<MTLPipelineState>(
1546- Name, std::move (RootSig), std::move (ArgBuffer),
1547- std::move (MetalIR->Reflection ), PSO );
1531+ IRVersionedCSInfo Info;
1532+ if (!IRShaderReflectionCopyComputeInfo (MetalIR->Reflection .get (),
1533+ IRReflectionVersion_1_0, &Info))
1534+ return llvm::createStringError (
1535+ " Failed to read compute reflection for entry point '%s'; cannot "
1536+ " determine threadgroup size from numthreads()." ,
1537+ CS .EntryPoint .c_str ());
1538+ const MTL ::Size ThreadsPerGroup (Info.info_1_0 .tg_size [0 ],
1539+ Info.info_1_0 .tg_size [1 ],
1540+ Info.info_1_0 .tg_size [2 ]);
1541+ IRShaderReflectionReleaseComputeInfo (&Info);
1542+
1543+ return std::make_unique<MTLPipelineState>(Name, std::move (RootSig),
1544+ std::move (ArgBuffer), PSO ,
1545+ ThreadsPerGroup);
15481546 }
15491547
15501548 llvm::Expected<std::unique_ptr<PipelineState>>
0 commit comments