Repository: gem5/gem5
Pull request #2272: gpu-compute,arch-vega: Included two new DS instructions
Author: login: german-v-t-um-es
Labels: name: arch-vega
description: The VEGA ISA
name: gpu-compute
description: gem5's GPU Compute Code
Created: 2025-05-14T21:56:16Z | Merged: 2025-05-22T02:20:41Z

While testing benchmarks on the FS gfx90a model, I needed to add support for two new ds instructions to ensure correct execution. Additionally, since the benchmarks made use of both v_mbcnt_lo_u32_b32 and v_mbcnt_hi_u32_b32, I added REG_EXEC_HI to the relevant register switch-case to properly support these instructions.


Diff:
diff --git a/src/arch/amdgpu/vega/gpu_registers.cc b/src/arch/amdgpu/vega/gpu_registers.cc
index 302a89e2b88..c1a119de2ad 100644
--- a/src/arch/amdgpu/vega/gpu_registers.cc
+++ b/src/arch/amdgpu/vega/gpu_registers.cc
@@ -86,6 +86,9 @@ namespace VegaISA
           case REG_EXEC_LO:
             reg_sym = "exec";
             break;
+          case REG_EXEC_HI:
+            reg_sym = "exec";
+            break;
           case REG_ZERO:
             reg_sym = "0";
             break;
diff --git a/src/arch/amdgpu/vega/insts/ds.cc b/src/arch/amdgpu/vega/insts/ds.cc
index efc8db2d53e..45ac49ef822 100644
--- a/src/arch/amdgpu/vega/insts/ds.cc
+++ b/src/arch/amdgpu/vega/insts/ds.cc
@@ -986,6 +986,9 @@ namespace VegaISA
     Inst_DS__DS_ADD_RTN_U32::Inst_DS__DS_ADD_RTN_U32(InFmt_DS *iFmt)
         : Inst_DS(iFmt, "ds_add_rtn_u32")
     {
+        setFlag(MemoryRef);
+        setFlag(AtomicAdd);
+        setFlag(AtomicReturn);
     } // Inst_DS__DS_ADD_RTN_U32
 
     Inst_DS__DS_ADD_RTN_U32::~Inst_DS__DS_ADD_RTN_U32()
@@ -1000,8 +1003,59 @@ namespace VegaISA
     void
     Inst_DS__DS_ADD_RTN_U32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 data(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        data.read();
+
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = data[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
     } // execute
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
+
+        initAtomicAccess<VecElemU32>(gpuDynInst, offset);
+    } // initiateAcc
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::completeAcc(GPUDynInstPtr gpuDynInst)
+    {
+        VecOperandU32 vdst(gpuDynInst, extData.VDST);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                vdst[lane] = (reinterpret_cast<VecElemU32*>(
+                    gpuDynInst->d_data))[lane];
+            }
+        }
+
+        vdst.write();
+    } // completeAcc
     // --- Inst_DS__DS_SUB_RTN_U32 class methods ---
 
     Inst_DS__DS_SUB_RTN_U32::Inst_DS__DS_SUB_RTN_U32(InFmt_DS *iFmt)
@@ -1319,6 +1373,9 @@ namespace VegaISA
     Inst_DS__DS_CMPST_RTN_B32::Inst_DS__DS_CMPST_RTN_B32(InFmt_DS *iFmt)
         : Inst_DS(iFmt, "ds_cmpst_rtn_b32")
     {
+        setFlag(MemoryRef);
+        setFlag(AtomicCAS);
+        setFlag(AtomicReturn);
     } // Inst_DS__DS_CMPST_RTN_B32
 
     Inst_DS__DS_CMPST_RTN_B32::~Inst_DS__DS_CMPST_RTN_B32()
@@ -1338,10 +1395,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
+
     } // execute
     // --- Inst_DS__DS_CMPST_RTN_F32 class methods ---
 
