Skip to content

Commit 895cd01

Browse files
Merge pull request #84796 from aschwaighofer/assembly_vision_copy_destroy
AssemblyVision: Emit remarks for generic copies and destroys
2 parents 5f897a8 + a2e930e commit 895cd01

File tree

3 files changed

+140
-3
lines changed

3 files changed

+140
-3
lines changed

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/DiagnosticsParse.h"
1919
#include "swift/AST/DistributedDecl.h"
20+
#include "swift/AST/Expr.h"
2021
#include "swift/AST/ParameterList.h"
2122
#include "swift/AST/SemanticAttrs.h"
2223
#include "swift/Basic/Assertions.h"
@@ -407,6 +408,21 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
407408
&& "addFunctionAttributes() on ABI-only decl?");
408409
addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration,
409410
constant);
411+
} else if (auto *ce = constant.getAbstractClosureExpr()) {
412+
if (mod.getOptions().EnableGlobalAssemblyVision) {
413+
F->addSemanticsAttr(semantics::FORCE_EMIT_OPT_REMARK_PREFIX);
414+
} else {
415+
// Add the attribute to a closure if the enclosing method has it.
416+
auto decl = ce->getParent()->getInnermostDeclarationDeclContext();
417+
if (decl &&
418+
decl->getAttrs().getAttribute(DeclAttrKind::EmitAssemblyVisionRemarks)) {
419+
F->addSemanticsAttr(semantics::FORCE_EMIT_OPT_REMARK_PREFIX);
420+
}
421+
}
422+
} else {
423+
if (mod.getOptions().EnableGlobalAssemblyVision) {
424+
F->addSemanticsAttr(semantics::FORCE_EMIT_OPT_REMARK_PREFIX);
425+
}
410426
}
411427

412428
return F;

