Skip to content

SILOptimizer: A new "TempLValueOpt" optimization for copy_addr #32428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,12 @@ class SILInstruction
/// The instruction may read memory.
MayRead,
/// The instruction may write to memory.
/// This includes destroying or taking from memory (e.g. destroy_addr,
/// copy_addr [take], load [take]).
/// Although, physically, destroying or taking does not modify the memory,
/// it is important to model it is a write. Optimizations must not assume
/// that the value stored in memory is still available for loading after
/// the memory is destroyed or taken.
MayWrite,
/// The instruction may read or write memory.
MayReadWrite,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ PASS(PerformanceSILLinker, "performance-linker",
"Deserialize all referenced SIL functions")
PASS(RawSILInstLowering, "raw-sil-inst-lowering",
"Lower all raw SIL instructions to canonical equivalents.")
PASS(TempLValueOpt, "temp-lvalue-opt",
"Remove short-lived immutable temporary l-values")
PASS(TempRValueOpt, "temp-rvalue-opt",
"Remove short-lived immutable temporary copies")
PASS(SideEffectsDumper, "side-effects-dump",
Expand Down
18 changes: 15 additions & 3 deletions lib/SILOptimizer/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,15 @@ AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2,
return Result;
}

/// Get the underlying object, looking through init_enum_data_addr and
/// init_existential_addr.
static SILValue stripInitEnumAndExistentialAddr(SILValue v) {
while (isa<InitEnumDataAddrInst>(v) || isa<InitExistentialAddrInst>(v)) {
v = getUnderlyingObject(cast<SingleValueInstruction>(v)->getOperand(0));
}
return v;
}

/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
/// to disambiguate the two values.
AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
Expand Down Expand Up @@ -614,9 +623,12 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
LLVM_DEBUG(llvm::dbgs() << " Underlying V1:" << *O1);
LLVM_DEBUG(llvm::dbgs() << " Underlying V2:" << *O2);

// If O1 and O2 do not equal, see if we can prove that they cannot be the
// same object. If we can, return No Alias.
if (O1 != O2 && aliasUnequalObjects(O1, O2))
// If the underlying objects are not equal, see if we can prove that they
// cannot be the same object. If we can, return No Alias.
// For this we even look through init_enum_data_addr and init_existential_addr.
SILValue StrippedO1 = stripInitEnumAndExistentialAddr(O1);
SILValue StrippedO2 = stripInitEnumAndExistentialAddr(O2);
if (StrippedO1 != StrippedO2 && aliasUnequalObjects(StrippedO1, StrippedO2))
return AliasResult::NoAlias;

// Ok, either O1, O2 are the same or we could not prove anything based off of
Expand Down
33 changes: 33 additions & 0 deletions lib/SILOptimizer/Analysis/MemoryBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class MemoryBehaviorVisitor

MemBehavior visitLoadInst(LoadInst *LI);
MemBehavior visitStoreInst(StoreInst *SI);
MemBehavior visitCopyAddrInst(CopyAddrInst *CAI);
MemBehavior visitApplyInst(ApplyInst *AI);
MemBehavior visitTryApplyInst(TryApplyInst *AI);
MemBehavior visitBuiltinInst(BuiltinInst *BI);
Expand Down Expand Up @@ -245,6 +246,10 @@ MemBehavior MemoryBehaviorVisitor::visitLoadInst(LoadInst *LI) {
if (!mayAlias(LI->getOperand()))
return MemBehavior::None;

// A take is modelled as a write. See MemoryBehavior::MayWrite.
if (LI->getOwnershipQualifier() == LoadOwnershipQualifier::Take)
return MemBehavior::MayReadWrite;

LLVM_DEBUG(llvm::dbgs() << " Could not prove that load inst does not alias "
"pointer. Returning may read.\n");
return MemBehavior::MayRead;
Expand All @@ -268,6 +273,34 @@ MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) {
return MemBehavior::MayWrite;
}

MemBehavior MemoryBehaviorVisitor::visitCopyAddrInst(CopyAddrInst *CAI) {
// If it's an assign to the destination, a destructor might be called on the
// old value. This can have any side effects.
// We could also check if it's a trivial type (which cannot have any side
// effect on destruction), but such copy_addr instructions are optimized to
// load/stores anyway, so it's probably not worth it.
if (!CAI->isInitializationOfDest())
return MemBehavior::MayHaveSideEffects;

bool mayWrite = mayAlias(CAI->getDest());
bool mayRead = mayAlias(CAI->getSrc());

if (mayRead) {
if (mayWrite)
return MemBehavior::MayReadWrite;

// A take is modelled as a write. See MemoryBehavior::MayWrite.
if (CAI->isTakeOfSrc())
return MemBehavior::MayReadWrite;

return MemBehavior::MayRead;
}
if (mayWrite)
return MemBehavior::MayWrite;

return MemBehavior::None;
}

MemBehavior MemoryBehaviorVisitor::visitBuiltinInst(BuiltinInst *BI) {
// If our callee is not a builtin, be conservative and return may have side
// effects.
Expand Down
3 changes: 3 additions & 0 deletions lib/SILOptimizer/PassManager/PassPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ void addFunctionPasses(SILPassPipelinePlan &P,
// splits up copy_addr.
P.addCopyForwarding();

// Optimize copies from a temporary (an "l-value") to a destination.
P.addTempLValueOpt();

// Split up opaque operations (copy_addr, retain_value, etc.).
P.addLowerAggregateInstrs();

Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ target_sources(swiftSILOptimizer PRIVATE
Sink.cpp
SpeculativeDevirtualizer.cpp
StackPromotion.cpp
TempLValueOpt.cpp
TempRValueElimination.cpp
UnsafeGuaranteedPeephole.cpp)
Loading