Skip to content

Commit 9df1c81

Browse files
authored
[SelectionDAG] Combine range metadata when loads are CSEd. (#146026)
When CSEing a load with an existing load with different range metadata, clear the range metadata on the existing load. This is conservative, alternatively we could calculate new range metadata using MDNode::getMostGenericRange. Without a test case I wasn't sure it was worth it. MDnode::getMostGenericRange takes a non-const MDNode*, but all of SelectionDAG uses const MDNode*. A const_cast will need to be used somewhere or we need to make the codebase consistent about whether MDNode pointers should be const or not. I'm sure this isn't the only place that needs to be updated to handle the CSE. Fixes #145363.
1 parent 375af75 commit 9df1c81

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

llvm/include/llvm/CodeGen/SelectionDAGNodes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,14 @@ class MemSDNode : public SDNode {
14971497
MMO->refineAlignment(NewMMO);
14981498
}
14991499

1500+
void refineRanges(const MachineMemOperand *NewMMO) {
1501+
// If this node has range metadata that is different than NewMMO, clear the
1502+
// range metadata.
1503+
// FIXME: Union the ranges instead?
1504+
if (getRanges() && getRanges() != NewMMO->getRanges())
1505+
MMO->clearRanges();
1506+
}
1507+
15001508
const SDValue &getChain() const { return getOperand(0); }
15011509

15021510
const SDValue &getBasePtr() const {

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,8 @@ SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) {
12751275
// to replace the dead one with the existing one. This can cause
12761276
// recursive merging of other unrelated nodes down the line.
12771277
Existing->intersectFlagsWith(N->getFlags());
1278+
if (auto *MemNode = dyn_cast<MemSDNode>(Existing))
1279+
MemNode->refineRanges(cast<MemSDNode>(N)->getMemOperand());
12781280
ReplaceAllUsesWith(N, Existing);
12791281

12801282
// N is now dead. Inform the listeners and delete it.
@@ -9110,8 +9112,9 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT,
91109112
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
91119113
ID.AddInteger(MMO->getFlags());
91129114
void* IP = nullptr;
9113-
if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) {
9114-
cast<AtomicSDNode>(E)->refineAlignment(MMO);
9115+
if (auto *E = cast_or_null<AtomicSDNode>(FindNodeOrInsertPos(ID, dl, IP))) {
9116+
E->refineAlignment(MMO);
9117+
E->refineRanges(MMO);
91159118
return SDValue(E, 0);
91169119
}
91179120

@@ -9402,8 +9405,9 @@ SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType,
94029405
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
94039406
ID.AddInteger(MMO->getFlags());
94049407
void *IP = nullptr;
9405-
if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) {
9406-
cast<LoadSDNode>(E)->refineAlignment(MMO);
9408+
if (auto *E = cast_or_null<LoadSDNode>(FindNodeOrInsertPos(ID, dl, IP))) {
9409+
E->refineAlignment(MMO);
9410+
E->refineRanges(MMO);
94079411
return SDValue(E, 0);
94089412
}
94099413
auto *N = newSDNode<LoadSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM,
@@ -9623,8 +9627,9 @@ SDValue SelectionDAG::getLoadVP(ISD::MemIndexedMode AM,
96239627
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
96249628
ID.AddInteger(MMO->getFlags());
96259629
void *IP = nullptr;
9626-
if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) {
9627-
cast<VPLoadSDNode>(E)->refineAlignment(MMO);
9630+
if (auto *E = cast_or_null<VPLoadSDNode>(FindNodeOrInsertPos(ID, dl, IP))) {
9631+
E->refineAlignment(MMO);
9632+
E->refineRanges(MMO);
96289633
return SDValue(E, 0);
96299634
}
96309635
auto *N = newSDNode<VPLoadSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM,

llvm/test/CodeGen/RISCV/pr145363.ll

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc < %s -mtriple=riscv64 | FileCheck %s
3+
4+
; These two loads will CSE, we need to conservatively combine the range
5+
; metadata. The final assembly should not contain an OR.
6+
define i32 @f(ptr %p) {
7+
; CHECK-LABEL: f:
8+
; CHECK: # %bb.0:
9+
; CHECK-NEXT: lw a0, 0(a0)
10+
; CHECK-NEXT: lui a1, 294471
11+
; CHECK-NEXT: addi a1, a1, 1064
12+
; CHECK-NEXT: addw a0, a0, a1
13+
; CHECK-NEXT: ret
14+
%load = load i32, ptr %p, align 4, !range !0
15+
%load2 = load i32, ptr %p, align 4
16+
%add = add i32 1206154280, %load2
17+
ret i32 %add
18+
}
19+
20+
; The mul and getelementptr will get removed in DAGCombine causing the loads
21+
; to CSE after they are created.
22+
define i32 @test(ptr %p, i32 %x, ptr %q) {
23+
; CHECK-LABEL: test:
24+
; CHECK: # %bb.0:
25+
; CHECK-NEXT: lw a1, 0(a0)
26+
; CHECK-NEXT: lui a0, 294471
27+
; CHECK-NEXT: addi a0, a0, 1064
28+
; CHECK-NEXT: addw a0, a1, a0
29+
; CHECK-NEXT: sw a1, 0(a2)
30+
; CHECK-NEXT: ret
31+
%load = load i32, ptr %p, align 4, !range !0
32+
%mul = mul i32 0, %x
33+
%a = getelementptr i32, ptr %p, i32 %mul
34+
%load2 = load i32, ptr %a, align 4
35+
%add = add i32 1206154280, %load2
36+
store i32 %load, ptr %q
37+
ret i32 %add
38+
}
39+
40+
!0 = !{i32 1, i32 2, i32 3, i32 4}

0 commit comments

Comments
 (0)