Skip to content

Commit b12015c

Browse files
committed
[SIL] Introduce the increment_profiler_counter instruction
This is a dedicated instruction for incrementing a profiler counter, which lowers to the `llvm.instrprof.increment` intrinsic. This replaces the builtin instruction that was previously used, and ensures that its arguments are statically known. This ensures that SIL optimization passes do not invalidate the instruction, fixing some code coverage cases in `-O`. rdar://39146527
1 parent 0d1c336 commit b12015c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+427
-226
lines changed

docs/SIL.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3898,6 +3898,22 @@ It is worth noting that a SIL DIExpression is similar to
38983898
info metadata. While LLVM represents ``!DIExpression`` are a list of 64-bit integers,
38993899
SIL DIExpression can have elements with various types, like AST nodes or strings.
39003900

3901+
Profiling
3902+
~~~~~~~~~
3903+
3904+
increment_profiler_counter
3905+
``````````````````````````
3906+
::
3907+
3908+
sil-instruction ::= 'increment_profiler_counter' int-literal ',' string-literal ',' 'num_counters' int-literal ',' 'hash' int-literal
3909+
3910+
increment_profiler_counter 1, "$foo", num_counters 3, hash 0
3911+
3912+
Increments a given profiler counter for a given PGO function name. This is
3913+
lowered to the ``llvm.instrprof.increment`` LLVM intrinsic. This instruction
3914+
is emitted when profiling is enabled, and enables features such as code coverage
3915+
and profile-guided optimization.
3916+
39013917
Accessing Memory
39023918
~~~~~~~~~~~~~~~~
39033919

include/swift/AST/Builtins.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -738,9 +738,6 @@ BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special)
738738
// TypePtrAuthDiscriminator has type <T> (T.Type) -> Int64
739739
BUILTIN_MISC_OPERATION(TypePtrAuthDiscriminator, "typePtrAuthDiscriminator", "n", Special)
740740

741-
// int_instrprof_increment has type (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ().
742-
BUILTIN_MISC_OPERATION(IntInstrprofIncrement, "int_instrprof_increment", "", Special)
743-
744741
/// Initialize the default-actor instance in a default actor object.
745742
BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Special)
746743

include/swift/AST/DiagnosticsParse.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,14 @@ ERROR(sil_invalid_attribute_for_instruction,none,
531531
ERROR(sil_invalid_attribute_for_expected,none,
532532
"Invalid attribute '%0' (expected '%1').",
533533
(StringRef, StringRef))
534+
ERROR(expected_sil_profiler_counter_idx,none,
535+
"expected profiler counter index", ())
536+
ERROR(expected_sil_profiler_counter_pgo_func_name,none,
537+
"expected profiler counter PGO function name", ())
538+
ERROR(expected_sil_profiler_counter_total,none,
539+
"expected profiler counter total", ())
540+
ERROR(expected_sil_profiler_counter_hash,none,
541+
"expected profiler counter hash", ())
534542

535543
// SIL Values
536544
ERROR(sil_value_redefinition,none,

include/swift/SIL/SILBuilder.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,6 +2131,19 @@ class SILBuilder {
21312131
return createCondFail(loc, one, message);
21322132
}
21332133

2134+
//===--------------------------------------------------------------------===//
2135+
// Profiler
2136+
//===--------------------------------------------------------------------===//
2137+
2138+
IncrementProfilerCounterInst *
2139+
createIncrementProfilerCounter(SILLocation Loc, unsigned CounterIdx,
2140+
StringRef PGOFuncName, unsigned NumCounters,
2141+
uint64_t PGOFuncHash) {
2142+
return insert(IncrementProfilerCounterInst::create(
2143+
getSILDebugLocation(Loc), CounterIdx, PGOFuncName, NumCounters,
2144+
PGOFuncHash, getModule()));
2145+
}
2146+
21342147
//===--------------------------------------------------------------------===//
21352148
// Array indexing instructions
21362149
//===--------------------------------------------------------------------===//

include/swift/SIL/SILCloner.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,17 @@ SILCloner<ImplClass>::visitCondFailInst(CondFailInst *Inst) {
26202620
Inst->getMessage()));
26212621
}
26222622

