Skip to content

Commit

Permalink
[CGP] Undo constant propagation of pointers across calls
Browse files Browse the repository at this point in the history
It may be profitable to revert SCCP propagation of C++ static values,
if such constants are pointers, in order to avoid redundant pointer
computation, since the method returning the constant is non-removable.
  • Loading branch information
antoniofrighetto committed Sep 2, 2024
1 parent ed6d9f6 commit e4e0dfb
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
48 changes: 47 additions & 1 deletion llvm/lib/CodeGen/CodeGenPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2677,7 +2677,8 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, ModifyDT &ModifiedDT) {
}

// From here on out we're working with named functions.
if (!CI->getCalledFunction())
auto *Callee = CI->getCalledFunction();
if (!Callee)
return false;

// Lower all default uses of _chk calls. This is very similar
Expand All @@ -2692,6 +2693,51 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, ModifyDT &ModifiedDT) {
return true;
}

// SCCP may have propagated, among other things, C++ static variables across
// calls. If this happens to be the case, we may want to undo it in order to
// avoid redundant pointer computation of the constant, as the function method
// returning the constant needs to be executed anyways.
auto GetUniformReturnValue = [](const Function *F) -> GlobalVariable * {
if (!F->getReturnType()->isPointerTy())
return nullptr;

GlobalVariable *UniformValue = nullptr;
for (auto &BB : *F) {
if (auto *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
if (auto *V = dyn_cast<GlobalVariable>(RI->getReturnValue())) {
if (!UniformValue)
UniformValue = V;
else if (V != UniformValue)
return nullptr;
} else {
return nullptr;
}
}
}

return UniformValue;
};

if (Callee->hasExactDefinition()) {
if (GlobalVariable *RV = GetUniformReturnValue(Callee)) {
bool MadeChange = false;
for (Use &U : make_early_inc_range(RV->uses())) {
auto *I = dyn_cast<Instruction>(U.getUser());
if (!I || I->getParent() != CI->getParent()) {
// Limit to the same basic block to avoid extending the call-site live
// range, which otherwise could increase register pressure.
continue;
}
if (CI->comesBefore(I)) {
U.set(CI);
MadeChange = true;
}
}

return MadeChange;
}
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ entry:
define i32 @caller_1() {
; CHECK-LABEL: @caller_1(
; CHECK-NEXT: [[GETS_PTR:%.*]] = call ptr @getS()
; CHECK-NEXT: [[GETI:%.*]] = call i32 @S_getI(ptr @g_getS)
; CHECK-NEXT: [[GETI:%.*]] = call i32 @S_getI(ptr [[GETS_PTR]])
; CHECK-NEXT: ret i32 [[GETI]]
;
%getS_ptr = call ptr @getS()
Expand Down

0 comments on commit e4e0dfb

Please sign in to comment.