Skip to content
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

Merged
merged 1 commit into from Dec 5, 2016

Conversation

ben-ng
Copy link
Contributor

@ben-ng ben-ng commented Nov 30, 2016

This makes myArray += [42] equivalent to myArray.append(42), which results in a 6x speedup.

It does this by modifying the ArrayElementValuePropagation pass, replacing calls to Array.append(contentsOf: with calls to Array.append(element:.

@slavapestov I figured that it'd be easier to discuss the problems in this diff on Github than on the mailing list.

@ben-ng
Copy link
Contributor Author

ben-ng commented Nov 30, 2016

@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)
Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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);
Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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);
}
}

Copy link
Contributor

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.

Copy link
Contributor Author

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()))
Copy link
Member

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.

Copy link
Contributor Author

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)};
Copy link
Member

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?

Copy link
Contributor Author

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) {
Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
Contributor Author

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();
Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor Author

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) () -> () {
Copy link
Member

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.

Copy link
Contributor Author

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();
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@slavapestov
Copy link
Member

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() {
Copy link
Member

@CodaFi CodaFi Nov 30, 2016

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, done.

Copy link
Member

@eeckstein eeckstein left a 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:
Copy link
Member

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).

Copy link
Contributor Author

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)
Copy link
Member

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;
  }
}

Copy link
Contributor Author

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;
Copy link
Member

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;
Copy link
Member

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()?

Copy link
Contributor Author

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");
Copy link
Member

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.

Copy link
Contributor Author

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");
Copy link
Member

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.

Copy link
Contributor Author

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"
Copy link
Member

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.

Copy link
Contributor Author

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));
}

Copy link
Member

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.

Copy link
Contributor Author

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.

@ben-ng ben-ng force-pushed the redundant-array-init-removal branch 3 times, most recently from 260c6cc to 0f1990c Compare December 1, 2016 01:54
Copy link
Member

@slavapestov slavapestov left a 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;
Copy link
Member

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 {
Copy link
Member

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") {
Copy link
Member

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) {
Copy link
Member

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),
Copy link
Member

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, {})};
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

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.

@ben-ng ben-ng force-pushed the redundant-array-init-removal branch from 0f1990c to 48bdf6c Compare December 1, 2016 02:25
void replaceAppendCalls(SmallVector<ValueReplacementsPair, 4> Repls) {
auto &Fn = *getFunction();
auto &M = Fn.getModule();
auto &C = M.getASTContext();
Copy link
Contributor

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.

@ben-ng ben-ng force-pushed the redundant-array-init-removal branch 2 times, most recently from ff45d9c to a230183 Compare December 1, 2016 15:35
if (Repls.empty())
return;

llvm::dbgs() << "Array append contentsOf calls replaced in "
Copy link
Contributor

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) {
Copy link
Contributor

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;
Copy link
Contributor

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.

@ben-ng ben-ng force-pushed the redundant-array-init-removal branch from a230183 to 6247ad6 Compare December 1, 2016 22:48
@ben-ng
Copy link
Contributor Author

ben-ng commented Dec 1, 2016

Thanks @swiftix, changes made.

I also cached the result of the lookup function in ASTContext as suggested.

@@ -168,6 +168,7 @@ typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *>
class ASTContext {
ASTContext(const ASTContext&) = delete;
void operator=(const ASTContext&) = delete;
FuncDecl *ArrayAppendElementDecl;
Copy link
Contributor

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.

@swiftix
Copy link
Contributor

swiftix commented Dec 2, 2016

@swift-ci Please smoke test

1 similar comment
@swiftix
Copy link
Contributor

swiftix commented Dec 2, 2016

@swift-ci Please smoke test

@swiftix
Copy link
Contributor

swiftix commented Dec 2, 2016

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?

@jckarter
Copy link
Member

jckarter commented Dec 2, 2016

Are we making different inlining judgments on Linux that cause the @_semantics-bearing methods to disappear before we have a change to change them?

@eeckstein
Copy link
Member

@jckarter I don't think so

@airspeedswift
Copy link
Member

Hi – sorry to come in so late on this but you probably want to be aware of this PR, since it is affecting Array.append(contentsOf:) as well as the += operator. The optimization would still be valid, but your implementation might be affected.

@gottesmm
Copy link
Member

gottesmm commented Dec 2, 2016

@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.

Copy link
Member

@gottesmm gottesmm left a 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;
Copy link
Member

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.

Copy link
Member

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;
Copy link
Member

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) {
Copy link
Member

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()) &&
Copy link
Member

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).