+    void
+    Inst_DS__DS_CMPST_RTN_B32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
+
+        initAtomicAccess<VecElemU32>(gpuDynInst, offset);
+    } // initiateAcc
+
+    void
+    Inst_DS__DS_CMPST_RTN_B32::completeAcc(GPUDynInstPtr gpuDynInst)
+    {
+        VecOperandU32 vdst(gpuDynInst, extData.VDST);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                vdst[lane] = (reinterpret_cast<VecElemU32*>(
+                    gpuDynInst->d_data))[lane];
+            }
+        }
+
+        vdst.write();
+    } // completeAcc
+    // --- Inst_DS__DS_CMPST_RTN_F32 class methods ---
+
     Inst_DS__DS_CMPST_RTN_F32::Inst_DS__DS_CMPST_RTN_F32(InFmt_DS *iFmt)
         : Inst_DS(iFmt, "ds_cmpst_rtn_f32")
     {
diff --git a/src/arch/amdgpu/vega/insts/instructions.hh b/src/arch/amdgpu/vega/insts/instructions.hh
index 62a400d31e3..7a328f9230b 100644
--- a/src/arch/amdgpu/vega/insts/instructions.hh
+++ b/src/arch/amdgpu/vega/insts/instructions.hh
@@ -32276,6 +32276,8 @@ namespace VegaISA
         } // getOperandSize
 
         void execute(GPUDynInstPtr) override;
+        void initiateAcc(GPUDynInstPtr) override;
+        void completeAcc(GPUDynInstPtr) override;
     }; // Inst_DS__DS_ADD_RTN_U32
 
     class Inst_DS__DS_SUB_RTN_U32 : public Inst_DS
@@ -32809,9 +32811,11 @@ namespace VegaISA
             switch (opIdx) {
               case 0: //vgpr_a
                 return 4;
-              case 1: //vgpr_d1
+              case 1: //vgpr_d0
                 return 4;
-              case 2: //vgpr_rtn
+              case 2: //vgpr_d1
+                return 4;
+              case 3: //vgpr_rtn
                 return 4;
               default:
                 fatal("op idx %i out of bounds\n", opIdx);
@@ -32820,6 +32824,8 @@ namespace VegaISA
         } // getOperandSize
 
         void execute(GPUDynInstPtr) override;
+        void initiateAcc(GPUDynInstPtr) override;
+        void completeAcc(GPUDynInstPtr) override;
     }; // Inst_DS__DS_CMPST_RTN_B32
 
     class Inst_DS__DS_CMPST_RTN_F32 : public Inst_DS


Reviews:
user: login: mattsinc
body: thanks @german-v-t-um-es !  A couple small things
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T13:52:51Z
user: login: abmerop
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T17:27:44Z
user: login: german-v-t-um-es
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T09:01:19Z
user: login: german-v-t-um-es
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T09:02:16Z
user: login: german-v-t-um-es
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T09:41:35Z
user: login: german-v-t-um-es
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T09:55:06Z
user: login: abmerop
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T16:39:17Z
user: login: mattsinc
body: since @abmerop had questions about the order of the CAS lines, he should also approve before we merge
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-18T18:17:51Z
user: login: abmerop
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-18T18:23:42Z

Review comments:
diff_hunk: @@ -1000,8 +1003,60 @@ namespace VegaISA
     void
     Inst_DS__DS_ADD_RTN_U32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: mattsinc
