Repository: llvm/llvm-project
Pull request #136502: [RISCV] Remove `AND` mask generated by `( zext  ( atomic_load ) )` by replacing the load with `zextload` for orderings not stronger then monotonic.
Author: login: janagor
Labels: name: backend:RISC-V
Created: 2025-04-20T18:57:38Z | Merged: 2025-04-28T15:35:51Z

Extends changes from [ff687af](https://github.com/llvm/llvm-project/commit/ff687af04f5b0e85305250587b524cb0b3849aa0).
Fixes https://github.com/llvm/llvm-project/issues/131476.

This patch adds a DAG combine to replace an `AND` of an `ATOMIC_LOAD` with a full-bit mask (e.g. `0xFF`, `0xFFFF`, etc.) which is generated as a result of `(zext (atomic_load))`,  by a zero-extended load, provided the atomic operation is monotonic or weaker.



Diff:
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index c72a016c5333b..6a890569f6c61 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15312,6 +15312,40 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+  if (!N0.hasOneUse())
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  ConstantSDNode *MaskConst = dyn_cast<ConstantSDNode>(N->getOperand(1));
+  if (!MaskConst)
+    return SDValue();
+  uint64_t Mask = MaskConst->getZExtValue();
+  uint64_t ExpectedMask = maskTrailingOnes<uint64_t>(LoadedVT.getSizeInBits());
+  if (Mask != ExpectedMask)
+    return SDValue();
+
+  SDValue ZextLoad = DAG.getAtomicLoad(
+      ISD::ZEXTLOAD, SDLoc(N), ALoad->getMemoryVT(), N->getValueType(0),
+      ALoad->getChain(), ALoad->getBasePtr(), ALoad->getMemOperand());
+  DCI.CombineTo(N, ZextLoad);
+  DAG.ReplaceAllUsesOfValueWith(SDValue(N0.getNode(), 1), ZextLoad.getValue(1));
+  DCI.recursivelyDeleteUnusedNodes(N0.getNode());
+  return SDValue(N, 0);
+}
+
 // Combines two comparison operation and logic operation to one selection
 // operation(min, max) and logic operation. Returns new constructed Node if
 // conditions for optimization are satisfied.
@@ -15346,6 +15380,8 @@ static SDValue performANDCombine(SDNode *N,
     return V;
   if (SDValue V = combineBinOpOfExtractToReduceTree(N, DAG, Subtarget))
     return V;
+  if (SDValue V = reduceANDOfAtomicLoad(N, DCI))
+    return V;
 
   if (DCI.isAfterLegalizeDAG())
     if (SDValue V = combineDeMorganOfBoolean(N, DAG))
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
index 74873a66bc8c9..5fa7d4160752f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
@@ -167,6 +167,8 @@ class seq_cst_store<PatFrag base>
 let Predicates = [HasAtomicLdSt] in {
   def : LdPat<relaxed_load<atomic_load_asext_8>,  LB>;
   def : LdPat<relaxed_load<atomic_load_asext_16>, LH>;
+  def : LdPat<relaxed_load<atomic_load_zext_8>,  LBU>;
+  def : LdPat<relaxed_load<atomic_load_zext_16>, LHU>;
 
   def : StPat<relaxed_store<atomic_store_8>,  SB, GPR, XLenVT>;
   def : StPat<relaxed_store<atomic_store_16>, SH, GPR, XLenVT>;
@@ -179,6 +181,7 @@ let Predicates = [HasAtomicLdSt, IsRV32] in {
 
 let Predicates = [HasAtomicLdSt, IsRV64] in {
   def : LdPat<relaxed_load<atomic_load_asext_32>, LW>;
+  def : LdPat<relaxed_load<atomic_load_zext_32>, LWU>;
   def : LdPat<relaxed_load<atomic_load_nonext_64>, LD, i64>;
   def : StPat<relaxed_store<atomic_store_64>, SD, GPR, i64>;
 }
diff --git a/llvm/test/CodeGen/RISCV/atomic-load-zext.ll b/llvm/test/CodeGen/RISCV/atomic-load-zext.ll
index 8097179443791..68d6b127ac6f1 100644
--- a/llvm/test/CodeGen/RISCV/atomic-load-zext.ll
+++ b/llvm/test/CodeGen/RISCV/atomic-load-zext.ll
@@ -301,8 +301,7 @@ define zeroext i8 @atomic_load_i8_unordered(ptr %a) nounwind {
 ;
 ; RV32IA-LABEL: atomic_load_i8_unordered:
 ; RV32IA:       # %bb.0:
-; RV32IA-NEXT:    lb a0, 0(a0)
-; RV32IA-NEXT:    zext.b a0, a0
+; RV32IA-NEXT:    lbu a0, 0(a0)
 ; RV32IA-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i8_unordered:
@@ -318,8 +317,7 @@ define zeroext i8 @atomic_load_i8_unordered(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i8_unordered:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lb a0, 0(a0)
-; RV64IA-NEXT:    zext.b a0, a0
+; RV64IA-NEXT:    lbu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i8, ptr %a unordered, align 1
   ret i8 %1
@@ -339,8 +337,7 @@ define zeroext i8 @atomic_load_i8_monotonic(ptr %a) nounwind {
 ;
 ; RV32IA-LABEL: atomic_load_i8_monotonic:
 ; RV32IA:       # %bb.0:
-; RV32IA-NEXT:    lb a0, 0(a0)
-; RV32IA-NEXT:    zext.b a0, a0
+; RV32IA-NEXT:    lbu a0, 0(a0)
 ; RV32IA-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i8_monotonic:
@@ -356,8 +353,7 @@ define zeroext i8 @atomic_load_i8_monotonic(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i8_monotonic:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lb a0, 0(a0)
-; RV64IA-NEXT:    zext.b a0, a0
+; RV64IA-NEXT:    lbu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i8, ptr %a monotonic, align 1
   ret i8 %1
@@ -377,15 +373,13 @@ define zeroext i8 @atomic_load_i8_acquire(ptr %a) nounwind {
 ;
 ; RV32IA-WMO-LABEL: atomic_load_i8_acquire:
 ; RV32IA-WMO:       # %bb.0:
-; RV32IA-WMO-NEXT:    lb a0, 0(a0)
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
 ; RV32IA-WMO-NEXT:    fence r, rw
-; RV32IA-WMO-NEXT:    zext.b a0, a0
 ; RV32IA-WMO-NEXT:    ret
 ;
 ; RV32IA-TSO-LABEL: atomic_load_i8_acquire:
 ; RV32IA-TSO:       # %bb.0:
-; RV32IA-TSO-NEXT:    lb a0, 0(a0)
-; RV32IA-TSO-NEXT:    zext.b a0, a0
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
 ; RV32IA-TSO-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i8_acquire:
@@ -401,41 +395,35 @@ define zeroext i8 @atomic_load_i8_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-WMO-LABEL: atomic_load_i8_acquire:
 ; RV64IA-WMO:       # %bb.0:
-; RV64IA-WMO-NEXT:    lb a0, 0(a0)
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
-; RV64IA-WMO-NEXT:    zext.b a0, a0
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i8_acquire:
 ; RV64IA-TSO:       # %bb.0:
-; RV64IA-TSO-NEXT:    lb a0, 0(a0)
-; RV64IA-TSO-NEXT:    zext.b a0, a0
+; RV64IA-TSO-NEXT:    lbu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
 ; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    zext.b a0, a0
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
 ; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    zext.b a0, a0
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-WMO-LABEL: atomic_load_i8_acquire:
@@ -446,8 +434,7 @@ define zeroext i8 @atomic_load_i8_acquire(ptr %a) nounwind {
 ;
 ; RV32IA-ZALASR-TSO-LABEL: atomic_load_i8_acquire:
 ; RV32IA-ZALASR-TSO:       # %bb.0:
-; RV32IA-ZALASR-TSO-NEXT:    lb a0, 0(a0)
-; RV32IA-ZALASR-TSO-NEXT:    zext.b a0, a0
+; RV32IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
 ; RV32IA-ZALASR-TSO-NEXT:    ret
 ;
 ; RV64IA-ZALASR-WMO-LABEL: atomic_load_i8_acquire:
@@ -458,8 +445,7 @@ define zeroext i8 @atomic_load_i8_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-ZALASR-TSO-LABEL: atomic_load_i8_acquire:
 ; RV64IA-ZALASR-TSO:       # %bb.0:
-; RV64IA-ZALASR-TSO-NEXT:    lb a0, 0(a0)
-; RV64IA-ZALASR-TSO-NEXT:    zext.b a0, a0
+; RV64IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
 ; RV64IA-ZALASR-TSO-NEXT:    ret
   %1 = load atomic i8, ptr %a acquire, align 1
   ret i8 %1
@@ -480,16 +466,14 @@ define zeroext i8 @atomic_load_i8_seq_cst(ptr %a) nounwind {
 ; RV32IA-WMO-LABEL: atomic_load_i8_seq_cst:
 ; RV32IA-WMO:       # %bb.0:
 ; RV32IA-WMO-NEXT:    fence rw, rw
-; RV32IA-WMO-NEXT:    lb a0, 0(a0)
-; RV32IA-WMO-NEXT:    zext.b a0, a0
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
 ; RV32IA-WMO-NEXT:    fence r, rw
 ; RV32IA-WMO-NEXT:    ret
 ;
 ; RV32IA-TSO-LABEL: atomic_load_i8_seq_cst:
 ; RV32IA-TSO:       # %bb.0:
 ; RV32IA-TSO-NEXT:    fence rw, rw
-; RV32IA-TSO-NEXT:    lb a0, 0(a0)
-; RV32IA-TSO-NEXT:    zext.b a0, a0
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
 ; RV32IA-TSO-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i8_seq_cst:
@@ -506,46 +490,40 @@ define zeroext i8 @atomic_load_i8_seq_cst(ptr %a) nounwind {
 ; RV64IA-WMO-LABEL: atomic_load_i8_seq_cst:
 ; RV64IA-WMO:       # %bb.0:
 ; RV64IA-WMO-NEXT:    fence rw, rw
-; RV64IA-WMO-NEXT:    lb a0, 0(a0)
-; RV64IA-WMO-NEXT:    zext.b a0, a0
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i8_seq_cst:
 ; RV64IA-TSO:       # %bb.0:
 ; RV64IA-TSO-NEXT:    fence rw, rw
-; RV64IA-TSO-NEXT:    lb a0, 0(a0)
-; RV64IA-TSO-NEXT:    zext.b a0, a0
+; RV64IA-TSO-NEXT:    lbu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_seq_cst:
 ; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_seq_cst:
 ; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_seq_cst:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_seq_cst:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lb a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    zext.b a0, a0
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-LABEL: atomic_load_i8_seq_cst:
@@ -578,9 +556,7 @@ define zeroext i16 @atomic_load_i16_unordered(ptr %a) nounwind {
 ;
 ; RV32IA-LABEL: atomic_load_i16_unordered:
 ; RV32IA:       # %bb.0:
-; RV32IA-NEXT:    lh a0, 0(a0)
-; RV32IA-NEXT:    slli a0, a0, 16
-; RV32IA-NEXT:    srli a0, a0, 16
+; RV32IA-NEXT:    lhu a0, 0(a0)
 ; RV32IA-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i16_unordered:
@@ -597,9 +573,7 @@ define zeroext i16 @atomic_load_i16_unordered(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i16_unordered:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lh a0, 0(a0)
-; RV64IA-NEXT:    slli a0, a0, 48
-; RV64IA-NEXT:    srli a0, a0, 48
+; RV64IA-NEXT:    lhu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i16, ptr %a unordered, align 2
   ret i16 %1
@@ -620,9 +594,7 @@ define zeroext i16 @atomic_load_i16_monotonic(ptr %a) nounwind {
 ;
 ; RV32IA-LABEL: atomic_load_i16_monotonic:
 ; RV32IA:       # %bb.0:
-; RV32IA-NEXT:    lh a0, 0(a0)
-; RV32IA-NEXT:    slli a0, a0, 16
-; RV32IA-NEXT:    srli a0, a0, 16
+; RV32IA-NEXT:    lhu a0, 0(a0)
 ; RV32IA-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i16_monotonic:
@@ -639,9 +611,7 @@ define zeroext i16 @atomic_load_i16_monotonic(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i16_monotonic:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lh a0, 0(a0)
-; RV64IA-NEXT:    slli a0, a0, 48
-; RV64IA-NEXT:    srli a0, a0, 48
+; RV64IA-NEXT:    lhu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i16, ptr %a monotonic, align 2
   ret i16 %1
@@ -662,17 +632,13 @@ define zeroext i16 @atomic_load_i16_acquire(ptr %a) nounwind {
 ;
 ; RV32IA-WMO-LABEL: atomic_load_i16_acquire:
 ; RV32IA-WMO:       # %bb.0:
-; RV32IA-WMO-NEXT:    lh a0, 0(a0)
+; RV32IA-WMO-NEXT:    lhu a0, 0(a0)
 ; RV32IA-WMO-NEXT:    fence r, rw
-; RV32IA-WMO-NEXT:    slli a0, a0, 16
-; RV32IA-WMO-NEXT:    srli a0, a0, 16
 ; RV32IA-WMO-NEXT:    ret
 ;
 ; RV32IA-TSO-LABEL: atomic_load_i16_acquire:
 ; RV32IA-TSO:       # %bb.0:
-; RV32IA-TSO-NEXT:    lh a0, 0(a0)
-; RV32IA-TSO-NEXT:    slli a0, a0, 16
-; RV32IA-TSO-NEXT:    srli a0, a0, 16
+; RV32IA-TSO-NEXT:    lhu a0, 0(a0)
 ; RV32IA-TSO-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i16_acquire:
@@ -689,47 +655,35 @@ define zeroext i16 @atomic_load_i16_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-WMO-LABEL: atomic_load_i16_acquire:
 ; RV64IA-WMO:       # %bb.0:
-; RV64IA-WMO-NEXT:    lh a0, 0(a0)
+; RV64IA-WMO-NEXT:    lhu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
-; RV64IA-WMO-NEXT:    slli a0, a0, 48
-; RV64IA-WMO-NEXT:    srli a0, a0, 48
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i16_acquire:
 ; RV64IA-TSO:       # %bb.0:
-; RV64IA-TSO-NEXT:    lh a0, 0(a0)
-; RV64IA-TSO-NEXT:    slli a0, a0, 48
-; RV64IA-TSO-NEXT:    srli a0, a0, 48
+; RV64IA-TSO-NEXT:    lhu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i16_acquire:
 ; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 16
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 16
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i16_acquire:
 ; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 16
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 16
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i16_acquire:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 48
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 48
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i16_acquire:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 48
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 48
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-WMO-LABEL: atomic_load_i16_acquire:
@@ -741,9 +695,7 @@ define zeroext i16 @atomic_load_i16_acquire(ptr %a) nounwind {
 ;
 ; RV32IA-ZALASR-TSO-LABEL: atomic_load_i16_acquire:
 ; RV32IA-ZALASR-TSO:       # %bb.0:
-; RV32IA-ZALASR-TSO-NEXT:    lh a0, 0(a0)
-; RV32IA-ZALASR-TSO-NEXT:    slli a0, a0, 16
-; RV32IA-ZALASR-TSO-NEXT:    srli a0, a0, 16
+; RV32IA-ZALASR-TSO-NEXT:    lhu a0, 0(a0)
 ; RV32IA-ZALASR-TSO-NEXT:    ret
 ;
 ; RV64IA-ZALASR-WMO-LABEL: atomic_load_i16_acquire:
@@ -755,9 +707,7 @@ define zeroext i16 @atomic_load_i16_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-ZALASR-TSO-LABEL: atomic_load_i16_acquire:
 ; RV64IA-ZALASR-TSO:       # %bb.0:
-; RV64IA-ZALASR-TSO-NEXT:    lh a0, 0(a0)
-; RV64IA-ZALASR-TSO-NEXT:    slli a0, a0, 48
-; RV64IA-ZALASR-TSO-NEXT:    srli a0, a0, 48
+; RV64IA-ZALASR-TSO-NEXT:    lhu a0, 0(a0)
 ; RV64IA-ZALASR-TSO-NEXT:    ret
   %1 = load atomic i16, ptr %a acquire, align 2
   ret i16 %1
@@ -779,18 +729,14 @@ define zeroext i16 @atomic_load_i16_seq_cst(ptr %a) nounwind {
 ; RV32IA-WMO-LABEL: atomic_load_i16_seq_cst:
 ; RV32IA-WMO:       # %bb.0:
 ; RV32IA-WMO-NEXT:    fence rw, rw
-; RV32IA-WMO-NEXT:    lh a0, 0(a0)
-; RV32IA-WMO-NEXT:    slli a0, a0, 16
-; RV32IA-WMO-NEXT:    srli a0, a0, 16
+; RV32IA-WMO-NEXT:    lhu a0, 0(a0)
 ; RV32IA-WMO-NEXT:    fence r, rw
 ; RV32IA-WMO-NEXT:    ret
 ;
 ; RV32IA-TSO-LABEL: atomic_load_i16_seq_cst:
 ; RV32IA-TSO:       # %bb.0:
 ; RV32IA-TSO-NEXT:    fence rw, rw
-; RV32IA-TSO-NEXT:    lh a0, 0(a0)
-; RV32IA-TSO-NEXT:    slli a0, a0, 16
-; RV32IA-TSO-NEXT:    srli a0, a0, 16
+; RV32IA-TSO-NEXT:    lhu a0, 0(a0)
 ; RV32IA-TSO-NEXT:    ret
 ;
 ; RV64I-LABEL: atomic_load_i16_seq_cst:
@@ -808,52 +754,40 @@ define zeroext i16 @atomic_load_i16_seq_cst(ptr %a) nounwind {
 ; RV64IA-WMO-LABEL: atomic_load_i16_seq_cst:
 ; RV64IA-WMO:       # %bb.0:
 ; RV64IA-WMO-NEXT:    fence rw, rw
-; RV64IA-WMO-NEXT:    lh a0, 0(a0)
-; RV64IA-WMO-NEXT:    slli a0, a0, 48
-; RV64IA-WMO-NEXT:    srli a0, a0, 48
+; RV64IA-WMO-NEXT:    lhu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i16_seq_cst:
 ; RV64IA-TSO:       # %bb.0:
 ; RV64IA-TSO-NEXT:    fence rw, rw
-; RV64IA-TSO-NEXT:    lh a0, 0(a0)
-; RV64IA-TSO-NEXT:    slli a0, a0, 48
-; RV64IA-TSO-NEXT:    srli a0, a0, 48
+; RV64IA-TSO-NEXT:    lhu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i16_seq_cst:
 ; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 16
-; RV32IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 16
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
 ; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i16_seq_cst:
 ; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 16
-; RV32IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 16
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i16_seq_cst:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 48
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 48
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i16_seq_cst:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lh a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 48
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 48
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lhu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-LABEL: atomic_load_i16_seq_cst:
@@ -903,9 +837,7 @@ define zeroext i32 @atomic_load_i32_unordered(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i32_unordered:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lw a0, 0(a0)
-; RV64IA-NEXT:    slli a0, a0, 32
-; RV64IA-NEXT:    srli a0, a0, 32
+; RV64IA-NEXT:    lwu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i32, ptr %a unordered, align 4
   ret i32 %1
@@ -941,9 +873,7 @@ define zeroext i32 @atomic_load_i32_monotonic(ptr %a) nounwind {
 ;
 ; RV64IA-LABEL: atomic_load_i32_monotonic:
 ; RV64IA:       # %bb.0:
-; RV64IA-NEXT:    lw a0, 0(a0)
-; RV64IA-NEXT:    slli a0, a0, 32
-; RV64IA-NEXT:    srli a0, a0, 32
+; RV64IA-NEXT:    lwu a0, 0(a0)
 ; RV64IA-NEXT:    ret
   %1 = load atomic i32, ptr %a monotonic, align 4
   ret i32 %1
@@ -985,17 +915,13 @@ define zeroext i32 @atomic_load_i32_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-WMO-LABEL: atomic_load_i32_acquire:
 ; RV64IA-WMO:       # %bb.0:
-; RV64IA-WMO-NEXT:    lw a0, 0(a0)
+; RV64IA-WMO-NEXT:    lwu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
-; RV64IA-WMO-NEXT:    slli a0, a0, 32
-; RV64IA-WMO-NEXT:    srli a0, a0, 32
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i32_acquire:
 ; RV64IA-TSO:       # %bb.0:
-; RV64IA-TSO-NEXT:    lw a0, 0(a0)
-; RV64IA-TSO-NEXT:    slli a0, a0, 32
-; RV64IA-TSO-NEXT:    srli a0, a0, 32
+; RV64IA-TSO-NEXT:    lwu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i32_acquire:
@@ -1011,17 +937,13 @@ define zeroext i32 @atomic_load_i32_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i32_acquire:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lw a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lwu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 32
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 32
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i32_acquire:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lw a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 32
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 32
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lwu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-WMO-LABEL: atomic_load_i32_acquire:
@@ -1043,9 +965,7 @@ define zeroext i32 @atomic_load_i32_acquire(ptr %a) nounwind {
 ;
 ; RV64IA-ZALASR-TSO-LABEL: atomic_load_i32_acquire:
 ; RV64IA-ZALASR-TSO:       # %bb.0:
-; RV64IA-ZALASR-TSO-NEXT:    lw a0, 0(a0)
-; RV64IA-ZALASR-TSO-NEXT:    slli a0, a0, 32
-; RV64IA-ZALASR-TSO-NEXT:    srli a0, a0, 32
+; RV64IA-ZALASR-TSO-NEXT:    lwu a0, 0(a0)
 ; RV64IA-ZALASR-TSO-NEXT:    ret
   %1 = load atomic i32, ptr %a acquire, align 4
   ret i32 %1
@@ -1090,18 +1010,14 @@ define zeroext i32 @atomic_load_i32_seq_cst(ptr %a) nounwind {
 ; RV64IA-WMO-LABEL: atomic_load_i32_seq_cst:
 ; RV64IA-WMO:       # %bb.0:
 ; RV64IA-WMO-NEXT:    fence rw, rw
-; RV64IA-WMO-NEXT:    lw a0, 0(a0)
-; RV64IA-WMO-NEXT:    slli a0, a0, 32
-; RV64IA-WMO-NEXT:    srli a0, a0, 32
+; RV64IA-WMO-NEXT:    lwu a0, 0(a0)
 ; RV64IA-WMO-NEXT:    fence r, rw
 ; RV64IA-WMO-NEXT:    ret
 ;
 ; RV64IA-TSO-LABEL: atomic_load_i32_seq_cst:
 ; RV64IA-TSO:       # %bb.0:
 ; RV64IA-TSO-NEXT:    fence rw, rw
-; RV64IA-TSO-NEXT:    lw a0, 0(a0)
-; RV64IA-TSO-NEXT:    slli a0, a0, 32
-; RV64IA-TSO-NEXT:    srli a0, a0, 32
+; RV64IA-TSO-NEXT:    lwu a0, 0(a0)
 ; RV64IA-TSO-NEXT:    ret
 ;
 ; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i32_seq_cst:
@@ -1120,18 +1036,14 @@ define zeroext i32 @atomic_load_i32_seq_cst(ptr %a) nounwind {
 ; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i32_seq_cst:
 ; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    lw a0, 0(a0)
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    slli a0, a0, 32
-; RV64IA-WMO-TRAILING-FENCE-NEXT:    srli a0, a0, 32
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lwu a0, 0(a0)
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
 ; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i32_seq_cst:
 ; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    lw a0, 0(a0)
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    slli a0, a0, 32
-; RV64IA-TSO-TRAILING-FENCE-NEXT:    srli a0, a0, 32
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lwu a0, 0(a0)
 ; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
 ;
 ; RV32IA-ZALASR-LABEL: atomic_load_i32_seq_cst:


Reviews:
user: login: topperc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T00:47:54Z
user: login: topperc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T01:03:41Z
user: login: topperc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T19:19:45Z
user: login: topperc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-25T16:10:26Z
user: login: topperc
body: LGTM
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-25T18:00:41Z

Review comments:
diff_hunk: @@ -15267,6 +15267,48 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  EVT ResultVT = N->getValueType(0);
+
+  SDValue MaskVal = N->getOperand(1);
+  ConstantSDNode *MaskConst = dyn_cast<ConstantSDNode>(MaskVal);
+  if (!MaskConst)
+    return SDValue();
+  uint64_t Mask = MaskConst->getZExtValue();
+  uint64_t ExpectedMask = LoadedVT.getSizeInBits() == 8    ? 0xFF
+                          : LoadedVT.getSizeInBits() == 16 ? 0xFFFF
+                          : LoadedVT.getSizeInBits() == 32 ? 0xFFFFFFFF
+                                                           : 0xFFFFFFFFFFFFFFFF;
+  if (Mask != ExpectedMask)
+    return SDValue();
+
+  SDLoc DL(N);
+  SDValue Chain = ALoad->getChain();
+  SDValue Ptr = ALoad->getBasePtr();
+  MachineMemOperand *MemOp = ALoad->getMemOperand();
+  SDValue ZextLoad = DAG.getExtLoad(ISD::ZEXTLOAD, DL, ResultVT, Chain, Ptr,
+                                    MemOp->getPointerInfo(), LoadedVT,
+                                    MemOp->getAlign(), MemOp->getFlags());
+  DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), ZextLoad);
path: llvm/lib/Target/RISCV/RISCVISelLowering.cpp
user: login: topperc
body: We need to make sure that the AND is the only user of the atomic_load data result. If another user depends on the sign extension behavior this will break.
created_at: 2025-04-24T00:47:53Z
author_association: COLLABORATOR
diff_hunk: @@ -15267,6 +15267,48 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  EVT ResultVT = N->getValueType(0);
+
+  SDValue MaskVal = N->getOperand(1);
+  ConstantSDNode *MaskConst = dyn_cast<ConstantSDNode>(MaskVal);
+  if (!MaskConst)
+    return SDValue();
+  uint64_t Mask = MaskConst->getZExtValue();
+  uint64_t ExpectedMask = LoadedVT.getSizeInBits() == 8    ? 0xFF
+                          : LoadedVT.getSizeInBits() == 16 ? 0xFFFF
+                          : LoadedVT.getSizeInBits() == 32 ? 0xFFFFFFFF
+                                                           : 0xFFFFFFFFFFFFFFFF;
+  if (Mask != ExpectedMask)
+    return SDValue();
+
+  SDLoc DL(N);
+  SDValue Chain = ALoad->getChain();
+  SDValue Ptr = ALoad->getBasePtr();
+  MachineMemOperand *MemOp = ALoad->getMemOperand();
+  SDValue ZextLoad = DAG.getExtLoad(ISD::ZEXTLOAD, DL, ResultVT, Chain, Ptr,
+                                    MemOp->getPointerInfo(), LoadedVT,
+                                    MemOp->getAlign(), MemOp->getFlags());
+  DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), ZextLoad);
path: llvm/lib/Target/RISCV/RISCVISelLowering.cpp
user: login: topperc
body: We should use `DCI.CombineTo(N, ZextLoad)` instead of `DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), ZextLoad)`
created_at: 2025-04-24T01:03:41Z
author_association: COLLABORATOR
diff_hunk: @@ -15274,6 +15274,50 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+  if (!N0.hasOneUse())
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  EVT ResultVT = N->getValueType(0);
+
+  SDValue MaskVal = N->getOperand(1);
+  ConstantSDNode *MaskConst = dyn_cast<ConstantSDNode>(MaskVal);
+  if (!MaskConst)
+    return SDValue();
+  uint64_t Mask = MaskConst->getZExtValue();
+  uint64_t ExpectedMask = LoadedVT.getSizeInBits() == 8    ? 0xFF
path: llvm/lib/Target/RISCV/RISCVISelLowering.cpp
user: login: topperc
body: Can we use `maskTrailingOnes<uint64_t>(LoadedVT.getSizeInBits())`?
created_at: 2025-04-24T19:19:45Z
author_association: COLLABORATOR
diff_hunk: @@ -15280,6 +15280,40 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+  if (!N0.hasOneUse())
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  uint64_t Mask = maskTrailingOnes<uint64_t>(LoadedVT.getSizeInBits());
path: llvm/lib/Target/RISCV/RISCVISelLowering.cpp
user: login: topperc
body: You're no longer getting the mask from the AND. Mask and ExpectedMask are always the same.
created_at: 2025-04-25T16:10:26Z
author_association: COLLABORATOR

PR comments:
user: login: llvmbot
created_at: 2025-04-20T18:58:15Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Jan Górski (janagor)

<details>
<summary>Changes</summary>

Extends changes from [ff687af](https://github.com/llvm/llvm-project/commit/ff687af04f5b0e85305250587b524cb0b3849aa0).
Fixes https://github.com/llvm/llvm-project/issues/131476.

This patch adds a DAG combine to replace an `AND` of an `ATOMIC_LOAD` with a full-bit mask (e.g. `0xFF`, `0xFFFF`, etc.) which is generated as a result of `(zext (atomic_load))`,  by a zero-extended load, provided the atomic operation is monotonic or weaker.


---

Patch is 45.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/136502.diff


2 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+44) 
- (added) llvm/test/CodeGen/RISCV/atomic-load-zext.ll (+1276) 


``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 98fba9e86e88a..2ec2ccb8cf132 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15220,6 +15220,48 @@ static SDValue reverseZExtICmpCombine(SDNode *N, SelectionDAG &DAG,
   return DAG.getNode(ISD::ZERO_EXTEND, DL, VT, Res);
 }
 
+static SDValue reduceANDOfAtomicLoad(SDNode *N,
+                                     TargetLowering::DAGCombinerInfo &DCI) {
+  SelectionDAG &DAG = DCI.DAG;
+  if (N->getOpcode() != ISD::AND)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+  if (N0.getOpcode() != ISD::ATOMIC_LOAD)
+    return SDValue();
+
+  AtomicSDNode *ALoad = cast<AtomicSDNode>(N0.getNode());
+  if (isStrongerThanMonotonic(ALoad->getSuccessOrdering()))
+    return SDValue();
+
+  EVT LoadedVT = ALoad->getMemoryVT();
+  EVT ResultVT = N->getValueType(0);
+
+  SDValue MaskVal = N->getOperand(1);
+  ConstantSDNode *MaskConst = dyn_cast<ConstantSDNode>(MaskVal);
+  if (!MaskConst)
+    return SDValue();
+  uint64_t Mask = MaskConst->getZExtValue();
+  uint64_t ExpectedMask = LoadedVT.getSizeInBits() == 8    ? 0xFF
+                          : LoadedVT.getSizeInBits() == 16 ? 0xFFFF
+                          : LoadedVT.getSizeInBits() == 32 ? 0xFFFFFFFF
+                                                           : 0xFFFFFFFFFFFFFFFF;
+  if (Mask != ExpectedMask)
+    return SDValue();
+
+  SDLoc DL(N);
+  SDValue Chain = ALoad->getChain();
+  SDValue Ptr = ALoad->getBasePtr();
+  MachineMemOperand *MemOp = ALoad->getMemOperand();
+  SDValue ZextLoad = DAG.getExtLoad(ISD::ZEXTLOAD, DL, ResultVT, Chain, Ptr,
+                                    MemOp->getPointerInfo(), LoadedVT,
+                                    MemOp->getAlign(), MemOp->getFlags());
+  DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), ZextLoad);
+  DAG.ReplaceAllUsesOfValueWith(SDValue(N0.getNode(), 1), ZextLoad.getValue(1));
+  DCI.recursivelyDeleteUnusedNodes(N0.getNode());
+  return SDValue(N, 0);
+}
+
 // Combines two comparison operation and logic operation to one selection
 // operation(min, max) and logic operation. Returns new constructed Node if
 // conditions for optimization are satisfied.
@@ -15254,6 +15296,8 @@ static SDValue performANDCombine(SDNode *N,
     return V;
   if (SDValue V = combineBinOpOfExtractToReduceTree(N, DAG, Subtarget))
     return V;
+  if (SDValue V = reduceANDOfAtomicLoad(N, DCI))
+    return V;
 
   if (DCI.isAfterLegalizeDAG())
     if (SDValue V = combineDeMorganOfBoolean(N, DAG))
diff --git a/llvm/test/CodeGen/RISCV/atomic-load-zext.ll b/llvm/test/CodeGen/RISCV/atomic-load-zext.ll
new file mode 100644
index 0000000000000..1fcf5f085646d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/atomic-load-zext.ll
@@ -0,0 +1,1276 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv32 -mattr=+a,+no-trailing-seq-cst-fence -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-WMO %s
+; RUN: llc -mtriple=riscv32 -mattr=+a,+ztso,+no-trailing-seq-cst-fence -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-TSO %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+a,+no-trailing-seq-cst-fence -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-WMO %s
+; RUN: llc -mtriple=riscv64 -mattr=+a,+ztso,+no-trailing-seq-cst-fence -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-TSO %s
+
+
+; RUN: llc -mtriple=riscv32 -mattr=+a -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-WMO-TRAILING-FENCE %s
+; RUN: llc -mtriple=riscv32 -mattr=+a,+ztso -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-TSO-TRAILING-FENCE %s
+
+; RUN: llc -mtriple=riscv64 -mattr=+a -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-WMO-TRAILING-FENCE %s
+; RUN: llc -mtriple=riscv64 -mattr=+a,+ztso -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-TSO-TRAILING-FENCE %s
+
+; RUN: llc -mtriple=riscv32 -mattr=+a,+experimental-zalasr -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-ZALASR,RV32IA-ZALASR-WMO %s
+; RUN: llc -mtriple=riscv32 -mattr=+a,+experimental-zalasr,+ztso -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV32IA,RV32IA-ZALASR,RV32IA-ZALASR-TSO %s
+
+; RUN: llc -mtriple=riscv64 -mattr=+a,+experimental-zalasr -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-ZALASR,RV64IA-ZALASR-WMO %s
+; RUN: llc -mtriple=riscv64 -mattr=+a,+experimental-zalasr,+ztso -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64IA,RV64IA-ZALASR,RV64IA-ZALASR-TSO %s
+
+define zeroext i1 @atomic_load_i1_unordered(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i1_unordered:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 0
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    andi a0, a0, 1
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-LABEL: atomic_load_i1_unordered:
+; RV32IA:       # %bb.0:
+; RV32IA-NEXT:    lbu a0, 0(a0)
+; RV32IA-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i1_unordered:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 0
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    andi a0, a0, 1
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-LABEL: atomic_load_i1_unordered:
+; RV64IA:       # %bb.0:
+; RV64IA-NEXT:    lbu a0, 0(a0)
+; RV64IA-NEXT:    ret
+  %1 = load atomic i8, ptr %a unordered, align 1
+  %2 = trunc nuw i8 %1 to i1
+  ret i1 %2
+}
+
+define zeroext i1 @atomic_load_i1_monotonic(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i1_monotonic:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 0
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    andi a0, a0, 1
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-LABEL: atomic_load_i1_monotonic:
+; RV32IA:       # %bb.0:
+; RV32IA-NEXT:    lbu a0, 0(a0)
+; RV32IA-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i1_monotonic:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 0
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    andi a0, a0, 1
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-LABEL: atomic_load_i1_monotonic:
+; RV64IA:       # %bb.0:
+; RV64IA-NEXT:    lbu a0, 0(a0)
+; RV64IA-NEXT:    ret
+  %1 = load atomic i8, ptr %a monotonic, align 1
+  %2 = trunc nuw i8 %1 to i1
+  ret i1 %2
+}
+
+define zeroext i1 @atomic_load_i1_acquire(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i1_acquire:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 2
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    andi a0, a0, 1
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-WMO-LABEL: atomic_load_i1_acquire:
+; RV32IA-WMO:       # %bb.0:
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-NEXT:    fence r, rw
+; RV32IA-WMO-NEXT:    ret
+;
+; RV32IA-TSO-LABEL: atomic_load_i1_acquire:
+; RV32IA-TSO:       # %bb.0:
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i1_acquire:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 2
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    andi a0, a0, 1
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-WMO-LABEL: atomic_load_i1_acquire:
+; RV64IA-WMO:       # %bb.0:
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-NEXT:    fence r, rw
+; RV64IA-WMO-NEXT:    ret
+;
+; RV64IA-TSO-LABEL: atomic_load_i1_acquire:
+; RV64IA-TSO:       # %bb.0:
+; RV64IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-NEXT:    ret
+;
+; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i1_acquire:
+; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i1_acquire:
+; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i1_acquire:
+; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i1_acquire:
+; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-ZALASR-WMO-LABEL: atomic_load_i1_acquire:
+; RV32IA-ZALASR-WMO:       # %bb.0:
+; RV32IA-ZALASR-WMO-NEXT:    lb.aq a0, (a0)
+; RV32IA-ZALASR-WMO-NEXT:    zext.b a0, a0
+; RV32IA-ZALASR-WMO-NEXT:    ret
+;
+; RV32IA-ZALASR-TSO-LABEL: atomic_load_i1_acquire:
+; RV32IA-ZALASR-TSO:       # %bb.0:
+; RV32IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-ZALASR-TSO-NEXT:    ret
+;
+; RV64IA-ZALASR-WMO-LABEL: atomic_load_i1_acquire:
+; RV64IA-ZALASR-WMO:       # %bb.0:
+; RV64IA-ZALASR-WMO-NEXT:    lb.aq a0, (a0)
+; RV64IA-ZALASR-WMO-NEXT:    zext.b a0, a0
+; RV64IA-ZALASR-WMO-NEXT:    ret
+;
+; RV64IA-ZALASR-TSO-LABEL: atomic_load_i1_acquire:
+; RV64IA-ZALASR-TSO:       # %bb.0:
+; RV64IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
+; RV64IA-ZALASR-TSO-NEXT:    ret
+  %1 = load atomic i8, ptr %a acquire, align 1
+  %2 = trunc nuw i8 %1 to i1
+  ret i1 %2
+}
+
+define zeroext i1 @atomic_load_i1_seq_cst(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i1_seq_cst:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 5
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    andi a0, a0, 1
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-WMO-LABEL: atomic_load_i1_seq_cst:
+; RV32IA-WMO:       # %bb.0:
+; RV32IA-WMO-NEXT:    fence rw, rw
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-NEXT:    fence r, rw
+; RV32IA-WMO-NEXT:    ret
+;
+; RV32IA-TSO-LABEL: atomic_load_i1_seq_cst:
+; RV32IA-TSO:       # %bb.0:
+; RV32IA-TSO-NEXT:    fence rw, rw
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i1_seq_cst:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 5
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    andi a0, a0, 1
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-WMO-LABEL: atomic_load_i1_seq_cst:
+; RV64IA-WMO:       # %bb.0:
+; RV64IA-WMO-NEXT:    fence rw, rw
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-NEXT:    fence r, rw
+; RV64IA-WMO-NEXT:    ret
+;
+; RV64IA-TSO-LABEL: atomic_load_i1_seq_cst:
+; RV64IA-TSO:       # %bb.0:
+; RV64IA-TSO-NEXT:    fence rw, rw
+; RV64IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-NEXT:    ret
+;
+; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i1_seq_cst:
+; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i1_seq_cst:
+; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i1_seq_cst:
+; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence rw, rw
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i1_seq_cst:
+; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    fence rw, rw
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-ZALASR-LABEL: atomic_load_i1_seq_cst:
+; RV32IA-ZALASR:       # %bb.0:
+; RV32IA-ZALASR-NEXT:    lb.aq a0, (a0)
+; RV32IA-ZALASR-NEXT:    zext.b a0, a0
+; RV32IA-ZALASR-NEXT:    ret
+;
+; RV64IA-ZALASR-LABEL: atomic_load_i1_seq_cst:
+; RV64IA-ZALASR:       # %bb.0:
+; RV64IA-ZALASR-NEXT:    lb.aq a0, (a0)
+; RV64IA-ZALASR-NEXT:    zext.b a0, a0
+; RV64IA-ZALASR-NEXT:    ret
+  %1 = load atomic i8, ptr %a seq_cst, align 1
+  %2 = trunc nuw i8 %1 to i1
+  ret i1 %2
+}
+
+define zeroext i8 @atomic_load_i8_unordered(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i8_unordered:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 0
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    zext.b a0, a0
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-LABEL: atomic_load_i8_unordered:
+; RV32IA:       # %bb.0:
+; RV32IA-NEXT:    lbu a0, 0(a0)
+; RV32IA-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i8_unordered:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 0
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    zext.b a0, a0
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-LABEL: atomic_load_i8_unordered:
+; RV64IA:       # %bb.0:
+; RV64IA-NEXT:    lbu a0, 0(a0)
+; RV64IA-NEXT:    ret
+  %1 = load atomic i8, ptr %a unordered, align 1
+  ret i8 %1
+}
+
+define zeroext i8 @atomic_load_i8_monotonic(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i8_monotonic:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 0
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    zext.b a0, a0
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-LABEL: atomic_load_i8_monotonic:
+; RV32IA:       # %bb.0:
+; RV32IA-NEXT:    lbu a0, 0(a0)
+; RV32IA-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i8_monotonic:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 0
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    zext.b a0, a0
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-LABEL: atomic_load_i8_monotonic:
+; RV64IA:       # %bb.0:
+; RV64IA-NEXT:    lbu a0, 0(a0)
+; RV64IA-NEXT:    ret
+  %1 = load atomic i8, ptr %a monotonic, align 1
+  ret i8 %1
+}
+
+define zeroext i8 @atomic_load_i8_acquire(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i8_acquire:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 2
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    zext.b a0, a0
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-WMO-LABEL: atomic_load_i8_acquire:
+; RV32IA-WMO:       # %bb.0:
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-NEXT:    fence r, rw
+; RV32IA-WMO-NEXT:    ret
+;
+; RV32IA-TSO-LABEL: atomic_load_i8_acquire:
+; RV32IA-TSO:       # %bb.0:
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i8_acquire:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 2
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    zext.b a0, a0
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-WMO-LABEL: atomic_load_i8_acquire:
+; RV64IA-WMO:       # %bb.0:
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-NEXT:    fence r, rw
+; RV64IA-WMO-NEXT:    ret
+;
+; RV64IA-TSO-LABEL: atomic_load_i8_acquire:
+; RV64IA-TSO:       # %bb.0:
+; RV64IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-NEXT:    ret
+;
+; RV32IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
+; RV32IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV32IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
+; RV32IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-WMO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
+; RV64IA-WMO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    fence r, rw
+; RV64IA-WMO-TRAILING-FENCE-NEXT:    ret
+;
+; RV64IA-TSO-TRAILING-FENCE-LABEL: atomic_load_i8_acquire:
+; RV64IA-TSO-TRAILING-FENCE:       # %bb.0:
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    lbu a0, 0(a0)
+; RV64IA-TSO-TRAILING-FENCE-NEXT:    ret
+;
+; RV32IA-ZALASR-WMO-LABEL: atomic_load_i8_acquire:
+; RV32IA-ZALASR-WMO:       # %bb.0:
+; RV32IA-ZALASR-WMO-NEXT:    lb.aq a0, (a0)
+; RV32IA-ZALASR-WMO-NEXT:    zext.b a0, a0
+; RV32IA-ZALASR-WMO-NEXT:    ret
+;
+; RV32IA-ZALASR-TSO-LABEL: atomic_load_i8_acquire:
+; RV32IA-ZALASR-TSO:       # %bb.0:
+; RV32IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-ZALASR-TSO-NEXT:    ret
+;
+; RV64IA-ZALASR-WMO-LABEL: atomic_load_i8_acquire:
+; RV64IA-ZALASR-WMO:       # %bb.0:
+; RV64IA-ZALASR-WMO-NEXT:    lb.aq a0, (a0)
+; RV64IA-ZALASR-WMO-NEXT:    zext.b a0, a0
+; RV64IA-ZALASR-WMO-NEXT:    ret
+;
+; RV64IA-ZALASR-TSO-LABEL: atomic_load_i8_acquire:
+; RV64IA-ZALASR-TSO:       # %bb.0:
+; RV64IA-ZALASR-TSO-NEXT:    lbu a0, 0(a0)
+; RV64IA-ZALASR-TSO-NEXT:    ret
+  %1 = load atomic i8, ptr %a acquire, align 1
+  ret i8 %1
+}
+
+define zeroext i8 @atomic_load_i8_seq_cst(ptr %a) nounwind {
+; RV32I-LABEL: atomic_load_i8_seq_cst:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    li a1, 5
+; RV32I-NEXT:    call __atomic_load_1
+; RV32I-NEXT:    zext.b a0, a0
+; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV32IA-WMO-LABEL: atomic_load_i8_seq_cst:
+; RV32IA-WMO:       # %bb.0:
+; RV32IA-WMO-NEXT:    fence rw, rw
+; RV32IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV32IA-WMO-NEXT:    fence r, rw
+; RV32IA-WMO-NEXT:    ret
+;
+; RV32IA-TSO-LABEL: atomic_load_i8_seq_cst:
+; RV32IA-TSO:       # %bb.0:
+; RV32IA-TSO-NEXT:    fence rw, rw
+; RV32IA-TSO-NEXT:    lbu a0, 0(a0)
+; RV32IA-TSO-NEXT:    ret
+;
+; RV64I-LABEL: atomic_load_i8_seq_cst:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    li a1, 5
+; RV64I-NEXT:    call __atomic_load_1
+; RV64I-NEXT:    zext.b a0, a0
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64IA-WMO-LABEL: atomic_load_i8_seq_cst:
+; RV64IA-WMO:       # %bb.0:
+; RV64IA-WMO-NEXT:    fence rw, rw
+; RV64IA-WMO-NEXT:    lbu a0, 0(a0)
+; RV64IA-WMO-NEXT:    fence ...
[truncated]

``````````

</details>

author_association: MEMBER
user: login: lenary
created_at: 2025-04-21T09:56:22Z
body: The title of this PR is still wrong, it's not adding range metadata at all. It's doing some kind of combine. I don't know what the right name should be, maybe `[RISCV] Remove ZEXT after some atomic loads` or similar?
author_association: MEMBER
user: login: topperc
created_at: 2025-04-22T22:53:10Z
body: I spoke with @preames and he told me that it is not safe to replace an ISD::ATOMIC_LOAD with an ISD::LOAD in the current SelectionDAG. I think there are optimizations that don't expect an ISD::LOAD to be atomic and make unsafe changes.

We should make an ISD::ATOMIC_LOAD here with ISD::ZEXTLOAD extension type. I made a couple patches yesterday to make that more possible 704fc6542cf171c603bd387663a2de3a3fa9c4ff and f6178cdad03468a9801a23f8f7e80927614fdb7e.
author_association: COLLABORATOR
user: login: janagor
created_at: 2025-04-23T07:20:55Z
body: For _testing purposes only_ I reverted the changes from this patch and made such change:
```
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index 53244a990a86..bb247574a5f2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -386,6 +386,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic0(AtomicSDNode *N) {
     switch (TLI.getExtendForAtomicOps()) {
     case ISD::SIGN_EXTEND:
       ExtType = ISD::SEXTLOAD;
+      ExtType = ISD::ZEXTLOAD;
       break;
     case ISD::ZERO_EXTEND:
       ExtType = ISD::ZEXTLOAD;
```
just to check what is generated for a following snippet (the code from original [issue](https://github.com/llvm/llvm-project/issues/131476)):
```c
#include <stdbool.h>
extern bool t1;
bool test1(void) {
    return __atomic_load_n(&t1, __ATOMIC_RELAXED);
}
```
I run:
```bash
./bin/clang --target=riscv64 -O1 -S -emit-llvm atomic-ops-load.c -o test.ll
./bin/llc -filetype=asm test.ll -o test.s -O1 -mtriple=riscv64 --print-after-isel -debug 2> result.txt
```
I got following instructions:
```
test1:                                  # @test1
# %bb.0:                                # %entry
        lui     a0, %hi(t1)
        lb      a0, %lo(t1)(a0)
        ret
.Lfunc_end0:
```
with debug file info that I attached to this comment: [result.txt](https://github.com/user-attachments/files/19862687/result.txt). I think the main thing from it is the following info:
```
ISEL: Starting selection on root node: t9: i64,ch = AtomicLoad<(dereferenceable load monotonic (s8) from @t1), zext from i8> t0, t15
ISEL: Starting pattern match
  Initial Opcode index to 1152977
  TypeSwitch[i64] from 1152986 to 1152989
  Morphed node: t9: i64,ch = LB<Mem:(dereferenceable load monotonic (s8) from @t1)> t14, TargetGlobalAddress:i64<ptr @t1> 0 [TF=3], t0
ISEL: Match complete!
```

It seems to me that changing extention type of ISD::ATOMIC_LOAD is not enough. Does this imply that there should be a match for `(zext(atomic_load))` in tablegen that would catch this pattern?




author_association: CONTRIBUTOR
user: login: topperc
created_at: 2025-04-23T16:51:50Z
body: > For _testing purposes only_ I reverted the changes from this patch and made such change:
> 
> ```
> diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> index 53244a990a86..bb247574a5f2 100644
> --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> @@ -386,6 +386,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic0(AtomicSDNode *N) {
>      switch (TLI.getExtendForAtomicOps()) {
>      case ISD::SIGN_EXTEND:
>        ExtType = ISD::SEXTLOAD;
> +      ExtType = ISD::ZEXTLOAD;
>        break;
>      case ISD::ZERO_EXTEND:
>        ExtType = ISD::ZEXTLOAD;
> ```
> 
> just to check what is generated for a following snippet (the code from original [issue](https://github.com/llvm/llvm-project/issues/131476)):
> 
> ```c
> #include <stdbool.h>
> extern bool t1;
> bool test1(void) {
>     return __atomic_load_n(&t1, __ATOMIC_RELAXED);
> }
> ```
> 
> I run:
> 
> ```shell
> ./bin/clang --target=riscv64 -O1 -S -emit-llvm atomic-ops-load.c -o test.ll
> ./bin/llc -filetype=asm test.ll -o test.s -O1 -mtriple=riscv64 --print-after-isel -debug 2> result.txt
> ```
> 
> I got following instructions:
> 
> ```
> test1:                                  # @test1
> # %bb.0:                                # %entry
>         lui     a0, %hi(t1)
>         lb      a0, %lo(t1)(a0)
>         ret
> .Lfunc_end0:
> ```
> 
> with debug file info that I attached to this comment: [result.txt](https://github.com/user-attachments/files/19862687/result.txt). I think the main thing from it is the following info:
> 
> ```
> ISEL: Starting selection on root node: t9: i64,ch = AtomicLoad<(dereferenceable load monotonic (s8) from @t1), zext from i8> t0, t15
> ISEL: Starting pattern match
>   Initial Opcode index to 1152977
>   TypeSwitch[i64] from 1152986 to 1152989
>   Morphed node: t9: i64,ch = LB<Mem:(dereferenceable load monotonic (s8) from @t1)> t14, TargetGlobalAddress:i64<ptr @t1> 0 [TF=3], t0
> ISEL: Match complete!
> ```
> 
> It seems to me that changing extention type of ISD::ATOMIC_LOAD is not enough. Does this imply that there should be a match for `(zext(atomic_load))` in tablegen that would catch this pattern?

I just posted https://github.com/llvm/llvm-project/pull/137019 to check the extension type in isel patterns. Once that's in we can add new predicates for zextload.
author_association: COLLABORATOR
user: login: topperc
created_at: 2025-04-24T00:45:21Z
body: > > For _testing purposes only_ I reverted the changes from this patch and made such change:
> > ```
> > diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> > index 53244a990a86..bb247574a5f2 100644
> > --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> > +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> > @@ -386,6 +386,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic0(AtomicSDNode *N) {
> >      switch (TLI.getExtendForAtomicOps()) {
> >      case ISD::SIGN_EXTEND:
> >        ExtType = ISD::SEXTLOAD;
> > +      ExtType = ISD::ZEXTLOAD;
> >        break;
> >      case ISD::ZERO_EXTEND:
> >        ExtType = ISD::ZEXTLOAD;
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > just to check what is generated for a following snippet (the code from original [issue](https://github.com/llvm/llvm-project/issues/131476)):
> > ```c
> > #include <stdbool.h>
> > extern bool t1;
> > bool test1(void) {
> >     return __atomic_load_n(&t1, __ATOMIC_RELAXED);
> > }
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > I run:
> > ```shell
> > ./bin/clang --target=riscv64 -O1 -S -emit-llvm atomic-ops-load.c -o test.ll
> > ./bin/llc -filetype=asm test.ll -o test.s -O1 -mtriple=riscv64 --print-after-isel -debug 2> result.txt
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > I got following instructions:
> > ```
> > test1:                                  # @test1
> > # %bb.0:                                # %entry
> >         lui     a0, %hi(t1)
> >         lb      a0, %lo(t1)(a0)
> >         ret
> > .Lfunc_end0:
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > with debug file info that I attached to this comment: [result.txt](https://github.com/user-attachments/files/19862687/result.txt). I think the main thing from it is the following info:
> > ```
> > ISEL: Starting selection on root node: t9: i64,ch = AtomicLoad<(dereferenceable load monotonic (s8) from @t1), zext from i8> t0, t15
> > ISEL: Starting pattern match
> >   Initial Opcode index to 1152977
> >   TypeSwitch[i64] from 1152986 to 1152989
> >   Morphed node: t9: i64,ch = LB<Mem:(dereferenceable load monotonic (s8) from @t1)> t14, TargetGlobalAddress:i64<ptr @t1> 0 [TF=3], t0
> > ISEL: Match complete!
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > It seems to me that changing extention type of ISD::ATOMIC_LOAD is not enough. Does this imply that there should be a match for `(zext(atomic_load))` in tablegen that would catch this pattern?
> 
> I just posted #137019 to check the extension type in isel patterns. Once that's in we can add new predicates for zextload.

That patch landed. I have https://github.com/llvm/llvm-project/pull/137096 to try to fix the tablegen infrastructure. If that goes in we can use atomic_load_zext_8/16/32 for this patch.
author_association: COLLABORATOR
user: login: janagor
created_at: 2025-04-26T13:28:28Z
body: > LGTM

Thanks @topperc. I don’t have commit access, can you merge this PR for me?
author_association: CONTRIBUTOR