2623+
template <typename ImplClass>
2624+
void SILCloner<ImplClass>::visitIncrementProfilerCounterInst(
2625+
IncrementProfilerCounterInst *Inst) {
2626+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2627+
recordClonedInstruction(Inst,
2628+
getBuilder().createIncrementProfilerCounter(
2629+
getOpLocation(Inst->getLoc()),
2630+
Inst->getCounterIndex(), Inst->getPGOFuncName(),
2631+
Inst->getNumCounters(), Inst->getPGOFuncHash()));
2632+
}
2633+
26232634
template<typename ImplClass>
26242635
void
26252636
SILCloner<ImplClass>::visitIndexAddrInst(IndexAddrInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3858,7 +3858,53 @@ class BuiltinInst final
38583858
return OperandValueArrayRef(getAllOperands());
38593859
}
38603860
};
3861-
3861+
3862+
/// Increments a given profiler counter for a given PGO function name. This is
3863+
/// lowered to the \c llvm.instrprof.increment LLVM intrinsic.
3864+
class IncrementProfilerCounterInst final
3865+
: public InstructionBase<SILInstructionKind::IncrementProfilerCounterInst,
3866+
NonValueInstruction>,
3867+
private llvm::TrailingObjects<IncrementProfilerCounterInst, char> {
3868+
friend TrailingObjects;
3869+
friend SILBuilder;
3870+
3871+
unsigned CounterIdx;
3872+
unsigned PGOFuncNameLength;
3873+
unsigned NumCounters;
3874+
uint64_t PGOFuncHash;
3875+
3876+
IncrementProfilerCounterInst(SILDebugLocation Loc, unsigned CounterIdx,
3877+
unsigned PGOFuncNameLength, unsigned NumCounters,
3878+
uint64_t PGOFuncHash)
3879+
: InstructionBase(Loc), CounterIdx(CounterIdx),
3880+
PGOFuncNameLength(PGOFuncNameLength), NumCounters(NumCounters),
3881+
PGOFuncHash(PGOFuncHash) {}
3882+
3883+
static IncrementProfilerCounterInst *
3884+
create(SILDebugLocation Loc, unsigned CounterIdx, StringRef PGOFuncName,
3885+
unsigned NumCounters, uint64_t PGOFuncHash, SILModule &M);
3886+
3887+
public:
3888+
/// The index of the counter to be incremented.
3889+
unsigned getCounterIndex() const { return CounterIdx; }
3890+
3891+
/// The PGO function name for the function in which the counter resides.
3892+
StringRef getPGOFuncName() const {
3893+
return StringRef(getTrailingObjects<char>(), PGOFuncNameLength);
3894+
}
3895+
3896+
/// The total number of counters within the function.
3897+
unsigned getNumCounters() const { return NumCounters; }
3898+
3899+
/// A hash value for the function used to determine whether the profile is
3900+
/// outdated.
3901+
/// FIXME: This is currently always 0.
3902+
uint64_t getPGOFuncHash() const { return PGOFuncHash; }
3903+
3904+
ArrayRef<Operand> getAllOperands() const { return {}; }
3905+
MutableArrayRef<Operand> getAllOperands() { return {}; }
3906+
};
3907+
38623908
/// Initializes a SIL global variable. Only valid once, before any
38633909
/// usages of the global via GlobalAddrInst.
38643910
class AllocGlobalInst

include/swift/SIL/SILNodes.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,10 @@ NON_VALUE_INST(AbortApplyInst, abort_apply,
810810
BRIDGED_NON_VALUE_INST(CondFailInst, cond_fail,
811811
SILInstruction, MayHaveSideEffects, DoesNotRelease)
812812

813-
NODE_RANGE(NonValueInstruction, UnreachableInst, CondFailInst)
813+
NON_VALUE_INST(IncrementProfilerCounterInst, increment_profiler_counter,
814+
SILInstruction, MayReadWrite, DoesNotRelease)
815+
816+
NODE_RANGE(NonValueInstruction, UnreachableInst, IncrementProfilerCounterInst)
814817

815818
ABSTRACT_INST(MultipleValueInstruction, SILInstruction)
816819
MULTIPLE_VALUE_INST(BeginApplyInst, begin_apply,

lib/AST/Builtins.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,15 +1190,6 @@ static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) {
11901190
return builder.build(Id);
11911191
}
11921192

1193-
static ValueDecl *getIntInstrprofIncrement(ASTContext &C, Identifier Id) {
1194-
// (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ()
1195-
Type Int64Ty = BuiltinIntegerType::get(64, C);
1196-
Type Int32Ty = BuiltinIntegerType::get(32, C);
1197-
return getBuiltinFunction(Id,
1198-
{C.TheRawPointerType, Int64Ty, Int32Ty, Int32Ty},
1199-
TupleType::getEmpty(C));
1200-
}
1201-
12021193
static ValueDecl *getTypePtrAuthDiscriminator(ASTContext &C, Identifier Id) {
12031194
// <T : AnyObject> (T.Type) -> Int64
12041195
BuiltinFunctionBuilder builder(C);
@@ -2844,9 +2835,6 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
28442835
{},
28452836
TupleType::getEmpty(Context));
28462837

2847-
case BuiltinValueKind::IntInstrprofIncrement:
2848-
return getIntInstrprofIncrement(Context, Id);
2849-
28502838
case BuiltinValueKind::TypePtrAuthDiscriminator:
28512839
return getTypePtrAuthDiscriminator(Context, Id);
28522840

lib/IRGen/GenBuiltin.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -400,56 +400,6 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
400400
return;
401401
}
402402

