1616// ===----------------------------------------------------------------------===//
1717
1818#include " GenKeyPath.h"
19- #include " swift/AST/ExtInfo.h"
2019#include " swift/AST/ASTContext.h"
2120#include " swift/AST/ASTMangler.h"
2221#include " swift/AST/DiagnosticsIRGen.h"
22+ #include " swift/AST/ExtInfo.h"
2323#include " swift/AST/GenericEnvironment.h"
2424#include " swift/AST/IRGenOptions.h"
2525#include " swift/AST/ParameterList.h"
5353#include " llvm/ADT/MapVector.h"
5454#include " llvm/ADT/SmallBitVector.h"
5555#include " llvm/ADT/TinyPtrVector.h"
56+ #include " llvm/Analysis/ValueTracking.h"
5657#include " llvm/IR/Constant.h"
5758#include " llvm/IR/Constants.h"
5859#include " llvm/IR/DIBuilder.h"
@@ -3258,7 +3259,9 @@ void IRGenSILFunction::visitExistentialMetatypeInst(
32583259static void emitApplyArgument (IRGenSILFunction &IGF,
32593260 SILValue arg,
32603261 SILType paramType,
3261- Explosion &out) {
3262+ Explosion &out,
3263+ SILInstruction *apply = nullptr ,
3264+ unsigned idx = 0 ) {
32623265 bool isSubstituted = (arg->getType () != paramType);
32633266
32643267 // For indirect arguments, we just need to pass a pointer.
@@ -3282,7 +3285,24 @@ static void emitApplyArgument(IRGenSILFunction &IGF,
32823285
32833286 // Fast path: avoid an unnecessary temporary explosion.
32843287 if (!isSubstituted) {
3288+ bool canForwardLoadToIndirect = false ;
3289+ auto *load = dyn_cast<LoadInst>(arg);
3290+ [&]() {
3291+ if (apply && load && apply->getParent () == load->getParent ()) {
3292+ for (auto it = std::next (load->getIterator ()), e = apply->getIterator ();
3293+ it != e; ++it) {
3294+ if (isa<LoadInst>(&(*it))) {
3295+ continue ;
3296+ }
3297+ return ;
3298+ }
3299+ canForwardLoadToIndirect = true ;
3300+ }
3301+ }();
32853302 IGF.getLoweredExplosion (arg, out);
3303+ if (canForwardLoadToIndirect) {
3304+ IGF.setForwardableArgument (idx);
3305+ }
32863306 return ;
32873307 }
32883308
@@ -3710,6 +3730,8 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) {
37103730 // Lower the SIL arguments to IR arguments.
37113731
37123732 // Turn the formal SIL parameters into IR-gen things.
3733+ clearForwardableArguments ();
3734+
37133735 for (auto index : indices (args)) {
37143736 if (origConv.hasIndirectSILErrorResults () &&
37153737 index == origConv.getNumIndirectSILResults ()) {
@@ -3718,7 +3740,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) {
37183740 continue ;
37193741 }
37203742 emitApplyArgument (*this , args[index], emission->getParameterType (index),
3721- llArgs);
3743+ llArgs, site. getInstruction (), index );
37223744 }
37233745
37243746 auto &calleeFP = emission->getCallee ().getFunctionPointer ();
@@ -3744,6 +3766,9 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) {
37443766 Explosion result;
37453767 emission->emitToExplosion (result, false );
37463768
3769+ // We might have set forwardable arguments. Clear it for the next round.
3770+ clearForwardableArguments ();
3771+
37473772 // For a simple apply, just bind the apply result to the result of the call.
37483773 if (auto apply = dyn_cast<ApplyInst>(i)) {
37493774 setLoweredExplosion (apply, result);
@@ -5336,12 +5361,72 @@ void IRGenSILFunction::visitLoadInst(swift::LoadInst *i) {
53365361 setLoweredExplosion (i, lowered);
53375362}
53385363
5364+ static Address canForwardIndirectResultAlloca (const TypeInfo &TI,
5365+ StoreInst *store,
5366+ Explosion &argSrc,
5367+ llvm::Instruction * &insertPt) {
5368+ // Check that the store stores the result of and apply instruction immediately
5369+ // preceeding the store.
5370+ auto *apply = dyn_cast<ApplyInst>(store->getSrc ());
5371+ auto *allocStack = dyn_cast<AllocStackInst>(store->getDest ());
5372+ if (!apply || !allocStack || apply->getParent () != store->getParent () ||
5373+ std::next (apply->getIterator ()) != store->getIterator ())
5374+ return Address ();
5375+
5376+ auto explosionSize = TI.getSchema ().size ();
5377+ if (argSrc.size () < 1 || explosionSize < 4 )
5378+ return Address ();
5379+
5380+ auto *load = dyn_cast<llvm::LoadInst>(*argSrc.begin ());
5381+ if (!load)
5382+ return Address ();
5383+ auto *gep = dyn_cast<llvm::GetElementPtrInst>(load->getPointerOperand ());
5384+ if (!gep)
5385+ return Address ();
5386+
5387+ auto *alloca = dyn_cast<llvm::AllocaInst>(getUnderlyingObject (gep));
5388+ if (!alloca)
5389+ return Address ();
5390+
5391+ // Check all the other loads.
5392+ for (size_t i = 1 , e = explosionSize; i != e; ++i) {
5393+ auto *load = dyn_cast<llvm::LoadInst>(*(argSrc.begin () + i));
5394+ if (!load)
5395+ return Address ();
5396+ auto *alloca2 = dyn_cast<llvm::AllocaInst>(
5397+ getUnderlyingObject (load->getPointerOperand ()));
5398+ if (!alloca2 || alloca2 != alloca)
5399+ return Address ();
5400+ }
5401+
5402+ // Set insertPt to the first load such that we are within the lifetime of the
5403+ // alloca marked by the lifetime intrinsic.
5404+ insertPt = load;
5405+
5406+ return TI.getAddressForPointer (alloca);
5407+ }
5408+
53395409void IRGenSILFunction::visitStoreInst (swift::StoreInst *i) {
53405410 Explosion source = getLoweredExplosion (i->getSrc ());
53415411 Address dest = getLoweredAddress (i->getDest ());
53425412 SILType objType = i->getSrc ()->getType ().getObjectType ();
5343-
53445413 const auto &typeInfo = cast<LoadableTypeInfo>(getTypeInfo (objType));
5414+
5415+
5416+ llvm::Instruction *insertPt = nullptr ;
5417+ auto forwardAddr = canForwardIndirectResultAlloca (typeInfo, i, source,
5418+ insertPt);
5419+ if (forwardAddr.isValid ()) {
5420+ const auto &addrTI = getTypeInfo (i->getDest ()->getType ());
5421+ // Set the insert point to the first load instruction. We need to be with
5422+ // the lifetime of the alloca.
5423+ IRBuilder::SavedInsertionPointRAII insertRAII (this ->Builder , insertPt);
5424+ addrTI.initializeWithTake (*this , dest, forwardAddr, i->getDest ()->getType (),
5425+ false );
5426+ (void )source.claimAll ();
5427+ return ;
5428+ }
5429+
53455430 switch (i->getOwnershipQualifier ()) {
53465431 case StoreOwnershipQualifier::Unqualified:
53475432 case StoreOwnershipQualifier::Init:
0 commit comments