mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Enhance SRoA to promote allocas that are used by selects in some
common cases. This triggers a surprising number of times in SPEC2K6 because min/max idioms end up doing this. For example, code from the STL ends up looking like this to SRoA: %202 = load i64* %__old_size, align 8, !tbaa !3 %203 = load i64* %__old_size, align 8, !tbaa !3 %204 = load i64* %__n, align 8, !tbaa !3 %205 = icmp ult i64 %203, %204 %storemerge.i = select i1 %205, i64* %__n, i64* %__old_size %206 = load i64* %storemerge.i, align 8, !tbaa !3 We can now promote both the __n and the __old_size allocas. This addresses another chunk of rdar://7339113, poor codegen on stringswitch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@124088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3928af6ac4
commit
c87c50a39c
@ -31,6 +31,7 @@
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Analysis/Loads.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||
@ -43,12 +44,14 @@
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(NumReplaced, "Number of allocas broken up");
|
||||
STATISTIC(NumPromoted, "Number of allocas promoted");
|
||||
STATISTIC(NumAdjusted, "Number of scalar allocas adjusted to allow promotion");
|
||||
STATISTIC(NumConverted, "Number of aggregates converted to scalar");
|
||||
STATISTIC(NumGlobals, "Number of allocas copied from constant global");
|
||||
|
||||
@ -862,6 +865,134 @@ public:
|
||||
};
|
||||
} // end anon namespace
|
||||
|
||||
/// isSafeSelectToSpeculate - Select instructions that use an alloca and are
|
||||
/// subsequently loaded can be rewritten to load both input pointers and then
|
||||
/// select between the result, allowing the load of the alloca to be promoted.
|
||||
/// From this:
|
||||
/// %P2 = select i1 %cond, i32* %Alloca, i32* %Other
|
||||
/// %V = load i32* %P2
|
||||
/// to:
|
||||
/// %V1 = load i32* %Alloca -> will be mem2reg'd
|
||||
/// %V2 = load i32* %Other
|
||||
/// %V = select i1 %cond, i32 %V1, i32* %V2
|
||||
///
|
||||
/// We can do this to a select if its only uses are loads and if the operand to
|
||||
/// the select can be loaded unconditionally.
|
||||
static bool isSafeSelectToSpeculate(SelectInst *SI, const TargetData *TD) {
|
||||
bool TDerefable = SI->getTrueValue()->isDereferenceablePointer();
|
||||
bool FDerefable = SI->getFalseValue()->isDereferenceablePointer();
|
||||
|
||||
for (Value::use_iterator UI = SI->use_begin(), UE = SI->use_end();
|
||||
UI != UE; ++UI) {
|
||||
LoadInst *LI = dyn_cast<LoadInst>(*UI);
|
||||
if (LI == 0 || LI->isVolatile()) return false;
|
||||
|
||||
// Both operands to the select need to be deferencable, either absolutely
|
||||
// (e.g. allocas) or at this point because we can see other accesses to it.
|
||||
if (!TDerefable && !isSafeToLoadUnconditionally(SI->getTrueValue(), LI,
|
||||
LI->getAlignment(), TD))
|
||||
return false;
|
||||
if (!FDerefable && !isSafeToLoadUnconditionally(SI->getFalseValue(), LI,
|
||||
LI->getAlignment(), TD))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// tryToMakeAllocaBePromotable - This returns true if the alloca only has
|
||||
/// direct (non-volatile) loads and stores to it. If the alloca is close but
|
||||
/// not quite there, this will transform the code to allow promotion. As such,
|
||||
/// it is a non-pure predicate.
|
||||
static bool tryToMakeAllocaBePromotable(AllocaInst *AI, const TargetData *TD) {
|
||||
SetVector<Instruction*, SmallVector<Instruction*, 4>,
|
||||
SmallPtrSet<Instruction*, 4> > InstsToRewrite;
|
||||
|
||||
for (Value::use_iterator UI = AI->use_begin(), UE = AI->use_end();
|
||||
UI != UE; ++UI) {
|
||||
User *U = *UI;
|
||||
if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
|
||||
if (LI->isVolatile())
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
|
||||
if (SI->getOperand(0) == AI || SI->isVolatile())
|
||||
return false; // Don't allow a store OF the AI, only INTO the AI.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(U)) {
|
||||
// If the condition being selected on is a constant, fold the select, yes
|
||||
// this does (rarely) happen early on.
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(SI->getCondition())) {
|
||||
Value *Result = SI->getOperand(1+CI->isZero());
|
||||
SI->replaceAllUsesWith(Result);
|
||||
SI->eraseFromParent();
|
||||
|
||||
// This is very rare and we just scrambled the use list of AI, start
|
||||
// over completely.
|
||||
return tryToMakeAllocaBePromotable(AI, TD);
|
||||
}
|
||||
|
||||
// If it is safe to turn "load (select c, AI, ptr)" into a select of two
|
||||
// loads, then we can transform this by rewriting the select.
|
||||
if (!isSafeSelectToSpeculate(SI, TD))
|
||||
return false;
|
||||
|
||||
InstsToRewrite.insert(SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are no instructions to rewrite, then all uses are load/stores and
|
||||
// we're done!
|
||||
if (InstsToRewrite.empty())
|
||||
return true;
|
||||
|
||||
// If we have instructions that need to be rewritten for this to be promotable
|
||||
// take care of it now.
|
||||
for (unsigned i = 0, e = InstsToRewrite.size(); i != e; ++i) {
|
||||
// Selects in InstsToRewrite only have load uses. Rewrite each as two
|
||||
// loads with a new select.
|
||||
SelectInst *SI = cast<SelectInst>(InstsToRewrite[i]);
|
||||
|
||||
for (Value::use_iterator UI = SI->use_begin(), E = SI->use_end(); UI != E;){
|
||||
LoadInst *LI = cast<LoadInst>(*UI++);
|
||||
|
||||
IRBuilder<> Builder(LI);
|
||||
LoadInst *TrueLoad =
|
||||
Builder.CreateLoad(SI->getTrueValue(), LI->getName()+".t");
|
||||
LoadInst *FalseLoad =
|
||||
Builder.CreateLoad(SI->getFalseValue(), LI->getName()+".t");
|
||||
|
||||
// Transfer alignment and TBAA info if present.
|
||||
TrueLoad->setAlignment(LI->getAlignment());
|
||||
FalseLoad->setAlignment(LI->getAlignment());
|
||||
if (MDNode *Tag = LI->getMetadata(LLVMContext::MD_tbaa)) {
|
||||
TrueLoad->setMetadata(LLVMContext::MD_tbaa, Tag);
|
||||
FalseLoad->setMetadata(LLVMContext::MD_tbaa, Tag);
|
||||
}
|
||||
|
||||
Value *V = Builder.CreateSelect(SI->getCondition(), TrueLoad, FalseLoad);
|
||||
V->takeName(LI);
|
||||
LI->replaceAllUsesWith(V);
|
||||
LI->eraseFromParent();
|
||||
}
|
||||
|
||||
// Now that all the loads are gone, the select is gone too.
|
||||
SI->eraseFromParent();
|
||||
}
|
||||
|
||||
++NumAdjusted;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SROA::performPromotion(Function &F) {
|
||||
std::vector<AllocaInst*> Allocas;
|
||||
DominatorTree *DT = 0;
|
||||
@ -879,7 +1010,7 @@ bool SROA::performPromotion(Function &F) {
|
||||
// the entry node
|
||||
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) // Is it an alloca?
|
||||
if (isAllocaPromotable(AI))
|
||||
if (tryToMakeAllocaBePromotable(AI, TD))
|
||||
Allocas.push_back(AI);
|
||||
|
||||
if (Allocas.empty()) break;
|
||||
|
@ -44,16 +44,15 @@ F:
|
||||
}
|
||||
|
||||
; CHECK: @test3
|
||||
; CHECK: %A.0 = alloca i32
|
||||
; CHECK: %A.1 = alloca i32
|
||||
; CHECK-NEXT: %Q = select i1 %c, i32 1, i32 2
|
||||
; CHECK-NEXT: ret i32 %Q
|
||||
; rdar://8904039
|
||||
define i32 @test3(i1 %c) {
|
||||
entry:
|
||||
%A = alloca {i32, i32}
|
||||
%B = getelementptr {i32, i32}* %A, i32 0, i32 0
|
||||
store i32 1, i32* %B
|
||||
%C = getelementptr {i32, i32}* %A, i32 0, i32 1
|
||||
store i32 2, i32* %B
|
||||
store i32 2, i32* %C
|
||||
|
||||
%X = select i1 %c, i32* %B, i32* %C
|
||||
%Q = load i32* %X
|
||||
@ -76,3 +75,58 @@ entry:
|
||||
%Q = load i64* %Y
|
||||
ret i64 %Q
|
||||
}
|
||||
|
||||
|
||||
;;
|
||||
;; Tests for promoting allocas used by selects.
|
||||
;; rdar://7339113
|
||||
;;
|
||||
|
||||
define i32 @test5(i32 *%P) nounwind readnone ssp {
|
||||
entry:
|
||||
%b = alloca i32, align 8
|
||||
store i32 2, i32* %b, align 8
|
||||
|
||||
;; Select on constant condition should be folded.
|
||||
%p.0 = select i1 false, i32* %b, i32* %P
|
||||
store i32 123, i32* %p.0
|
||||
|
||||
%r = load i32* %b, align 8
|
||||
ret i32 %r
|
||||
|
||||
; CHECK: @test5
|
||||
; CHECK: store i32 123, i32* %P
|
||||
; CHECK: ret i32 2
|
||||
}
|
||||
|
||||
define i32 @test6(i32 %x, i1 %c) nounwind readnone ssp {
|
||||
%a = alloca i32, align 8
|
||||
%b = alloca i32, align 8
|
||||
store i32 1, i32* %a, align 8
|
||||
store i32 2, i32* %b, align 8
|
||||
%p.0 = select i1 %c, i32* %b, i32* %a
|
||||
%r = load i32* %p.0, align 8
|
||||
ret i32 %r
|
||||
; CHECK: @test6
|
||||
; CHECK-NEXT: %r = select i1 %c, i32 2, i32 1
|
||||
; CHECK-NEXT: ret i32 %r
|
||||
}
|
||||
|
||||
; Verify that the loads happen where the loads are, not where the select is.
|
||||
define i32 @test7(i32 %x, i1 %c) nounwind readnone ssp {
|
||||
%a = alloca i32, align 8
|
||||
%b = alloca i32, align 8
|
||||
store i32 1, i32* %a
|
||||
store i32 2, i32* %b
|
||||
%p.0 = select i1 %c, i32* %b, i32* %a
|
||||
|
||||
store i32 0, i32* %a
|
||||
|
||||
%r = load i32* %p.0, align 8
|
||||
ret i32 %r
|
||||
; CHECK: @test7
|
||||
; CHECK-NOT: alloca i32
|
||||
; CHECK: %r = select i1 %c, i32 2, i32 0
|
||||
; CHECK: ret i32 %r
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user