403-
// Calls to the int_instrprof_increment intrinsic are emitted during SILGen.
404-
// At that stage, the function name GV used by the profiling pass is hidden.
405-
// Fix the intrinsic call here by pointing it to the correct GV.
406-
if (IID == llvm::Intrinsic::instrprof_increment) {
407-
// If we import profiling intrinsics from a swift module but profiling is
408-
// not enabled, ignore the increment.
409-
SILModule &SILMod = IGF.getSILModule();
410-
const auto &Opts = SILMod.getOptions();
411-
if (!Opts.GenerateProfile) {
412-
(void)args.claimAll();
413-
return;
414-
}
415-
416-
// Extract the PGO function name.
417-
auto *NameGEP = cast<llvm::User>(args.claimNext());
418-
auto *NameGV = dyn_cast<llvm::GlobalVariable>(NameGEP->stripPointerCasts());
419-
420-
// TODO: The SIL optimizer may rewrite the name argument in a way that
421-
// makes it impossible to lower. Until that issue is fixed, defensively
422-
// refuse to lower ill-formed intrinsics (rdar://39146527).
423-
if (!NameGV) {
424-
(void)args.claimAll();
425-
return;
426-
}
427-
428-
auto *NameC = NameGV->getInitializer();
429-
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
430-
StringRef PGOFuncName = Name.rtrim(StringRef("\0", 1));
431-
432-
// Point the increment call to the right function name variable.
433-
std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName(
434-
PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage);
435-
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(PGOFuncNameVar);
436-
if (!FuncNamePtr)
437-
FuncNamePtr = llvm::createPGOFuncNameVar(
438-
*IGF.IGM.getModule(), llvm::GlobalValue::LinkOnceAnyLinkage,
439-
PGOFuncName);
440-
441-
llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
442-
NameGEP = llvm::ConstantExpr::getGetElementPtr(
443-
((llvm::PointerType *)FuncNamePtr->getType())->getPointerElementType(),
444-
FuncNamePtr, makeArrayRef(Indices));
445-
446-
// Replace the placeholder value with the new GEP.
447-
Explosion replacement;
448-
replacement.add(NameGEP);
449-
replacement.add(args.claimAll());
450-
args = std::move(replacement);
451-
}
452-
453403
// Implement the ptrauth builtins as no-ops when the Clang
454404
// intrinsics are disabled.
455405
if ((IID == llvm::Intrinsic::ptrauth_sign ||

lib/IRGen/IRGenSIL.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,9 @@ class IRGenSILFunction :
13151315
void visitRebindMemoryInst(RebindMemoryInst *i);
13161316

13171317
void visitCondFailInst(CondFailInst *i);
1318-
1318+
1319+
void visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *I);
1320+
13191321
void visitConvertFunctionInst(ConvertFunctionInst *i);
13201322
void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *i);
13211323
void visitUpcastInst(UpcastInst *i);
@@ -6956,6 +6958,39 @@ void IRGenSILFunction::visitCondFailInst(swift::CondFailInst *i) {
69566958
FailBBs.push_back(failBB);
69576959
}
69586960