body: it would be better if we weren't using magic numbers like 24 here, but at the same time I realize this isn't the only instruction to do so, so I won't fight too hard against it.
created_at: 2025-05-15T13:48:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1000,8 +1003,60 @@ namespace VegaISA
     void
     Inst_DS__DS_ADD_RTN_U32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 data(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        data.read();
+
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = data[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
     } // execute
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
+
+        initAtomicAccess<VecElemU32>(gpuDynInst, offset);
+    } // initiateAcc
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::completeAcc(GPUDynInstPtr gpuDynInst)
+    {
+        VecOperandU32 vdst(gpuDynInst, extData.VDST);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                // vdst[lane] = 10;
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: mattsinc
body: This line (1052) should be removed
created_at: 2025-05-15T13:49:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1319,6 +1374,9 @@ namespace VegaISA
     Inst_DS__DS_CMPST_RTN_B32::Inst_DS__DS_CMPST_RTN_B32(InFmt_DS *iFmt)
         : Inst_DS(iFmt, "ds_cmpst_rtn_b32")
     {
+        setFlag(MemoryRef);
+        setFlag(AtomicCAS);
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: mattsinc
body: @abmerop can chime in here, but technically this is not a CAS, it's an atomicAdd.  I'm not sure if we are distinguishing between them for the flags though
created_at: 2025-05-15T13:50:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
+
     } // execute
     // --- Inst_DS__DS_CMPST_RTN_F32 class methods ---
 
+    void
+    Inst_DS__DS_CMPST_RTN_B32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: mattsinc
body: I realize you probably copied this from another atomic instruction, but any idea why you are shifting by 8?  This sort of thing seems worth documenting.
created_at: 2025-05-15T13:51:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: abmerop
body: In the instruction description it says: "Compare and store. Caution, the order of src and cmp are the
*opposite* of the BUFFER_ATOMIC_CMPSWAP opcode." I think in order to use the existing AtomicCAS operator these values would have to be reversed.  I.e., x_data is cmp and a_data is src
created_at: 2025-05-15T17:26:26Z
author_association: MEMBER
diff_hunk: @@ -1319,6 +1374,9 @@ namespace VegaISA
     Inst_DS__DS_CMPST_RTN_B32::Inst_DS__DS_CMPST_RTN_B32(InFmt_DS *iFmt)
         : Inst_DS(iFmt, "ds_cmpst_rtn_b32")
     {
+        setFlag(MemoryRef);
+        setFlag(AtomicCAS);
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: abmerop
body: This should work, but I believe the order needs to be switched in the execute method below
created_at: 2025-05-15T17:26:53Z
author_association: MEMBER
diff_hunk: @@ -1000,8 +1003,60 @@ namespace VegaISA
     void
     Inst_DS__DS_ADD_RTN_U32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 data(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        data.read();
+
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = data[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
     } // execute
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
+
+        initAtomicAccess<VecElemU32>(gpuDynInst, offset);
+    } // initiateAcc
+
+    void
+    Inst_DS__DS_ADD_RTN_U32::completeAcc(GPUDynInstPtr gpuDynInst)
+    {
+        VecOperandU32 vdst(gpuDynInst, extData.VDST);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                // vdst[lane] = 10;
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: german-v-t-um-es
body: Sure, sorry for that line. I included it while I was debugging and forgot to erase it when I finished debugging.
created_at: 2025-05-16T09:01:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1000,8 +1003,60 @@ namespace VegaISA
     void
     Inst_DS__DS_ADD_RTN_U32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: german-v-t-um-es
body: So, we can leave it like that I guess?
created_at: 2025-05-16T09:02:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: german-v-t-um-es
body: Thanks for the note! I believe the values you're referring to are already inverted in lines 1413–1414.
From what I see, `src` is assigned from `extData.DATA1` and `cmp` from `extData.DATA0`, which matches the expected order for this opcode, if I'm understanding it correctly. Can you verify it?

created_at: 2025-05-16T09:41:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
+
     } // execute
     // --- Inst_DS__DS_CMPST_RTN_F32 class methods ---
 
+    void
+    Inst_DS__DS_CMPST_RTN_B32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: german-v-t-um-es
body: You're right, I took this pattern from the existing DS_ADD_U32 implementation. From what I understand, we shift OFFSET1 by 8 bits to build a 16-bit offset, where OFFSET1 provides the upper 8 bits and OFFSET0 the lower 8 bits. This offset is needed to compute the full virtual address used in initAtomicAccess.

I can add this comment if you'd like and @abmerop also finds it correct: 
`// Build a 16-bit offset by combining two 8-bit fields:                                             
//   OFFSET1 → high byte, OFFSET0 → low byte.`
created_at: 2025-05-16T09:55:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: abmerop
body: I see now, it does look correct then.
created_at: 2025-05-16T16:36:39Z
author_association: MEMBER
diff_hunk: @@ -1338,10 +1396,68 @@ namespace VegaISA
     void
     Inst_DS__DS_CMPST_RTN_B32::execute(GPUDynInstPtr gpuDynInst)
     {
-        panicUnimplemented();
+        //panicUnimplemented();
+        Wavefront *wf = gpuDynInst->wavefront();
+
+        if (gpuDynInst->exec_mask.none()) {
+            wf->decLGKMInstsIssued();
+            return;
+        }
+
+        gpuDynInst->execUnitId = wf->execUnitId;
+        gpuDynInst->latency.init(gpuDynInst->computeUnit());
+        gpuDynInst->latency.set(
+                gpuDynInst->computeUnit()->cyclesToTicks(Cycles(24)));
+
+        ConstVecOperandU32 addr(gpuDynInst, extData.ADDR);
+        ConstVecOperandU32 src(gpuDynInst, extData.DATA1);
+        ConstVecOperandU32 cmp(gpuDynInst, extData.DATA0);
+
+        addr.read();
+        src.read();
+        cmp.read();
+        calcAddr(gpuDynInst, addr);
+
+        for (int lane = 0; lane < NumVecElemPerVecReg; ++lane) {
+            if (gpuDynInst->exec_mask[lane]) {
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->x_data))[lane]
+                    = src[lane];
+                (reinterpret_cast<VecElemU32*>(gpuDynInst->a_data))[lane]
+                    = cmp[lane];
+            }
+        }
+
+        gpuDynInst->computeUnit()->localMemoryPipe.issueRequest(gpuDynInst);
+
     } // execute
     // --- Inst_DS__DS_CMPST_RTN_F32 class methods ---
 
