Skip to content

Commit 13503e2

Browse files
committed
[EarlyCSE] Add support for writeonly call CSE
1 parent 3d51cf4 commit 13503e2

File tree

2 files changed

+26
-23
lines changed

2 files changed

+26
-23
lines changed

llvm/lib/Transforms/Scalar/EarlyCSE.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ struct CallValue {
493493

494494
static bool canHandle(Instruction *Inst) {
495495
CallInst *CI = dyn_cast<CallInst>(Inst);
496-
if (!CI || !CI->onlyReadsMemory() ||
496+
if (!CI || (!CI->onlyReadsMemory() && !CI->onlyWritesMemory()) ||
497497
// FIXME: Currently the calls which may access the thread id may
498498
// be considered as not accessing the memory. But this is
499499
// problematic for coroutines, since coroutines may resume in a
@@ -1626,14 +1626,17 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
16261626
!(MemInst.isValid() && !MemInst.mayReadFromMemory()))
16271627
LastStore = nullptr;
16281628

1629-
// If this is a read-only call, process it.
1630-
if (CallValue::canHandle(&Inst)) {
1629+
// If this is a read-only or write-only call, process it. Skip store
1630+
// MemInsts, as they will be more precisely handled lateron.
1631+
if (CallValue::canHandle(&Inst) &&
1632+
(!MemInst.isValid() || !MemInst.isStore())) {
16311633
// If we have an available version of this call, and if it is the right
16321634
// generation, replace this instruction.
16331635
std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
16341636
if (InVal.first != nullptr &&
16351637
isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1636-
&Inst)) {
1638+
&Inst) &&
1639+
InVal.first->mayReadFromMemory() == Inst.mayReadFromMemory()) {
16371640
LLVM_DEBUG(dbgs() << "EarlyCSE CSE CALL: " << Inst
16381641
<< " to: " << *InVal.first << '\n');
16391642
if (!DebugCounter::shouldExecute(CSECounter)) {
@@ -1651,6 +1654,11 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
16511654
continue;
16521655
}
16531656

1657+
// Increase memory generation for writes. Do this before inserting
1658+
// the call, so it has the generation after the write occurred.
1659+
if (Inst.mayWriteToMemory())
1660+
++CurrentGeneration;
1661+
16541662
// Otherwise, remember that we have this instruction.
16551663
AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
16561664
continue;

llvm/test/Transforms/EarlyCSE/writeonly.ll

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ declare void @writeonly_void() memory(write)
2323
define void @writeonly_cse() {
2424
; CHECK-LABEL: @writeonly_cse(
2525
; CHECK-NEXT: call void @writeonly_void()
26-
; CHECK-NEXT: call void @writeonly_void()
2726
; CHECK-NEXT: ret void
2827
;
2928
call void @writeonly_void()
@@ -36,7 +35,6 @@ define i32 @writeonly_cse_intervening_load(ptr %p) {
3635
; CHECK-LABEL: @writeonly_cse_intervening_load(
3736
; CHECK-NEXT: call void @writeonly_void()
3837
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
39-
; CHECK-NEXT: call void @writeonly_void()
4038
; CHECK-NEXT: ret i32 [[V]]
4139
;
4240
call void @writeonly_void()
@@ -61,11 +59,16 @@ define void @writeonly_cse_intervening_store(ptr %p) {
6159

6260
; Can CSE, the store does not alias the writeonly call.
6361
define void @writeonly_cse_intervening_noalias_store(ptr noalias %p) {
64-
; CHECK-LABEL: @writeonly_cse_intervening_noalias_store(
65-
; CHECK-NEXT: call void @writeonly_void()
66-
; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
67-
; CHECK-NEXT: call void @writeonly_void()
68-
; CHECK-NEXT: ret void
62+
; NO-MSSA-LABEL: @writeonly_cse_intervening_noalias_store(
63+
; NO-MSSA-NEXT: call void @writeonly_void()
64+
; NO-MSSA-NEXT: store i32 0, ptr [[P:%.*]], align 4
65+
; NO-MSSA-NEXT: call void @writeonly_void()
66+
; NO-MSSA-NEXT: ret void
67+
;
68+
; MSSA-LABEL: @writeonly_cse_intervening_noalias_store(
69+
; MSSA-NEXT: call void @writeonly_void()
70+
; MSSA-NEXT: store i32 0, ptr [[P:%.*]], align 4
71+
; MSSA-NEXT: ret void
6972
;
7073
call void @writeonly_void()
7174
store i32 0, ptr %p
@@ -93,11 +96,8 @@ define i32 @load_cse_across_writeonly(ptr %p) {
9396
define i32 @load_cse_across_csed_writeonly(ptr %p) {
9497
; CHECK-LABEL: @load_cse_across_csed_writeonly(
9598
; CHECK-NEXT: call void @writeonly_void()
96-
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4
97-
; CHECK-NEXT: call void @writeonly_void()
98-
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
99-
; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
100-
; CHECK-NEXT: ret i32 [[RES]]
99+
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P:%.*]], align 4
100+
; CHECK-NEXT: ret i32 0
101101
;
102102
call void @writeonly_void()
103103
%v1 = load i32, ptr %p
@@ -112,10 +112,8 @@ declare i32 @writeonly(ptr %p) memory(write)
112112
; Can CSE writeonly calls with arg and return.
113113
define i32 @writeonly_ret_cse(ptr %p) {
114114
; CHECK-LABEL: @writeonly_ret_cse(
115-
; CHECK-NEXT: [[V1:%.*]] = call i32 @writeonly(ptr [[P:%.*]])
116-
; CHECK-NEXT: [[V2:%.*]] = call i32 @writeonly(ptr [[P]])
117-
; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
118-
; CHECK-NEXT: ret i32 [[RES]]
115+
; CHECK-NEXT: [[V2:%.*]] = call i32 @writeonly(ptr [[P:%.*]])
116+
; CHECK-NEXT: ret i32 0
119117
;
120118
%v1 = call i32 @writeonly(ptr %p)
121119
%v2 = call i32 @writeonly(ptr %p)
@@ -163,6 +161,3 @@ define void @writeonly_and_readonly() {
163161
call void @callee() memory(read)
164162
ret void
165163
}
166-
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
167-
; MSSA: {{.*}}
168-
; NO-MSSA: {{.*}}

0 commit comments

Comments
 (0)