@@ -410,4 +410,96 @@ void validateIRModuleIfEnabled(CodeGenContext* codeGenContext, IRModule* module)
410
410
validateIRModule (module, sink);
411
411
}
412
412
413
+ // Returns whether 'dst' is a valid destination for atomic operations, meaning
414
+ // it leads either to 'groupshared' or 'device buffer' memory.
415
+ static bool isValidAtomicDest (IRInst* dst)
416
+ {
417
+ bool isGroupShared = as<IRGroupSharedRate>(dst->getRate ());
418
+ if (isGroupShared)
419
+ return true ;
420
+
421
+ if (as<IRRWStructuredBufferGetElementPtr>(dst))
422
+ return true ;
423
+ if (as<IRImageSubscript>(dst))
424
+ return true ;
425
+
426
+ if (auto ptrType = as<IRPtrType>(dst->getDataType ()))
427
+ {
428
+ switch (ptrType->getAddressSpace ())
429
+ {
430
+ case AddressSpace::Global:
431
+ case AddressSpace::GroupShared:
432
+ case AddressSpace::StorageBuffer:
433
+ case AddressSpace::UserPointer:
434
+ return true ;
435
+ default :
436
+ break ;
437
+ }
438
+ }
439
+
440
+ if (as<IRGlobalParam>(dst))
441
+ {
442
+ switch (dst->getDataType ()->getOp ())
443
+ {
444
+ case kIROp_GLSLShaderStorageBufferType :
445
+ case kIROp_TextureType :
446
+ return true ;
447
+ default :
448
+ return false ;
449
+ }
450
+ }
451
+
452
+ if (auto param = as<IRParam>(dst))
453
+ if (auto outType = as<IROutTypeBase>(param->getDataType ()))
454
+ if (outType->getAddressSpace () == AddressSpace::GroupShared)
455
+ return true ;
456
+ if (auto getElementPtr = as<IRGetElementPtr>(dst))
457
+ return isValidAtomicDest (getElementPtr->getBase ());
458
+ if (auto getOffsetPtr = as<IRGetOffsetPtr>(dst))
459
+ return isValidAtomicDest (getOffsetPtr->getBase ());
460
+ if (auto fieldAddress = as<IRFieldAddress>(dst))
461
+ return isValidAtomicDest (fieldAddress->getBase ());
462
+
463
+ return false ;
464
+ }
465
+
466
+ void validateAtomicOperations (DiagnosticSink* sink, IRInst* inst)
467
+ {
468
+ // There may be unused functions containing violations after address space specialization.
469
+ if (auto func = as<IRFunc>(inst))
470
+ if (!(func->hasUses () || func->findDecoration <IREntryPointDecoration>()))
471
+ return ;
472
+
473
+ switch (inst->getOp ())
474
+ {
475
+ case kIROp_AtomicLoad :
476
+ case kIROp_AtomicStore :
477
+ case kIROp_AtomicExchange :
478
+ case kIROp_AtomicCompareExchange :
479
+ case kIROp_AtomicAdd :
480
+ case kIROp_AtomicSub :
481
+ case kIROp_AtomicAnd :
482
+ case kIROp_AtomicOr :
483
+ case kIROp_AtomicXor :
484
+ case kIROp_AtomicMin :
485
+ case kIROp_AtomicMax :
486
+ case kIROp_AtomicInc :
487
+ case kIROp_AtomicDec :
488
+ {
489
+ IRInst* destinationPtr = inst->getOperand (0 );
490
+ if (!isValidAtomicDest (destinationPtr))
491
+ sink->diagnose (inst->sourceLoc , Diagnostics::invalidAtomicDestinationPointer);
492
+ }
493
+ break ;
494
+
495
+ default :
496
+ break ;
497
+ }
498
+
499
+ for (auto child : inst->getModifiableChildren ())
500
+ {
501
+ validateAtomicOperations (sink, child);
502
+ }
503
+ }
504
+
413
505
} // namespace Slang
0 commit comments