[llvm] [RISCV][GlobalISel] Legalize and select G_ATOMICRMW_ADD instruction (PR #153791)

Kane Wang via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 15 04:52:02 PDT 2025


https://github.com/ReVe1uv updated https://github.com/llvm/llvm-project/pull/153791

>From 324f6cf0df7facc7f384e6cce5a5c4e4f8558b0d Mon Sep 17 00:00:00 2001
From: Kane Wang <kanewang95 at foxmail.com>
Date: Fri, 15 Aug 2025 19:25:32 +0800
Subject: [PATCH] [RISCV][GlobalISel] Legalize and select G_ATOMICRMW_ADD
 instruction

This patch adds legalization and instruction selection support for the G_ATOMICRMW_ADD opcode in the RISCV GlobalISel backend.
---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  |  69 ++++++
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp |   7 +
 .../instruction-select/atomicrmw-add-rv32.mir | 118 ++++++++++
 .../instruction-select/atomicrmw-add-rv64.mir | 218 ++++++++++++++++++
 .../GlobalISel/legalizer-info-validation.mir  |   4 +-
 .../legalizer/legalize-atomicrmw-add-rv32.mir |  98 ++++++++
 .../legalizer/legalize-atomicrmw-add-rv64.mir | 187 +++++++++++++++
 7 files changed, 699 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv64.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv64.mir

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index f83c2b6da8923..de34850536e6d 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -92,6 +92,7 @@ class RISCVInstructionSelector : public InstructionSelector {
   void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
                  MachineIRBuilder &MIB) const;
   bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB) const;
+  bool selectAtomicRMWAdd(MachineInstr &MI, MachineIRBuilder &MIB) const;
 
   ComplexRendererFns selectShiftMask(MachineOperand &Root,
                                      unsigned ShiftWidth) const;
@@ -815,6 +816,8 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
     return selectImplicitDef(MI, MIB);
   case TargetOpcode::G_UNMERGE_VALUES:
     return selectUnmergeValues(MI, MIB);
+  case TargetOpcode::G_ATOMICRMW_ADD:
+    return selectAtomicRMWAdd(MI, MIB);
   default:
     return false;
   }
@@ -1415,6 +1418,72 @@ void RISCVInstructionSelector::emitFence(AtomicOrdering FenceOrdering,
   MIB.buildInstr(RISCV::FENCE, {}, {}).addImm(Pred).addImm(Succ);
 }
 
