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
SILOptimizer: Replace Array.append(contentsOf: with Array.append(elem… #5978
Conversation
@swift-ci Please smoke test |
llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &Replacements) | ||
: Alloc(AI), ReplacementMap(Replacements) {} | ||
llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &GetElementReplacements, | ||
llvm::SmallVectorImpl<std::pair<ApplyInst *, llvm::SmallVector<SILValue, 4> > > &AppendContentsOfReplacements) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to make
llvm::SmallVectorImpl<std::pair<ApplyInst *, llvm::SmallVector<SILValue, 4> > >
instead be
llvm::SmallVectorImpl<std::pair<ApplyInst *, llvm::SmallVectorImpl<SILValue> > >
but it fails to compile because it can't find a conversion from std::pair<ApplyInst *, llvm::SmallVector<SILValue, 4> >
to std::pair<ApplyInst *, llvm::SmallVectorImpl<SILValue> >
. I don't know C++ well enough to understand what's wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ben-ng You may want to introduce typedefs
for these very long types to make the code more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The llvm prefix is not required either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might also want to create a helper class to store state for this specific transformation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the typedefs
, and removed redundant llvm
prefixes. I'm not sure what you mean about the helper class, but the refactored code is much cleaner, so maybe it's not necessary anymore.
@@ -131,6 +134,10 @@ class ArraySemanticsCall { | |||
/// Returns true on success, false otherwise. | |||
bool replaceByValue(SILValue V); | |||
|
|||
/// Replace a call to append(contentsOf: ) with a series of | |||
/// append(element: ) calls. | |||
bool replaceByAppendingValues(SILModule &M, SILFunction* appendFn, llvm::SmallVectorImpl<SILValue> &Vs, ArrayRef<ProtocolConformanceRef> &conformances); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method signature seemed really silly to me when I wrote it, and still does. The replacement isn't as straightforward as the one that replaceByValue(SILValue V)
does. Maybe it doesn't even make sense to have this be a method on ArraySemantic
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stylistic nitpicks: lines should be <= 80 columns, and put the * and & before the type and not after the name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapped the lines at 80 characters. Not sure what you mean by the * and &, but I did move the * so it's against the name rather than the type.
AppendContentsOf.replaceByAppendingValues(M, appendFn, Repl.second, conformances); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably a good idea to move the whole if-block into a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Word, done.
|
||
// We only handle loadable types. | ||
for(auto& V : Vs) { | ||
if (!V->getType().isLoadable(SemanticsCall->getModule())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SemanticsCall->getModule() and SemanticsCall->getLoc() should be stored in locals for readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I thought that getLoc
would return a different value after each insertion. I guess that's not the case.
auto copiedVal = ValLowering.emitCopyValue(Builder, SemanticsCall->getLoc(), V); | ||
auto allocStackInst = Builder.createAllocStack(SemanticsCall->getLoc(), subTy); | ||
Builder.createStore(SemanticsCall->getLoc(), copiedVal, allocStackInst, StoreOwnershipQualifier::Unqualified); | ||
ArrayRef<Substitution> subs{Substitution(subTy.getSwiftType(), conformances)}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use SemanticsCall->getSubstitutions() instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I tried that, the return value was an empty ArrayRef
. I figured that at this point, the original function has already been specialized, so the substitutions would be empty.
@@ -682,3 +684,36 @@ bool swift::ArraySemanticsCall::replaceByValue(SILValue V) { | |||
removeCall(); | |||
return true; | |||
} | |||
|
|||
bool swift::ArraySemanticsCall::replaceByAppendingValues(SILModule &M, SILFunction* appendFn, llvm::SmallVectorImpl<SILValue> &Vs, ArrayRef<ProtocolConformanceRef> &conformances) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be you should form the array of substitutions in the caller of this function and pass it as an argument, i.e. as ArrayRef<Substitution>
. It would make the signature simpler and would make the code cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
FuncDecl *appendFnDecl; | ||
|
||
for (auto candidateFn : appendFunctions) { | ||
auto *fnDecl = dyn_cast_or_null<FuncDecl>(candidateFn); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use dyn_cast here, candidateFn won't be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
auto genericEnv = appendFnDecl->getGenericEnvironment(); | ||
auto forwardingSubs = genericEnv->getForwardingSubstitutions(M.getSwiftModule(), genericSig); | ||
assert(forwardingSubs.size() == 1 && "Must have exactly one forwarding substitution"); | ||
auto conformances = forwardingSubs[0].getConformances(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just remove this I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't the conformances empty anyway? append's generic parameter has no requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, empty. Removed.
} | ||
} | ||
|
||
return appendFnDecl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an idea: You could also add a new semantics attribute, e.g. @_semantics("array.append_element")
to mark this function in a special way and then check here that the function you found has this @_semantics
. I'm not sure if it really needed though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. This way of finding the append function very fragile.
Let's just add another semantics function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I was thinking about doing that, but couldn't figure out how to do that with a FuncDecl
at the time. I finally figured it out, though. Done.
// CHECK: [[AEFUN:%.*]] = function_ref @_TFSa6appendfxT_ | ||
// CHECK: apply [[AEFUN]] | ||
// CHECK: return | ||
sil @append_contentsOf : $@convention(thin) () -> () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '// users' comments are not part the SIL source -- they comments that came from your -emit-sil dump. You can remove them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
}); | ||
// Perform the actual replacement of the append_contentsOf call by its value. | ||
if (!AppendContentsOfReplacements.empty()) { | ||
auto *appendFnDecl = lookupAppendFnDecl(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other variables seem to begin with upper-case. It would be nice to follow the coding style used in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I think I fixed them all.
This looks cool! Let's sort out the right way to get the Substitutions, and then it looks good to me on my side. |
@@ -249,6 +278,39 @@ bool ArrayAllocation::collectForwardableValues() { | |||
namespace { | |||
|
|||
class ArrayElementPropagation : public SILFunctionTransform { | |||
|
|||
FuncDecl* lookupAppendFnDecl() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this belongs in ASTContext.cpp
along with the rest of the stdlib lookup stuff. We can also cache it there too to make repeated calls easier and knock out a parameter in the functions below that use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beside my comments, LGTM!
@@ -537,6 +538,7 @@ bool swift::ArraySemanticsCall::doesNotChangeArray() const { | |||
case ArrayCallKind::kGetCount: | |||
case ArrayCallKind::kGetCapacity: | |||
case ArrayCallKind::kGetElement: | |||
case ArrayCallKind::kAppendContentsOf: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not correct to say that kAppendContentsOf does not change the array. What you care about is the newElements argument, which is not changed (and not the self-array).
I would remove this here and make a special case where doesNotChangeArray is called (see below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, when I did this I wrongly assumed that the "array" being referred to in the method name was not the self parameter, but the input parameter.
@@ -207,8 +232,12 @@ bool ArrayAllocation::recursivelyCollectUses(ValueBase *Def) { | |||
// Check array semantic calls. | |||
ArraySemanticsCall ArrayOp(User); | |||
if (ArrayOp && ArrayOp.doesNotChangeArray()) { | |||
if (ArrayOp.getKind() == ArrayCallKind::kAppendContentsOf) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kAppendContentsOf does change the self-array. But you care about it's source-argument (and not about the self argument).
You can do something like
if (ArrayOp) {
if (ArrayOp.getKind() == ArrayCallKind::kAppendContentsOf) {
// ArrayOp is the "newElements" operand
...
continue;
} else if (ArrayOp.getKind() == ArrayCallKind::kGetElement) {
...
continue;
} else if (ArrayOp.doesNotChangeArray()) {
continue;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, done.
} | ||
} | ||
|
||
return appendFnDecl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. This way of finding the append function very fragile.
Let's just add another semantics function.
llvm::DenseMap<uint64_t, SILValue> ElementValueMap; | ||
llvm::SmallVector<SILValue, 4> ElementValueVector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a class member?
Can't you just create this vector before you use it in ArrayAllocation::findReplacements()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, done.
// easier to replace | ||
auto elementCount = ElementValueMap.size(); | ||
for (size_t i = 0; i < elementCount; ++i) { | ||
assert(ElementValueMap.count(i) && "Elements should be contiguous"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should rather bail than assert if there is no defined value for a certain index.
I'm not sure if the compiler currently will create such a SIL where only parts of the elements are initialized by stores, it would definitely be valid SIL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I was also wondering if this situation would ever arise naturally, and decided to be defensive about it.
|
||
auto mangled = SILDeclRef(appendFnDecl, SILDeclRef::Kind::Func).mangle(); | ||
auto *appendFn = M.hasFunction(mangled, SILLinkage::PublicExternal); | ||
assert(appendFn && "Array.append(Element) function must exist"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better not to rely on the existence of the append function. It's better to bail instead of assert here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
#include "swift/SIL/SILBasicBlock.h" | ||
#include "swift/SIL/SILInstruction.h" | ||
#include "swift/SIL/SILFunction.h" | ||
#include "swift/SIL/DebugUtils.h" | ||
#include "swift/SILOptimizer/Analysis/ArraySemantic.h" | ||
#include "swift/SILOptimizer/PassManager/Passes.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should update the general comment for this optimization (some lines below) and describe the new feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
AppendContentsOfReplacementMap.push_back( | ||
std::make_pair(call, ElementValueVector)); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add some upper bound on the number of elements, so that we don't explode code size if a very large array is appended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Through experimentation, the upper bound is 6.
260c6cc
to
0f1990c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments
@@ -449,6 +449,7 @@ class ASTContext { | |||
/// Swift module. | |||
void lookupInSwiftModule(StringRef name, | |||
SmallVectorImpl<ValueDecl *> &results) const; | |||
FuncDecl* lookupArrayAppendElementDecl() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swap the space and the *
@@ -498,6 +498,22 @@ void ASTContext::lookupInSwiftModule( | |||
M->lookupValue({ }, identifier, NLKind::UnqualifiedLookup, results); | |||
} | |||
|
|||
FuncDecl* ASTContext::lookupArrayAppendElementDecl() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swap the space and the *
auto fnDecl = dyn_cast<FuncDecl>(CandidateFn); | ||
auto Attrs = fnDecl->getAttrs(); | ||
for (auto *A : Attrs.getAttributes<SemanticsAttr, false>()) { | ||
if (cast<SemanticsAttr>(A)->Value == "array.append_element") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the cast necessary?
assert(AppendFn && "Must provide an append SILFunction"); | ||
|
||
// We only handle loadable types. | ||
for(auto& V : Vs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swap the space and the &
SmallVectorImpl<ValueReplacementPair> &GetElementReplacements, | ||
SmallVectorImpl<ValueReplacementsPair> &AppendContentsOfReplacements) | ||
: Alloc(AI), | ||
GetElementReplacementMap(GetElementReplacements), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent this line and the next line by 2 spaces to line up the initializer list
assert(AppendContentsOf && "Must be AppendContentsOf call"); | ||
assert(Repl.second.size() && "Must have at least one replacement"); | ||
auto Ty = Repl.second[0]->getType().getSwiftType(); | ||
ArrayRef<Substitution> Subs{Substitution(Ty, {})}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still a bit nervous about using a lowered type here. Can you check what happens if you perform your optimization with a substitution where T maps to a function type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it blew up:
SIL verification failed: operand of 'apply' doesn't match function input type
$*Array<(Int) -> Int>
$*Array<@callee_owned (@in Int) -> @out Int>
Verifying instruction:
%11 = global_addr @_Tv4elsa4listGSaFSiSi_ : $*Array<(Int) -> Int>, loc "./elsa.swift":1:5, scope 0 // users: %56, %15
// function_ref Array.append(A) -> ()
%52 = function_ref @_TFSa6appendfxT_ : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> (), scope 0 // user: %56
%54 = alloc_stack $@callee_owned (@in Int) -> @out Int, scope 0 // users: %57, %56, %55
-> %56 = apply %52<@callee_owned (@in Int) -> @out Int>(%54, %11) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> (), scope 0
How do I get the unlowered type from a SILValue? I couldn't figure it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't. You should be able to get the formal type from the Array
's type argument, can't you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jckarter thanks for the tip, I think I figured it out. The problematic code now compiles just fine.
0f1990c
to
48bdf6c
Compare
void replaceAppendCalls(SmallVector<ValueReplacementsPair, 4> Repls) { | ||
auto &Fn = *getFunction(); | ||
auto &M = Fn.getModule(); | ||
auto &C = M.getASTContext(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually call ASTContext objects Ctx
.
ff45d9c
to
a230183
Compare
if (Repls.empty()) | ||
return; | ||
|
||
llvm::dbgs() << "Array append contentsOf calls replaced in " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this debug output into DEBUG
, i.e. DEBUG(your_code);
, otherwise it will be printed unconditionally on every compilation.
auto ElementCount = ElementValueMap.size(); | ||
llvm::SmallVector<SILValue, 4> ElementValueVector; | ||
|
||
if (ElementCount > 6) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest not hard-coding this limit here. Define a const
with a descriptive name and comment somewhere at the beginning of the file and then use it here. It will make it easier to adjust it if needed or even make it configurable.
auto Attrs = FnDecl->getAttrs(); | ||
for (auto *A : Attrs.getAttributes<SemanticsAttr, false>()) { | ||
if (A->Value == "array.append_element") { | ||
return FnDecl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it could be a good idea to add a bunch of asserts here to be on the safe side. E.g. you may want to check if this function has the expected number of arguments, the expected types of arguments and the expected return type.
a230183
to
6247ad6
Compare
Thanks @swiftix, changes made. I also cached the result of the lookup function in |
@@ -168,6 +168,7 @@ typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> | |||
class ASTContext { | |||
ASTContext(const ASTContext&) = delete; | |||
void operator=(const ASTContext&) = delete; | |||
FuncDecl *ArrayAppendElementDecl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the approach used e.g. by ASTContext::getEqualIntDecl
to lookup a function and cache it. Also use a similar naming scheme, i.e. getArrayAppendElementDecl
.
@swift-ci Please smoke test |
1 similar comment
@swift-ci Please smoke test |
It looks like generated SIL for array operations is different on Linux. This is probably due to the lack of bridging on Linux. Can you try to formulate the test-case in a platform independent way? If it is not possible, you could try to write two different tests and specify that one of them should run on platforms with objc-interop and the other on platforms without objc-interop? |
Are we making different inlining judgments on Linux that cause the |
@jckarter I don't think so |
Hi – sorry to come in so late on this but you probably want to be aware of this PR, since it is affecting |
@ben-ng Looking real quick. Also, isn't git-clang-format great? I love not having to think about formatting (even though it isn't perfect). I am hoping that at some point they make a git-clang-tidy so then we can eliminate even more of these issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking much better! Thank you so much for using git-clang-format. I think 1 more round will do this.
@@ -53,23 +67,32 @@ class ArrayAllocation { | |||
|
|||
// The calls to Array get_element that use this array allocation. | |||
llvm::SmallSetVector<ApplyInst *, 16> GetElementCalls; | |||
SmallVector<ApplyInst *, 4> AppendContentsOfCalls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please be consistent about using llvm:: prefix. In general in the optimizer we use it for SmallVector and SmallVectorImpl (in fact you even did that below).
I would look at what the file is doing and match that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, could you add a doxygen comment (i.e. 3 slashes) here?
// Array append_contentsOf calls and their matching array values for later | ||
// replacement. | ||
SmallVectorImpl<ValueReplacementsPair> &AppendContentsOfReplacementMap; | ||
ArrayRef<Substitution> Substitutions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doxygen comment?
llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &Replacements) { | ||
return ArrayAllocation(Inst, Replacements).findValueReplacements(); | ||
SmallVectorImpl<ValueReplacementPair> &GetElementReplacements, | ||
SmallVectorImpl<ValueReplacementsPair> &AppendContentsOfReplacements) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please be consistent about llvm::.
if (Uninitialized && | ||
(ArrayValue = Uninitialized.getArrayValue()) && | ||
(ElementBuffer = Uninitialized.getArrayElementStoragePointer())) | ||
if (Uninitialized && (ArrayValue = Uninitialized.getArrayValue()) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you invert this if statement? It is always better to make early exits the really simple case (in this case the return false).
This makes
myArray += [42]
equivalent tomyArray.append(42)
, which results in a 6x speedup.It does this by modifying the ArrayElementValuePropagation pass, replacing calls to
Array.append(contentsOf:
with calls toArray.append(element:
.@slavapestov I figured that it'd be easier to discuss the problems in this diff on Github than on the mailing list.