@@ -307,13 +307,19 @@ class SPIRVInstructionSelector : public InstructionSelector {
307307  bool  selectHandleFromBinding (Register &ResVReg, const  SPIRVType *ResType,
308308                               MachineInstr &I) const ;
309309
310+   bool  selectCounterHandleFromBinding (Register &ResVReg,
311+                                       const  SPIRVType *ResType,
312+                                       MachineInstr &I) const ;
313+ 
310314  bool  selectReadImageIntrinsic (Register &ResVReg, const  SPIRVType *ResType,
311315                                MachineInstr &I) const ;
312316  bool  selectImageWriteIntrinsic (MachineInstr &I) const ;
313317  bool  selectResourceGetPointer (Register &ResVReg, const  SPIRVType *ResType,
314318                                MachineInstr &I) const ;
315319  bool  selectModf (Register ResVReg, const  SPIRVType *ResType,
316320                  MachineInstr &I) const ;
321+   bool  selectUpdateCounter (Register &ResVReg, const  SPIRVType *ResType,
322+                            MachineInstr &I) const ;
317323  bool  selectFrexp (Register ResVReg, const  SPIRVType *ResType,
318324                   MachineInstr &I) const ;
319325  //  Utilities
@@ -3443,6 +3449,10 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
34433449  case  Intrinsic::spv_resource_handlefrombinding: {
34443450    return  selectHandleFromBinding (ResVReg, ResType, I);
34453451  }
3452+   case  Intrinsic::spv_resource_counterhandlefrombinding:
3453+     return  selectCounterHandleFromBinding (ResVReg, ResType, I);
3454+   case  Intrinsic::spv_resource_updatecounter:
3455+     return  selectUpdateCounter (ResVReg, ResType, I);
34463456  case  Intrinsic::spv_resource_store_typedbuffer: {
34473457    return  selectImageWriteIntrinsic (I);
34483458  }
@@ -3478,6 +3488,130 @@ bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
34783488                                  *cast<GIntrinsic>(&I), I);
34793489}
34803490
3491+ bool  SPIRVInstructionSelector::selectCounterHandleFromBinding (
3492+     Register &ResVReg, const  SPIRVType *ResType, MachineInstr &I) const  {
3493+   auto  &Intr = cast<GIntrinsic>(I);
3494+   assert (Intr.getIntrinsicID () ==
3495+          Intrinsic::spv_resource_counterhandlefrombinding);
3496+ 
3497+   //  Extract information from the intrinsic call.
3498+   Register MainHandleReg = Intr.getOperand (2 ).getReg ();
3499+   auto  *MainHandleDef = cast<GIntrinsic>(getVRegDef (*MRI, MainHandleReg));
3500+   assert (MainHandleDef->getIntrinsicID () ==
3501+          Intrinsic::spv_resource_handlefrombinding);
3502+ 
3503+   uint32_t  Set = getIConstVal (Intr.getOperand (4 ).getReg (), MRI);
3504+   uint32_t  Binding = getIConstVal (Intr.getOperand (3 ).getReg (), MRI);
3505+   uint32_t  ArraySize = getIConstVal (MainHandleDef->getOperand (4 ).getReg (), MRI);
3506+   Register IndexReg = MainHandleDef->getOperand (5 ).getReg ();
3507+   const  bool  IsNonUniform = false ;
3508+   std::string CounterName =
3509+       getStringValueFromReg (MainHandleDef->getOperand (6 ).getReg (), *MRI) +
3510+       " .counter"  ;
3511+ 
3512+   //  Create the counter variable.
3513+   MachineIRBuilder MIRBuilder (I);
3514+   Register CounterVarReg = buildPointerToResource (
3515+       GR.getPointeeType (ResType), GR.getPointerStorageClass (ResType), Set,
3516+       Binding, ArraySize, IndexReg, IsNonUniform, CounterName, MIRBuilder);
3517+ 
3518+   return  BuildCOPY (ResVReg, CounterVarReg, I);
3519+ }
3520+ 
3521+ bool  SPIRVInstructionSelector::selectUpdateCounter (Register &ResVReg,
3522+                                                    const  SPIRVType *ResType,
3523+                                                    MachineInstr &I) const  {
3524+   auto  &Intr = cast<GIntrinsic>(I);
3525+   assert (Intr.getIntrinsicID () == Intrinsic::spv_resource_updatecounter);
3526+ 
3527+   Register CounterHandleReg = Intr.getOperand (2 ).getReg ();
3528+   Register IncrReg = Intr.getOperand (3 ).getReg ();
3529+ 
3530+   //  The counter handle is a pointer to the counter variable (which is a struct
3531+   //  containing an i32). We need to get a pointer to that i32 member to do the
3532+   //  atomic operation.
3533+ #ifndef  NDEBUG
3534+   SPIRVType *CounterVarType = GR.getSPIRVTypeForVReg (CounterHandleReg);
3535+   SPIRVType *CounterVarPointeeType = GR.getPointeeType (CounterVarType);
3536+   assert (CounterVarPointeeType &&
3537+          CounterVarPointeeType->getOpcode () == SPIRV::OpTypeStruct &&
3538+          " Counter variable must be a struct"  );
3539+   assert (GR.getPointerStorageClass (CounterVarType) ==
3540+              SPIRV::StorageClass::StorageBuffer &&
3541+          " Counter variable must be in the storage buffer storage class"  );
3542+   assert (CounterVarPointeeType->getNumOperands () == 2  &&
3543+          " Counter variable must have exactly 1 member in the struct"  );
3544+   const  SPIRVType *MemberType =
3545+       GR.getSPIRVTypeForVReg (CounterVarPointeeType->getOperand (1 ).getReg ());
3546+   assert (MemberType->getOpcode () == SPIRV::OpTypeInt &&
3547+          " Counter variable struct must have a single i32 member"  );
3548+ #endif 
3549+ 
3550+   //  The struct has a single i32 member.
3551+   MachineIRBuilder MIRBuilder (I);
3552+   const  Type *LLVMIntType =
3553+       Type::getInt32Ty (I.getMF ()->getFunction ().getContext ());
3554+ 
3555+   SPIRVType *IntPtrType = GR.getOrCreateSPIRVPointerType (
3556+       LLVMIntType, MIRBuilder, SPIRV::StorageClass::StorageBuffer);
3557+ 
3558+   auto  Zero = buildI32Constant (0 , I);
3559+   if  (!Zero.second )
3560+     return  false ;
3561+ 
3562+   Register PtrToCounter =
3563+       MRI->createVirtualRegister (GR.getRegClass (IntPtrType));
3564+   if  (!BuildMI (*I.getParent (), I, I.getDebugLoc (),
3565+                TII.get (SPIRV::OpAccessChain))
3566+            .addDef (PtrToCounter)
3567+            .addUse (GR.getSPIRVTypeID (IntPtrType))
3568+            .addUse (CounterHandleReg)
3569+            .addUse (Zero.first )
3570+            .constrainAllUses (TII, TRI, RBI)) {
3571+     return  false ;
3572+   }
3573+ 
3574+   //  For UAV/SSBO counters, the scope is Device. The counter variable is not
3575+   //  used as a flag. So the memory semantics can be None.
3576+   auto  Scope = buildI32Constant (SPIRV::Scope::Device, I);
3577+   if  (!Scope.second )
3578+     return  false ;
3579+   auto  Semantics = buildI32Constant (SPIRV::MemorySemantics::None, I);
3580+   if  (!Semantics.second )
3581+     return  false ;
3582+ 
3583+   int64_t  IncrVal = getIConstValSext (IncrReg, MRI);
3584+   auto  Incr = buildI32Constant (static_cast <uint32_t >(IncrVal), I);
3585+   if  (!Incr.second )
3586+     return  false ;
3587+ 
3588+   Register AtomicRes = MRI->createVirtualRegister (GR.getRegClass (ResType));
3589+   if  (!BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpAtomicIAdd))
3590+            .addDef (AtomicRes)
3591+            .addUse (GR.getSPIRVTypeID (ResType))
3592+            .addUse (PtrToCounter)
3593+            .addUse (Scope.first )
3594+            .addUse (Semantics.first )
3595+            .addUse (Incr.first )
3596+            .constrainAllUses (TII, TRI, RBI)) {
3597+     return  false ;
3598+   }
3599+   if  (IncrVal >= 0 ) {
3600+     return  BuildCOPY (ResVReg, AtomicRes, I);
3601+   }
3602+ 
3603+   //  In HLSL, IncrementCounter returns the value *before* the increment, while
3604+   //  DecrementCounter returns the value *after* the decrement. Both are lowered
3605+   //  to the same atomic intrinsic which returns the value *before* the
3606+   //  operation. So for decrements (negative IncrVal), we must subtract the
3607+   //  increment value from the result to get the post-decrement value.
3608+   return  BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpIAddS))
3609+       .addDef (ResVReg)
3610+       .addUse (GR.getSPIRVTypeID (ResType))
3611+       .addUse (AtomicRes)
3612+       .addUse (Incr.first )
3613+       .constrainAllUses (TII, TRI, RBI);
3614+ }
34813615bool  SPIRVInstructionSelector::selectReadImageIntrinsic (
34823616    Register &ResVReg, const  SPIRVType *ResType, MachineInstr &I) const  {
34833617
0 commit comments