mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 23:20:40 +03:00
Eliminate comparisons between GC allocations and constants. This removes some
`assert(this !is null)`s when member functions get inlined. Also tweak pass order a bit.
This commit is contained in:
parent
465f15eda0
commit
5ecdf1a70a
2 changed files with 56 additions and 29 deletions
|
@ -154,26 +154,24 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||||
// opApply's, etc. where the actual function being called
|
// opApply's, etc. where the actual function being called
|
||||||
// wasn't known during the first inliner pass.
|
// wasn't known during the first inliner pass.
|
||||||
addPass(pm, createFunctionInliningPass());
|
addPass(pm, createFunctionInliningPass());
|
||||||
|
|
||||||
// Run clean-up again.
|
|
||||||
addPass(pm, createScalarReplAggregatesPass());
|
|
||||||
addPass(pm, createInstructionCombiningPass());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optimizeLevel >= 2 && !disableLangSpecificPasses) {
|
if (optimizeLevel >= 2) {
|
||||||
if (!disableSimplifyRuntimeCalls)
|
if (!disableLangSpecificPasses) {
|
||||||
addPass(pm, createSimplifyDRuntimeCalls());
|
if (!disableSimplifyRuntimeCalls)
|
||||||
|
addPass(pm, createSimplifyDRuntimeCalls());
|
||||||
|
|
||||||
#ifdef USE_METADATA
|
#ifdef USE_METADATA
|
||||||
if (!disableGCToStack) {
|
if (!disableGCToStack)
|
||||||
addPass(pm, createGarbageCollect2Stack());
|
addPass(pm, createGarbageCollect2Stack());
|
||||||
// Run some clean-up
|
|
||||||
addPass(pm, createInstructionCombiningPass());
|
|
||||||
addPass(pm, createScalarReplAggregatesPass());
|
|
||||||
addPass(pm, createCFGSimplificationPass());
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
// Run some clean-up passes
|
||||||
|
addPass(pm, createInstructionCombiningPass());
|
||||||
|
addPass(pm, createScalarReplAggregatesPass());
|
||||||
|
addPass(pm, createCFGSimplificationPass());
|
||||||
|
addPass(pm, createInstructionCombiningPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// -O3
|
// -O3
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace {
|
||||||
class VISIBILITY_HIDDEN LibCallOptimization {
|
class VISIBILITY_HIDDEN LibCallOptimization {
|
||||||
protected:
|
protected:
|
||||||
Function *Caller;
|
Function *Caller;
|
||||||
|
bool* Changed;
|
||||||
const TargetData *TD;
|
const TargetData *TD;
|
||||||
AliasAnalysis *AA;
|
AliasAnalysis *AA;
|
||||||
|
|
||||||
|
@ -64,9 +65,10 @@ namespace {
|
||||||
/// delete CI.
|
/// delete CI.
|
||||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0;
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0;
|
||||||
|
|
||||||
Value *OptimizeCall(CallInst *CI, const TargetData &TD,
|
Value *OptimizeCall(CallInst *CI, bool& Changed, const TargetData &TD,
|
||||||
AliasAnalysis& AA, IRBuilder<> &B) {
|
AliasAnalysis& AA, IRBuilder<> &B) {
|
||||||
Caller = CI->getParent()->getParent();
|
Caller = CI->getParent()->getParent();
|
||||||
|
this->Changed = &Changed;
|
||||||
this->TD = &TD;
|
this->TD = &TD;
|
||||||
this->AA = &AA;
|
this->AA = &AA;
|
||||||
return CallOptimizer(CI->getCalledFunction(), CI, B);
|
return CallOptimizer(CI->getCalledFunction(), CI, B);
|
||||||
|
@ -181,9 +183,36 @@ struct VISIBILITY_HIDDEN ArrayCastLenOpt : public LibCallOptimization {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// DeleteUnusedOpt - remove libcall if the return value is unused.
|
/// AllocationOpt - Common optimizations for various GC allocations.
|
||||||
struct VISIBILITY_HIDDEN DeleteUnusedOpt : public LibCallOptimization {
|
struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization {
|
||||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||||
|
// Allocations are never equal to constants, so remove any equality
|
||||||
|
// comparisons to constants. (Most importantly comparisons to null at
|
||||||
|
// the start of inlined member functions)
|
||||||
|
for (CallInst::use_iterator I = CI->use_begin(), E = CI->use_end() ; I != E;) {
|
||||||
|
Instruction* User = cast<Instruction>(*I++);
|
||||||
|
|
||||||
|
if (ICmpInst* Cmp = dyn_cast<ICmpInst>(User)) {
|
||||||
|
if (!Cmp->isEquality())
|
||||||
|
continue;
|
||||||
|
Constant* C = 0;
|
||||||
|
if ((C = dyn_cast<Constant>(Cmp->getOperand(0)))
|
||||||
|
|| (C = dyn_cast<Constant>(Cmp->getOperand(1)))) {
|
||||||
|
Value* Result = ConstantInt::get(Type::Int1Ty, !Cmp->isTrueWhenEqual());
|
||||||
|
Cmp->replaceAllUsesWith(Result);
|
||||||
|
// Don't delete the comparison because there may be an
|
||||||
|
// iterator to it. Instead, set the operands to constants
|
||||||
|
// and let dead code elimination clean it up later.
|
||||||
|
// (It doesn't matter that this changes the value of the
|
||||||
|
// icmp because it's not used anymore anyway)
|
||||||
|
Cmp->setOperand(0, C);
|
||||||
|
Cmp->setOperand(1, C);
|
||||||
|
*Changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's not used (anymore), pre-emptively GC it.
|
||||||
if (CI->use_empty())
|
if (CI->use_empty())
|
||||||
return CI;
|
return CI;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -245,7 +274,7 @@ namespace {
|
||||||
ArraySliceCopyOpt ArraySliceCopy;
|
ArraySliceCopyOpt ArraySliceCopy;
|
||||||
|
|
||||||
// GC allocations
|
// GC allocations
|
||||||
DeleteUnusedOpt DeleteUnused;
|
AllocationOpt Allocation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Pass identification
|
static char ID; // Pass identification
|
||||||
|
@ -290,14 +319,14 @@ void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||||
* (We can't mark allocating calls as readonly/readnone because they don't
|
* (We can't mark allocating calls as readonly/readnone because they don't
|
||||||
* return the same pointer every time when called with the same arguments)
|
* return the same pointer every time when called with the same arguments)
|
||||||
*/
|
*/
|
||||||
Optimizations["_d_allocmemoryT"] = &DeleteUnused;
|
Optimizations["_d_allocmemoryT"] = &Allocation;
|
||||||
Optimizations["_d_newarrayT"] = &DeleteUnused;
|
Optimizations["_d_newarrayT"] = &Allocation;
|
||||||
Optimizations["_d_newarrayiT"] = &DeleteUnused;
|
Optimizations["_d_newarrayiT"] = &Allocation;
|
||||||
Optimizations["_d_newarrayvT"] = &DeleteUnused;
|
Optimizations["_d_newarrayvT"] = &Allocation;
|
||||||
Optimizations["_d_newarraymT"] = &DeleteUnused;
|
Optimizations["_d_newarraymT"] = &Allocation;
|
||||||
Optimizations["_d_newarraymiT"] = &DeleteUnused;
|
Optimizations["_d_newarraymiT"] = &Allocation;
|
||||||
Optimizations["_d_newarraymvT"] = &DeleteUnused;
|
Optimizations["_d_newarraymvT"] = &Allocation;
|
||||||
Optimizations["_d_allocclass"] = &DeleteUnused;
|
Optimizations["_d_allocclass"] = &Allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,7 +382,7 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnal
|
||||||
Builder.SetInsertPoint(BB, I);
|
Builder.SetInsertPoint(BB, I);
|
||||||
|
|
||||||
// Try to optimize this call.
|
// Try to optimize this call.
|
||||||
Value *Result = OMI->second->OptimizeCall(CI, TD, AA, Builder);
|
Value *Result = OMI->second->OptimizeCall(CI, Changed, TD, AA, Builder);
|
||||||
if (Result == 0) continue;
|
if (Result == 0) continue;
|
||||||
|
|
||||||
DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI;
|
DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue