Skip to content

Commit c584405

Browse files
authored
Revert "Revert "SILOptimizer: Replace Array.append(contentsOf: with Array.append(elem…""
1 parent 5ae29e3 commit c584405

File tree

9 files changed

+303
-34
lines changed

9 files changed

+303
-34
lines changed

benchmark/single-source/ArrayAppend.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,15 @@ public func run_ArrayAppendRepeatCol(_ N: Int) {
157157
}
158158
}
159159

160-
160+
// Concatenate a single element array
161+
@inline(never)
162+
public func run_ArrayConcat(_ N: Int) {
163+
for _ in 0..<N {
164+
for _ in 0..<10 {
165+
var nums = [Int]()
166+
for _ in 0..<40000 {
167+
nums += [1]
168+
}
169+
}
170+
}
171+
}

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,10 @@ class ASTContext {
429429

430430
/// Retrieve the declaration of Swift.==(Int, Int) -> Bool.
431431
FuncDecl *getEqualIntDecl() const;
432-
432+
433+
/// Retrieve the declaration of Array.append(element:)
434+
FuncDecl *getArrayAppendElementDecl() const;
435+
433436
/// Retrieve the declaration of Swift._unimplementedInitializer.
434437
FuncDecl *getUnimplementedInitializerDecl(LazyResolver *resolver) const;
435438

include/swift/SILOptimizer/Analysis/ArraySemantic.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ enum class ArrayCallKind {
3737
// The following two semantic function kinds return the result @owned
3838
// instead of operating on self passed as parameter.
3939
kArrayInit,
40-
kArrayUninitialized
40+
kArrayUninitialized,
41+
// The following semantic function kinds have a self parameter,
42+
// and are mutating
43+
kAppendContentsOf,
44+
kAppendElement
4145
};
4246

4347
/// Wrapper around array semantic calls.
@@ -131,6 +135,12 @@ class ArraySemanticsCall {
131135
/// Returns true on success, false otherwise.
132136
bool replaceByValue(SILValue V);
133137

138+
/// Replace a call to append(contentsOf: ) with a series of
139+
/// append(element: ) calls.
140+
bool replaceByAppendingValues(SILModule &M, SILFunction *AppendFn,
141+
llvm::SmallVectorImpl<SILValue> &Vals,
142+
ArrayRef<Substitution> Subs);
143+
134144
/// Hoist the call to the insert point.
135145
void hoist(SILInstruction *InsertBefore, DominanceInfo *DT) {
136146
hoistOrCopy(InsertBefore, DT, false);

lib/AST/ASTContext.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ struct ASTContext::Implementation {
160160
/// func ==(Int, Int) -> Bool
161161
FuncDecl *EqualIntDecl = nullptr;
162162

163+
/// func append(Element) -> void
164+
FuncDecl *ArrayAppendElementDecl = nullptr;
165+
163166
/// func _unimplementedInitializer(className: StaticString).
164167
FuncDecl *UnimplementedInitializerDecl = nullptr;
165168

@@ -889,6 +892,55 @@ FuncDecl *ASTContext::getEqualIntDecl() const {
889892
return nullptr;
890893
}
891894

895+
FuncDecl *ASTContext::getArrayAppendElementDecl() const {
896+
if (Impl.ArrayAppendElementDecl)
897+
return Impl.ArrayAppendElementDecl;
898+
899+
auto AppendFunctions = getArrayDecl()->lookupDirect(getIdentifier("append"));
900+
901+
for (auto CandidateFn : AppendFunctions) {
902+
auto FnDecl = dyn_cast<FuncDecl>(CandidateFn);
903+
auto Attrs = FnDecl->getAttrs();
904+
for (auto *A : Attrs.getAttributes<SemanticsAttr, false>()) {
905+
if (A->Value != "array.append_element")
906+
continue;
907+
908+
#ifndef NDEBUG
909+
auto ParamLists = FnDecl->getParameterLists();
910+
assert(ParamLists.size() == 2 && "Should have two parameter lists");
911+
assert(ParamLists[0]->size() == 1 &&
912+
"First parameter list should have one parameter");
913+
auto SelfInOutTy = ParamLists[0]->get(0)->getType()->getAs<InOutType>();
914+
assert(SelfInOutTy && "Self parameter should be an inout Type");
915+
auto SelfGenericStructTy =
916+
SelfInOutTy->getObjectType()->getAs<BoundGenericStructType>();
917+
assert(SelfGenericStructTy &&
918+
"Self parameter should be a BoundGenericStructType Type");
919+
assert(SelfGenericStructTy->getDecl() == getArrayDecl() &&
920+
"Self parameter should be an Array");
921+
922+
assert(ParamLists[1]->size() == 1 &&
923+
"Second parameter list should have one parameter");
924+
auto ElementType = ParamLists[1]
925+
->get(0)
926+
->getType()
927+
->getAs<ArchetypeType>();
928+
assert(ElementType &&
929+
"First parameter replacement should be a Archetype");
930+
assert(ElementType->getName() == getIdentifier("Element") &&
931+
"The Archetype's name should be \"Element\"");
932+
933+
assert(FnDecl->getResultInterfaceType()->isVoid() &&
934+
"The return type should be void");
935+
#endif
936+
Impl.ArrayAppendElementDecl = FnDecl;
937+
return FnDecl;
938+
}
939+
}
940+
941+
return NULL;
942+
}
943+
892944
FuncDecl *
893945
ASTContext::getUnimplementedInitializerDecl(LazyResolver *resolver) const {
894946
if (Impl.UnimplementedInitializerDecl)

lib/SILOptimizer/Analysis/ArraySemantic.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ ArrayCallKind swift::ArraySemanticsCall::getKind() const {
161161
.Case("array.get_element_address",
162162
ArrayCallKind::kGetElementAddress)
163163
.Case("array.mutate_unknown", ArrayCallKind::kMutateUnknown)
164-
.Case("array.withUnsafeMutableBufferPointer", ArrayCallKind::kWithUnsafeMutableBufferPointer)
164+
.Case("array.withUnsafeMutableBufferPointer",
165+
ArrayCallKind::kWithUnsafeMutableBufferPointer)
166+
.Case("array.append_contentsOf", ArrayCallKind::kAppendContentsOf)
167+
.Case("array.append_element", ArrayCallKind::kAppendElement)
165168
.Default(ArrayCallKind::kNone);
166169
if (Tmp != ArrayCallKind::kNone) {
167170
assert(Kind == ArrayCallKind::kNone && "Multiple array semantic "
@@ -682,3 +685,41 @@ bool swift::ArraySemanticsCall::replaceByValue(SILValue V) {
682685
removeCall();
683686
return true;
684687
}
688+
689+
bool swift::ArraySemanticsCall::replaceByAppendingValues(
690+
SILModule &M, SILFunction *AppendFn, SmallVectorImpl<SILValue> &Vals,
691+
ArrayRef<Substitution> Subs) {
692+
assert(getKind() == ArrayCallKind::kAppendContentsOf &&
693+
"Must be an append_contentsOf call");
694+
assert(AppendFn && "Must provide an append SILFunction");
695+
696+
// We only handle loadable types.
697+
if (any_of(Vals, [&M](SILValue V) -> bool {
698+
return !V->getType().isLoadable(M);
699+
}))
700+
return false;
701+
702+
auto ArrRef = SemanticsCall->getArgument(1);
703+
SILBuilderWithScope Builder(SemanticsCall);
704+
auto Loc = SemanticsCall->getLoc();
705+
auto *FnRef = Builder.createFunctionRef(Loc, AppendFn);
706+
auto FnTy = FnRef->getType();
707+
708+
for (auto &V : Vals) {
709+
auto SubTy = V->getType();
710+
auto &ValLowering = Builder.getModule().getTypeLowering(SubTy);
711+
auto CopiedVal = ValLowering.emitCopyValue(Builder, Loc, V);
712+
auto *AllocStackInst = Builder.createAllocStack(Loc, SubTy);
713+
Builder.createStore(Loc, CopiedVal, AllocStackInst,
714+
StoreOwnershipQualifier::Unqualified);
715+
SILValue Args[] = {AllocStackInst, ArrRef};
716+
Builder.createApply(Loc, FnRef, FnTy.substGenericArgs(M, Subs),
717+
FnTy.castTo<SILFunctionType>()->getSILResult(), Subs,
718+
Args, false);
719+
Builder.createDeallocStack(Loc, AllocStackInst);
720+
}
721+
722+
removeCall();
723+
724+
return true;
725+
}

lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@ static bool isNonMutatingArraySemanticCall(SILInstruction *Inst) {
489489
case ArrayCallKind::kWithUnsafeMutableBufferPointer:
490490
case ArrayCallKind::kArrayInit:
491491
case ArrayCallKind::kArrayUninitialized:
492+
case ArrayCallKind::kAppendContentsOf:
493+
case ArrayCallKind::kAppendElement:
492494
return false;
493495
}
494496

@@ -825,6 +827,8 @@ static bool mayChangeArrayValueToNonUniqueState(ArraySemanticsCall &Call) {
825827
case ArrayCallKind::kWithUnsafeMutableBufferPointer:
826828
case ArrayCallKind::kArrayInit:
827829
case ArrayCallKind::kArrayUninitialized:
830+
case ArrayCallKind::kAppendContentsOf:
831+
case ArrayCallKind::kAppendElement:
828832
return true;
829833
}
830834

0 commit comments

Comments
 (0)