+    void
+    Inst_DS__DS_CMPST_RTN_B32::initiateAcc(GPUDynInstPtr gpuDynInst)
+    {
+        Addr offset0 = instData.OFFSET0;
+        Addr offset1 = instData.OFFSET1;
+        Addr offset = (offset1 << 8) | offset0;
path: src/arch/amdgpu/vega/insts/ds.cc
user: login: abmerop
body: That's correct.  Here is the quote from the MI200 spec: "Immediate offset, in bytes. Instructions with one address combine the offset fields into a single 16-bit unsigned offset: {offset1, offset0}."
created_at: 2025-05-16T16:39:04Z
author_association: MEMBER

PR comments:
user: login: mattsinc
created_at: 2025-05-15T13:54:37Z
body: Also @german-v-t-um-es I did want to know that we technically don't directly support gfx90a because the MI100 generation of GPUs added a special register file that was immediately removed in the MI200/300 generations.  So, we decided it wasn't worth adding support for a generation of GPU that was already not the latest generation and would have required special support beyond that.  Nevertheless, I think these instructions are worth adding -- do you have a test that validates them?
author_association: CONTRIBUTOR
user: login: german-v-t-um-es
created_at: 2025-05-16T10:59:07Z
body: > Also @german-v-t-um-es I did want to know that we technically don't directly support gfx90a because the MI100 generation of GPUs added a special register file that was immediately removed in the MI200/300 generations. So, we decided it wasn't worth adding support for a generation of GPU that was already not the latest generation and would have required special support beyond that. Nevertheless, I think these instructions are worth adding -- do you have a test that validates them?

I understand what you are saying, but isn't gfx90a the MI200 generation and gfx908 the MI100 generation, according to [Accelerator and GPU hardware specifications](https://rocm.docs.amd.com/en/latest/reference/gpu-arch-specs.html). 

I am very happy that you find these instructions useful and I do have a small test that validates them. I'm attaching here both the Makefile that compiles the test and the source code, which is compiled inside the docker container with ROCm 6.1 used for the GPUFS models. To make sure the code generates the instructions I have implemented, I obtained the assembly code and checked their presence.
[test.zip](https://github.com/user-attachments/files/20242706/test.zip)


author_association: CONTRIBUTOR
user: login: mattsinc
created_at: 2025-05-18T18:16:04Z
body: > > Also @german-v-t-um-es I did want to know that we technically don't directly support gfx90a because the MI100 generation of GPUs added a special register file that was immediately removed in the MI200/300 generations. So, we decided it wasn't worth adding support for a generation of GPU that was already not the latest generation and would have required special support beyond that. Nevertheless, I think these instructions are worth adding -- do you have a test that validates them?
> 
> I understand what you are saying, but isn't gfx90a the MI200 generation and gfx908 the MI100 generation, according to [Accelerator and GPU hardware specifications](https://rocm.docs.amd.com/en/latest/reference/gpu-arch-specs.html).
> 
> I am very happy that you find these instructions useful and I do have a small test that validates them. I'm attaching here both the Makefile that compiles the test and the source code, which is compiled inside the docker container with ROCm 6.1 used for the GPUFS models. To make sure the code generates the instructions I have implemented, I obtained the assembly code and checked their presence. [test.zip](https://github.com/user-attachments/files/20242706/test.zip)

You're right, I got the ISA numbers wrong
author_association: CONTRIBUTOR
user: login: german-v-t-um-es
created_at: 2025-05-21T10:03:54Z
body: Hi @abmerop and @mattsinc, just wanted to check if there's anything else needed to finalize the pull request. The tests are passing, but since develop is being updated frequently, it keeps requiring a merge with the latest develop, which then triggers the tests to rerun each time.
author_association: CONTRIBUTOR
user: login: abmerop
created_at: 2025-05-21T16:56:57Z
body: You shouldn't have to keep updating it, once the tests pass GitHub should be smart enough to rebase automatically 
author_association: MEMBER
user: login: mattsinc
created_at: 2025-05-22T05:58:32Z
body: > You shouldn't have to keep updating it, once the tests pass GitHub should be smart enough to rebase automatically

thanks @abmerop for merging before I got to this
author_association: CONTRIBUTOR