lib/SILOptimizer/Transforms/AssemblyVisionRemarkGenerator.cpp

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,30 @@ static llvm::cl::opt<bool> DecllessDebugValueUseSILDebugInfo(
6363
namespace {
6464

6565
struct ValueToDeclInferrer {
66+
67+
enum class NotePrefix {
68+
of,
69+
fromLocation,
70+
toLocation,
71+
inMemoryLocationOf
72+
};
73+
6674
using Argument = OptRemark::Argument;
6775
using ArgumentKeyKind = OptRemark::ArgumentKeyKind;
6876

6977
SmallVector<std::pair<SILType, Projection>, 32> accessPath;
7078
SmallVector<Operand *, 32> rcIdenticalSecondaryUseSearch;
7179
RCIdentityFunctionInfo &rcfi;
80+
NotePrefix currentNotePrefix = NotePrefix::of;
7281

7382
ValueToDeclInferrer(RCIdentityFunctionInfo &rcfi) : rcfi(rcfi) {}
7483

7584
/// Given a value, attempt to infer a conservative list of decls that the
7685
/// passed in value could be referring to. This is done just using heuristics
7786
bool infer(ArgumentKeyKind keyKind, SILValue value,
7887
SmallVectorImpl<Argument> &resultingInferredDecls,
79-
bool allowSingleRefEltAddrPeek = false);
88+
bool allowSingleRefEltAddrPeek = false,
89+
NotePrefix notePrefix = NotePrefix::of);
8090

8191
/// Print out a note to \p stream that beings at decl and then if
8292
/// useProjectionPath is set to true iterates the accessPath we computed for
@@ -196,7 +206,20 @@ void ValueToDeclInferrer::printAccessPath(llvm::raw_string_ostream &stream) {
196206
void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream,
197207
StringRef name,
198208
bool shouldPrintAccessPath) {
199-
stream << "of '" << name;
209+
switch (currentNotePrefix) {
210+
case NotePrefix::of:
211+
stream << "of '" << name;
212+
break;
213+
case NotePrefix::fromLocation:
214+
stream << "from location '" << name;
215+
break;
216+
case NotePrefix::toLocation:
217+
stream << "to location '" << name;
218+
break;
219+
case NotePrefix::inMemoryLocationOf:
220+
stream << "in memory location of '" << name;
221+
break;
222+
}
200223
if (shouldPrintAccessPath)
201224
printAccessPath(stream);
202225
stream << "'";
@@ -314,7 +337,11 @@ bool ValueUseToDeclInferrer::findDecls(Operand *use, SILValue value) {
314337
bool ValueToDeclInferrer::infer(
315338
ArgumentKeyKind keyKind, SILValue value,
316339
SmallVectorImpl<Argument> &resultingInferredDecls,
317-
bool allowSingleRefEltAddrPeek) {
340+
bool allowSingleRefEltAddrPeek,
341+
NotePrefix notePrefix) {
342+
343+
currentNotePrefix = notePrefix;
344+
318345
// Clear the stored access path at end of scope.
319346
SWIFT_DEFER { accessPath.clear(); };
320347
ValueUseToDeclInferrer valueUseInferrer{
@@ -533,10 +560,72 @@ struct AssemblyVisionRemarkGeneratorInstructionVisitor
533560
void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *ccabi);
534561
void visitUnconditionalCheckedCastAddrInst(
535562
UnconditionalCheckedCastAddrInst *uccai);
563+
void visitCopyAddrInst(CopyAddrInst *copy);
564+
void visitDestroyAddrInst(DestroyAddrInst *destroy);
536565
};
537566

538567
} // anonymous namespace
539568

569+
void AssemblyVisionRemarkGeneratorInstructionVisitor::
570+
visitCopyAddrInst(CopyAddrInst *copy) {
571+
ORE.emit([&]() {
572+
using namespace OptRemark;
573+
SmallVector<Argument, 8> inferredArgs;
574+
bool foundArgs = valueToDeclInferrer.infer(
575+
ArgumentKeyKind::Note, copy->getSrc(), inferredArgs,
576+
true /*allow single ref elt peek*/,
577+
ValueToDeclInferrer::NotePrefix::fromLocation);
578+
(void)foundArgs;
579+
580+
// Use the actual source loc of the
581+
auto remark = RemarkMissed("memory", *copy)
582+
<< "Memory copy of value with type '"
583+
<< NV("ValueType", copy->getSrc()->getType()) << "'";
584+
if (foundArgs) {
585+
for (auto arg : inferredArgs) {
586+
remark << arg;
587+
}
588+
}
589+
inferredArgs.clear();
590+
foundArgs = valueToDeclInferrer.infer(
591+
ArgumentKeyKind::Note, copy->getDest(), inferredArgs,
592+
true /*allow single ref elt peek*/,
593+
ValueToDeclInferrer::NotePrefix::toLocation);
594+
if (foundArgs) {
595+
for (auto arg : inferredArgs) {
596+
remark << arg;
597+
}
598+
}
599+
600+
return remark;
601+
});
602+
}
603+
604+
void AssemblyVisionRemarkGeneratorInstructionVisitor::
605+
visitDestroyAddrInst(DestroyAddrInst *destroy) {
606+
ORE.emit([&]() {
607+
using namespace OptRemark;
608+
SmallVector<Argument, 8> inferredArgs;
609+
bool foundArgs = valueToDeclInferrer.infer(
610+
ArgumentKeyKind::Note, destroy->getOperand(), inferredArgs,
611+
true /*allow single ref elt peek*/,
612+
ValueToDeclInferrer::NotePrefix::inMemoryLocationOf);
613+
(void)foundArgs;
614+
615+
// Use the actual source loc of the
616+
auto remark = RemarkMissed("memory", *destroy)
617+
<< "Memory destroy of value with type '"
618+
<< NV("ValueType", destroy->getOperand()->getType()) << "'";
619+
if (foundArgs) {
620+
for (auto arg : inferredArgs) {
621+
remark << arg;
622+
}
623+
}
624+
625+
return remark;
626+
});
627+
}
628+
540629
void AssemblyVisionRemarkGeneratorInstructionVisitor::
541630
visitUnconditionalCheckedCastAddrInst(
542631
UnconditionalCheckedCastAddrInst *uccai) {

test/SILOptimizer/assemblyvision_remark/basic.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,35 @@ func simpleInOut() -> Klass {
304304
// expected-note @-5:9 {{of 'x.next'}}
305305
return x
306306
}
307+
308+
309+
@inline(never)
310+
@_semantics("optimize.sil.specialize.generic.size.never")
311+
public func use<T>(_ t: inout T) { // expected-note @:22 {{from location 't'}}
312+
print(t); // expected-remark @:11 {{heap allocated ref of type}}
313+
// expected-remark @-1:11 {{Memory copy of value with type 'T'}}
314+
// expected-remark @-2:12 {{release of type}}
315+
}
316+
317+
@inline(never)
318+
@_assemblyVision
319+
public func genericFunc<T>(_ t: T) { // expected-note @:30 {{from location 't'}}
320+
var temp: T = t // expected-note @:9 {{to location 'temp'}}
321+
// expected-remark @-1:9 {{Memory destroy of value with type 'T'}}
322+
// expected-note @-2:9 {{in memory location of 'temp'}}
323+
// expected-remark @-3:19 {{Memory copy of value with type 'T'}}
324+
use(&temp)
325+
use(&temp)
326+
}
327+
328+
@_assemblyVision
329+
public func forEach<T>(_ elements: Array<T>, body: (borrowing T) -> Void) {
330+
elements.withUnsafeBufferPointer { buffer in
331+
for i in buffer.indices { // expected-remark @:5 {{Specialized function "Swift.IndexingIterator.next()" with type (@inout IndexingIterator<Range<Int>>) -> Optional<Int>}}
332+
// expected-remark @-1:21 {{Specialized function "Swift.Collection<>.makeIterator()" with type (Range<Int>) -> IndexingIterator<Range<Int>>}}
333+
body(/* copy */ buffer[i]) // expected-remark @:29 {{Memory copy of value with type 'T'}}
334+
// expected-remark @-1:32 {{Memory destroy of value with type 'T'}}
335+
// destroy of T
336+
}
337+
}
338+
}

0 commit comments

Comments
 (0)