6961+
void IRGenSILFunction::visitIncrementProfilerCounterInst(
6962+
IncrementProfilerCounterInst *i) {
6963+
// If we import profiling intrinsics from a swift module but profiling is
6964+
// not enabled, ignore the increment.
6965+
if (!getSILModule().getOptions().GenerateProfile)
6966+
return;
6967+
6968+
// Retrieve the global variable that stores the PGO function name, creating it
6969+
// if needed.
6970+
auto funcName = i->getPGOFuncName();
6971+
auto varLinkage = llvm::GlobalValue::LinkOnceAnyLinkage;
6972+
auto *nameVar = IGM.Module.getNamedGlobal(
6973+
llvm::getPGOFuncNameVarName(funcName, varLinkage));
6974+
if (!nameVar)
6975+
nameVar = llvm::createPGOFuncNameVar(IGM.Module, varLinkage, funcName);
6976+
6977+
// We need to GEP the function name global to point to the first character of
6978+
// the string.
6979+
llvm::SmallVector<llvm::Value *, 2> indices;
6980+
indices.append(2, llvm::ConstantInt::get(IGM.SizeTy, 0));
6981+
auto *nameGEP = llvm::ConstantExpr::getGetElementPtr(
6982+
nameVar->getValueType(), nameVar, makeArrayRef(indices));
6983+
6984+
// Emit the call to the 'llvm.instrprof.increment' LLVM intrinsic.
6985+
llvm::Value *args[] = {
6986+
nameGEP,
6987+
llvm::ConstantInt::get(IGM.Int64Ty, i->getPGOFuncHash()),
6988+
llvm::ConstantInt::get(IGM.Int32Ty, i->getNumCounters()),
6989+
llvm::ConstantInt::get(IGM.Int32Ty, i->getCounterIndex())
6990+
};
6991+
Builder.CreateIntrinsicCall(llvm::Intrinsic::instrprof_increment, args);
6992+
}
6993+
69596994
void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) {
69606995
assert(!i->getMember().isForeign);
69616996

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ SHOULD_NEVER_VISIT_INST(ReleaseValue)
119119
SHOULD_NEVER_VISIT_INST(ReleaseValueAddr)
120120
SHOULD_NEVER_VISIT_INST(StrongRelease)
121121
SHOULD_NEVER_VISIT_INST(GetAsyncContinuation)
122+
SHOULD_NEVER_VISIT_INST(IncrementProfilerCounter)
122123

123124
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
124125
SHOULD_NEVER_VISIT_INST(StrongRetain##Name) \
@@ -794,7 +795,6 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PoundAssert)
794795
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GlobalStringTablePointer)
795796
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TypePtrAuthDiscriminator)
796797
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TargetOSVersionAtLeast)
797-
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntInstrprofIncrement)
798798
BUILTIN_OPERAND_OWNERSHIP(UnownedInstantaneousUse, Copy)
799799
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLet)
800800
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, EndAsyncLet)

lib/SIL/IR/SILInstructions.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,22 @@ BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
438438
Substitutions(Subs) {
439439
}
440440

441+
IncrementProfilerCounterInst *IncrementProfilerCounterInst::create(
442+
SILDebugLocation Loc, unsigned CounterIdx, StringRef PGOFuncName,
443+
unsigned NumCounters, uint64_t PGOFuncHash, SILModule &M) {
444+
445+
auto PGOFuncNameLength = PGOFuncName.size();
446+
auto Size = totalSizeToAlloc<char>(PGOFuncNameLength);
447+
auto Buffer = M.allocateInst(Size, alignof(IncrementProfilerCounterInst));
448+
449+
auto *Inst = ::new (Buffer) IncrementProfilerCounterInst(
450+
Loc, CounterIdx, PGOFuncNameLength, NumCounters, PGOFuncHash);
451+
452+
std::uninitialized_copy(PGOFuncName.begin(), PGOFuncName.end(),
453+
Inst->getTrailingObjects<char>());
454+
return Inst;
455+
}
456+
441457
InitBlockStorageHeaderInst *
442458
InitBlockStorageHeaderInst::create(SILFunction &F,
443459
SILDebugLocation DebugLoc, SILValue BlockStorage,

lib/SIL/IR/SILPrinter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2359,7 +2359,14 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
23592359
*this << getIDAndType(FI->getOperand()) << ", "
23602360
<< QuotedString(FI->getMessage());
23612361
}
2362-
2362+
2363+
void visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *IPCI) {
2364+
*this << IPCI->getCounterIndex() << ", "
2365+
<< QuotedString(IPCI->getPGOFuncName()) << ", "
2366+
<< "num_counters " << IPCI->getNumCounters() << ", "
2367+
<< "hash " << IPCI->getPGOFuncHash();
2368+
}
2369+
23632370
void visitIndexAddrInst(IndexAddrInst *IAI) {
23642371
*this << getIDAndType(IAI->getBase()) << ", "
23652372
<< getIDAndType(IAI->getIndex());

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,6 @@ CONSTANT_OWNERSHIP_BUILTIN(None, TSanInoutAccess)
532532
CONSTANT_OWNERSHIP_BUILTIN(None, Swift3ImplicitObjCEntrypoint)
533533
CONSTANT_OWNERSHIP_BUILTIN(None, PoundAssert)
534534
CONSTANT_OWNERSHIP_BUILTIN(None, TypePtrAuthDiscriminator)
535-
CONSTANT_OWNERSHIP_BUILTIN(None, IntInstrprofIncrement)
536535
CONSTANT_OWNERSHIP_BUILTIN(None, TargetOSVersionAtLeast)
537536
CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer)
538537
CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentAsyncTask)

0 commit comments

Comments
 (0)