+bool RISCVInstructionSelector::selectAtomicRMWAdd(MachineInstr &MI,
+                                                  MachineIRBuilder &MIB) const {
+  MachineBasicBlock &MBB = *MI.getParent();
+  MachineFunction &MF = *MBB.getParent();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+
+  Register DstReg = MI.getOperand(0).getReg();
+  Register PtrReg = MI.getOperand(1).getReg();
+  Register ValReg = MI.getOperand(2).getReg();
+
+  if (MI.memoperands_empty())
+    return false;
+  MachineMemOperand *MMO = *MI.memoperands_begin();
+  AtomicOrdering Ordering = MMO->getSuccessOrdering();
+
+  unsigned BaseOpcode;
+  LLT Ty = MRI.getType(DstReg);
+  if (Ty == LLT::scalar(32)) {
+    switch (Ordering) {
+    case AtomicOrdering::Monotonic:
+      BaseOpcode = RISCV::AMOADD_W;
+      break;
+    case AtomicOrdering::Acquire:
+      BaseOpcode = RISCV::AMOADD_W_AQ;
+      break;
+    case AtomicOrdering::Release:
+      BaseOpcode = RISCV::AMOADD_W_RL;
+      break;
+    case AtomicOrdering::AcquireRelease:
+    case AtomicOrdering::SequentiallyConsistent:
+      BaseOpcode = RISCV::AMOADD_W_AQ_RL;
+      break;
+    default:
+      return false;
+    }
+  } else if (Ty == LLT::scalar(64)) {
+    switch (Ordering) {
+    case AtomicOrdering::Monotonic:
+      BaseOpcode = RISCV::AMOADD_D;
+      break;
+    case AtomicOrdering::Acquire:
+      BaseOpcode = RISCV::AMOADD_D_AQ;
+      break;
+    case AtomicOrdering::Release:
+      BaseOpcode = RISCV::AMOADD_D_RL;
+      break;
+    case AtomicOrdering::AcquireRelease:
+    case AtomicOrdering::SequentiallyConsistent:
+      BaseOpcode = RISCV::AMOADD_D_AQ_RL;
+      break;
+    default:
+      return false;
+    }
+  } else {
+    return false;
+  }
+
+  auto NewMI =
+      MIB.buildInstr(BaseOpcode).addDef(DstReg).addUse(ValReg).addUse(PtrReg);
+  NewMI.addMemOperand(MMO);
+
+  MI.eraseFromParent();
+
+  return constrainSelectedInstRegOperands(*NewMI, TII, TRI, RBI);
+}
+
 namespace llvm {
 InstructionSelector *
 createRISCVInstructionSelector(const RISCVTargetMachine &TM,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index e88f33d6859ec..9986cb39b7965 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -692,6 +692,13 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
                     typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
 
+  bool ForceAtomics = ST.hasForcedAtomics() && !ST.hasStdExtA();
+
+  getActionDefinitionsBuilder(G_ATOMICRMW_ADD)
+      .legalFor(!ForceAtomics, {{s32, p0}, {sXLen, p0}})
+      .libcallFor(ForceAtomics, {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
+      .clampScalar(0, s32, sXLen);
+
   getLegacyLegalizerInfo().computeTables();
   verify(*ST.getInstrInfo());
 }
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv32.mir
new file mode 100644
index 0000000000000..97cf4dc798280
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv32.mir
@@ -0,0 +1,118 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -mattr=+A -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name:            atomicrmw_add_i32_monotonic
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W:%[0-9]+]]:gpr = AMOADD_W [[COPY]], [[ADDI]] :: (load store monotonic (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store monotonic (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acquire
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_AQ:%[0-9]+]]:gpr = AMOADD_W_AQ [[COPY]], [[ADDI]] :: (load store acquire (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_AQ]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acquire (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_release
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_RL:%[0-9]+]]:gpr = AMOADD_W_RL [[COPY]], [[ADDI]] :: (load store release (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store release (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acq_rel
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_AQ_RL:%[0-9]+]]:gpr = AMOADD_W_AQ_RL [[COPY]], [[ADDI]] :: (load store acq_rel (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_AQ_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acq_rel (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_seq_cst
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_seq_cst
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_AQ_RL:%[0-9]+]]:gpr = AMOADD_W_AQ_RL [[COPY]], [[ADDI]] :: (load store seq_cst (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_AQ_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store seq_cst (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv64.mir
new file mode 100644
index 0000000000000..3d7e28281de15
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/atomicrmw-add-rv64.mir
@@ -0,0 +1,218 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -mattr=+A -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name:            atomicrmw_add_i32_monotonic
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W:%[0-9]+]]:gpr = AMOADD_W [[ADDI]], [[COPY]] :: (load store monotonic (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s32) = G_TRUNC %1(s64)
+    %3:gprb(s32) = G_ATOMICRMW_ADD %0, %2 :: (load store monotonic (s32))
+    %4:gprb(s64) = G_ANYEXT %3(s32)
+    $x10 = COPY %4(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acquire
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_AQ:%[0-9]+]]:gpr = AMOADD_W_AQ [[ADDI]], [[COPY]] :: (load store acquire (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_AQ]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s32) = G_TRUNC %1(s64)
+    %3:gprb(s32) = G_ATOMICRMW_ADD %0, %2 :: (load store acquire (s32))
+    %4:gprb(s64) = G_ANYEXT %3(s32)
+    $x10 = COPY %4(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_release
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_RL:%[0-9]+]]:gpr = AMOADD_W_RL [[ADDI]], [[COPY]] :: (load store release (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s32) = G_TRUNC %1(s64)
+    %3:gprb(s32) = G_ATOMICRMW_ADD %0, %2 :: (load store release (s32))
+    %4:gprb(s64) = G_ANYEXT %3(s32)
+    $x10 = COPY %4(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acq_rel
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_W_AQ_RL:%[0-9]+]]:gpr = AMOADD_W_AQ_RL [[ADDI]], [[COPY]] :: (load store acq_rel (s32))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_W_AQ_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s32) = G_TRUNC %1(s64)
+    %3:gprb(s32) = G_ATOMICRMW_ADD %0, %2 :: (load store acq_rel (s32))
+    %4:gprb(s64) = G_ANYEXT %3(s32)
+    $x10 = COPY %4(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_monotonic
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i64_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_D:%[0-9]+]]:gpr = AMOADD_D [[COPY]], [[ADDI]] :: (load store monotonic (s64))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_D]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store monotonic (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_acquire
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i64_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_D_AQ:%[0-9]+]]:gpr = AMOADD_D_AQ [[COPY]], [[ADDI]] :: (load store acquire (s64))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_D_AQ]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store acquire (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_release
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i64_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_D_RL:%[0-9]+]]:gpr = AMOADD_D_RL [[COPY]], [[ADDI]] :: (load store release (s64))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_D_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store release (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_acq_rel
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i64_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_D_AQ_RL:%[0-9]+]]:gpr = AMOADD_D_AQ_RL [[COPY]], [[ADDI]] :: (load store acq_rel (s64))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_D_AQ_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store acq_rel (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_seq_cst
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i64_seq_cst
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+    ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 1
+    ; CHECK-NEXT: [[AMOADD_D_AQ_RL:%[0-9]+]]:gpr = AMOADD_D_AQ_RL [[COPY]], [[ADDI]] :: (load store seq_cst (s64))
+    ; CHECK-NEXT: $x10 = COPY [[AMOADD_D_AQ_RL]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store seq_cst (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index 82cc6829838a0..c47ce4d5f1153 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -222,8 +222,8 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
 # DEBUG-NEXT: G_ATOMICRMW_ADD (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. the first uncovered type index: 2, OK
+# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
 # DEBUG-NEXT: G_ATOMICRMW_SUB (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
 # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv32.mir
new file mode 100644
index 0000000000000..5c378ac71dcce
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv32.mir
@@ -0,0 +1,98 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -mattr=+A -run-pass=legalizer %s -o - | FileCheck %s
+
+---
+name:            atomicrmw_add_i32_monotonic
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store monotonic (s32))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store monotonic (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acquire
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store acquire (s32))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acquire (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_release
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store release (s32))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store release (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acq_rel
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store acq_rel (s32))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acq_rel (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_seq_cst
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_seq_cst
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store seq_cst (s32))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store seq_cst (s32))
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv64.mir
new file mode 100644
index 0000000000000..c4340312011ec
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-atomicrmw-add-rv64.mir
@@ -0,0 +1,187 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -mattr=+A -run-pass=legalizer %s -o - | FileCheck %s
+
+---
+name:            atomicrmw_add_i32_monotonic
+body:             |
+  bb.0.entry:
+    liveins: $x10
+
+    ; CHECK-LABEL: name: atomicrmw_add_i32_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:gprb(s32) = G_TRUNC [[C]](s64)
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[TRUNC]] :: (load store monotonic (s32))
+    ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:gprb(s64) = G_ANYEXT [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store monotonic (s32))
+    %3:gprb(s64) = G_ANYEXT %2(s32)
+    $x10 = COPY %3(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acquire
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:gprb(s32) = G_TRUNC [[C]](s64)
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[TRUNC]] :: (load store acquire (s32))
+    ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:gprb(s64) = G_ANYEXT [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acquire (s32))
+    %3:gprb(s64) = G_ANYEXT %2(s32)
+    $x10 = COPY %3(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_release
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:gprb(s32) = G_TRUNC [[C]](s64)
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[TRUNC]] :: (load store release (s32))
+    ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:gprb(s64) = G_ANYEXT [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store release (s32))
+    %3:gprb(s64) = G_ANYEXT %2(s32)
+    $x10 = COPY %3(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i32_acq_rel
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i32_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:gprb(s32) = G_TRUNC [[C]](s64)
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s32) = G_ATOMICRMW_ADD [[COPY]](p0), [[TRUNC]] :: (load store acq_rel (s32))
+    ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:gprb(s64) = G_ANYEXT [[ATOMICRMW_ADD]](s32)
+    ; CHECK-NEXT: $x10 = COPY [[ANYEXT]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s32) = G_CONSTANT i32 1
+    %2:gprb(s32) = G_ATOMICRMW_ADD %0, %1 :: (load store acq_rel (s32))
+    %3:gprb(s64) = G_ANYEXT %2(s32)
+    $x10 = COPY %3(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_monotonic
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i64_monotonic
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s64) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store monotonic (s64))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store monotonic (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_acquire
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i64_acquire
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s64) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store acquire (s64))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store acquire (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_release
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i64_release
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s64) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store release (s64))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store release (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_acq_rel
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i64_acq_rel
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s64) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store acq_rel (s64))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store acq_rel (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...
+---
+name:            atomicrmw_add_i64_seq_cst
+body:             |
+  bb.0.entry:
+    liveins: $x10
+    ; CHECK-LABEL: name: atomicrmw_add_i64_seq_cst
+    ; CHECK: liveins: $x10
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(p0) = COPY $x10
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[ATOMICRMW_ADD:%[0-9]+]]:gprb(s64) = G_ATOMICRMW_ADD [[COPY]](p0), [[C]] :: (load store seq_cst (s64))
+    ; CHECK-NEXT: $x10 = COPY [[ATOMICRMW_ADD]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = COPY $x10
+    %1:gprb(s64) = G_CONSTANT i64 1
+    %2:gprb(s64) = G_ATOMICRMW_ADD %0, %1 :: (load store seq_cst (s64))
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+...



More information about the llvm-commits mailing list