Skip to content

[SIL] Introduce the increment_profiler_counter instruction #60979

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

Merged
merged 1 commit into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3898,6 +3898,22 @@ It is worth noting that a SIL DIExpression is similar to
info metadata. While LLVM represents ``!DIExpression`` are a list of 64-bit integers,
SIL DIExpression can have elements with various types, like AST nodes or strings.

Profiling
~~~~~~~~~

increment_profiler_counter
``````````````````````````
::

sil-instruction ::= 'increment_profiler_counter' int-literal ',' string-literal ',' 'num_counters' int-literal ',' 'hash' int-literal

increment_profiler_counter 1, "$foo", num_counters 3, hash 0

Increments a given profiler counter for a given PGO function name. This is
lowered to the ``llvm.instrprof.increment`` LLVM intrinsic. This instruction
is emitted when profiling is enabled, and enables features such as code coverage
and profile-guided optimization.

Accessing Memory
~~~~~~~~~~~~~~~~

Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -738,9 +738,6 @@ BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special)
// TypePtrAuthDiscriminator has type <T> (T.Type) -> Int64
BUILTIN_MISC_OPERATION(TypePtrAuthDiscriminator, "typePtrAuthDiscriminator", "n", Special)

// int_instrprof_increment has type (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ().
BUILTIN_MISC_OPERATION(IntInstrprofIncrement, "int_instrprof_increment", "", Special)

/// Initialize the default-actor instance in a default actor object.
BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Special)

Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,14 @@ ERROR(sil_invalid_attribute_for_instruction,none,
ERROR(sil_invalid_attribute_for_expected,none,
"Invalid attribute '%0' (expected '%1').",
(StringRef, StringRef))
ERROR(expected_sil_profiler_counter_idx,none,
"expected profiler counter index", ())
ERROR(expected_sil_profiler_counter_pgo_func_name,none,
"expected profiler counter PGO function name", ())
ERROR(expected_sil_profiler_counter_total,none,
"expected profiler counter total", ())
ERROR(expected_sil_profiler_counter_hash,none,
"expected profiler counter hash", ())

// SIL Values
ERROR(sil_value_redefinition,none,
Expand Down
13 changes: 13 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,19 @@ class SILBuilder {
return createCondFail(loc, one, message);
}

//===--------------------------------------------------------------------===//
// Profiler
//===--------------------------------------------------------------------===//

IncrementProfilerCounterInst *
createIncrementProfilerCounter(SILLocation Loc, unsigned CounterIdx,
StringRef PGOFuncName, unsigned NumCounters,
uint64_t PGOFuncHash) {
return insert(IncrementProfilerCounterInst::create(
getSILDebugLocation(Loc), CounterIdx, PGOFuncName, NumCounters,
PGOFuncHash, getModule()));
}

//===--------------------------------------------------------------------===//
// Array indexing instructions
//===--------------------------------------------------------------------===//
Expand Down
11 changes: 11 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,17 @@ SILCloner<ImplClass>::visitCondFailInst(CondFailInst *Inst) {
Inst->getMessage()));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitIncrementProfilerCounterInst(
IncrementProfilerCounterInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst,
getBuilder().createIncrementProfilerCounter(
getOpLocation(Inst->getLoc()),
Inst->getCounterIndex(), Inst->getPGOFuncName(),
Inst->getNumCounters(), Inst->getPGOFuncHash()));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitIndexAddrInst(IndexAddrInst *Inst) {
Expand Down
48 changes: 47 additions & 1 deletion include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3858,7 +3858,53 @@ class BuiltinInst final
return OperandValueArrayRef(getAllOperands());
}
};


/// Increments a given profiler counter for a given PGO function name. This is
/// lowered to the \c llvm.instrprof.increment LLVM intrinsic.
class IncrementProfilerCounterInst final
: public InstructionBase<SILInstructionKind::IncrementProfilerCounterInst,
NonValueInstruction>,
private llvm::TrailingObjects<IncrementProfilerCounterInst, char> {
friend TrailingObjects;
friend SILBuilder;

unsigned CounterIdx;
unsigned PGOFuncNameLength;
unsigned NumCounters;
uint64_t PGOFuncHash;

IncrementProfilerCounterInst(SILDebugLocation Loc, unsigned CounterIdx,
unsigned PGOFuncNameLength, unsigned NumCounters,
uint64_t PGOFuncHash)
: InstructionBase(Loc), CounterIdx(CounterIdx),
PGOFuncNameLength(PGOFuncNameLength), NumCounters(NumCounters),
PGOFuncHash(PGOFuncHash) {}

static IncrementProfilerCounterInst *
create(SILDebugLocation Loc, unsigned CounterIdx, StringRef PGOFuncName,
unsigned NumCounters, uint64_t PGOFuncHash, SILModule &M);

public:
/// The index of the counter to be incremented.
unsigned getCounterIndex() const { return CounterIdx; }

/// The PGO function name for the function in which the counter resides.
StringRef getPGOFuncName() const {
return StringRef(getTrailingObjects<char>(), PGOFuncNameLength);
}

/// The total number of counters within the function.
unsigned getNumCounters() const { return NumCounters; }

/// A hash value for the function used to determine whether the profile is
/// outdated.
/// FIXME: This is currently always 0.
uint64_t getPGOFuncHash() const { return PGOFuncHash; }

ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }
};

/// Initializes a SIL global variable. Only valid once, before any
/// usages of the global via GlobalAddrInst.
class AllocGlobalInst
Expand Down
5 changes: 4 additions & 1 deletion include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,10 @@ NON_VALUE_INST(AbortApplyInst, abort_apply,
BRIDGED_NON_VALUE_INST(CondFailInst, cond_fail,
SILInstruction, MayHaveSideEffects, DoesNotRelease)

NODE_RANGE(NonValueInstruction, UnreachableInst, CondFailInst)
NON_VALUE_INST(IncrementProfilerCounterInst, increment_profiler_counter,
SILInstruction, MayReadWrite, DoesNotRelease)

NODE_RANGE(NonValueInstruction, UnreachableInst, IncrementProfilerCounterInst)

ABSTRACT_INST(MultipleValueInstruction, SILInstruction)
MULTIPLE_VALUE_INST(BeginApplyInst, begin_apply,
Expand Down
12 changes: 0 additions & 12 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1190,15 +1190,6 @@ static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) {
return builder.build(Id);
}

static ValueDecl *getIntInstrprofIncrement(ASTContext &C, Identifier Id) {
// (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ()
Type Int64Ty = BuiltinIntegerType::get(64, C);
Type Int32Ty = BuiltinIntegerType::get(32, C);
return getBuiltinFunction(Id,
{C.TheRawPointerType, Int64Ty, Int32Ty, Int32Ty},
TupleType::getEmpty(C));
}

static ValueDecl *getTypePtrAuthDiscriminator(ASTContext &C, Identifier Id) {
// <T : AnyObject> (T.Type) -> Int64
BuiltinFunctionBuilder builder(C);
Expand Down Expand Up @@ -2844,9 +2835,6 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
{},
TupleType::getEmpty(Context));

case BuiltinValueKind::IntInstrprofIncrement:
return getIntInstrprofIncrement(Context, Id);

case BuiltinValueKind::TypePtrAuthDiscriminator:
return getTypePtrAuthDiscriminator(Context, Id);

Expand Down
50 changes: 0 additions & 50 deletions lib/IRGen/GenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,56 +400,6 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
return;
}

// Calls to the int_instrprof_increment intrinsic are emitted during SILGen.
// At that stage, the function name GV used by the profiling pass is hidden.
// Fix the intrinsic call here by pointing it to the correct GV.
if (IID == llvm::Intrinsic::instrprof_increment) {
// If we import profiling intrinsics from a swift module but profiling is
// not enabled, ignore the increment.
SILModule &SILMod = IGF.getSILModule();
const auto &Opts = SILMod.getOptions();
if (!Opts.GenerateProfile) {
(void)args.claimAll();
return;
}

// Extract the PGO function name.
auto *NameGEP = cast<llvm::User>(args.claimNext());
auto *NameGV = dyn_cast<llvm::GlobalVariable>(NameGEP->stripPointerCasts());

// TODO: The SIL optimizer may rewrite the name argument in a way that
// makes it impossible to lower. Until that issue is fixed, defensively
// refuse to lower ill-formed intrinsics (rdar://39146527).
if (!NameGV) {
(void)args.claimAll();
return;
}

auto *NameC = NameGV->getInitializer();
StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues();
StringRef PGOFuncName = Name.rtrim(StringRef("\0", 1));

// Point the increment call to the right function name variable.
std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName(
PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage);
auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(PGOFuncNameVar);
if (!FuncNamePtr)
FuncNamePtr = llvm::createPGOFuncNameVar(
*IGF.IGM.getModule(), llvm::GlobalValue::LinkOnceAnyLinkage,
PGOFuncName);

llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1));
NameGEP = llvm::ConstantExpr::getGetElementPtr(
((llvm::PointerType *)FuncNamePtr->getType())->getPointerElementType(),
FuncNamePtr, makeArrayRef(Indices));

// Replace the placeholder value with the new GEP.
Explosion replacement;
replacement.add(NameGEP);
replacement.add(args.claimAll());
args = std::move(replacement);
}

// Implement the ptrauth builtins as no-ops when the Clang
// intrinsics are disabled.
if ((IID == llvm::Intrinsic::ptrauth_sign ||
Expand Down
37 changes: 36 additions & 1 deletion lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,9 @@ class IRGenSILFunction :
void visitRebindMemoryInst(RebindMemoryInst *i);

void visitCondFailInst(CondFailInst *i);


void visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *I);

void visitConvertFunctionInst(ConvertFunctionInst *i);
void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *i);
void visitUpcastInst(UpcastInst *i);
Expand Down Expand Up @@ -6956,6 +6958,39 @@ void IRGenSILFunction::visitCondFailInst(swift::CondFailInst *i) {
FailBBs.push_back(failBB);
}

void IRGenSILFunction::visitIncrementProfilerCounterInst(
IncrementProfilerCounterInst *i) {
// If we import profiling intrinsics from a swift module but profiling is
// not enabled, ignore the increment.
if (!getSILModule().getOptions().GenerateProfile)
return;

// Retrieve the global variable that stores the PGO function name, creating it
// if needed.
auto funcName = i->getPGOFuncName();
auto varLinkage = llvm::GlobalValue::LinkOnceAnyLinkage;
auto *nameVar = IGM.Module.getNamedGlobal(
llvm::getPGOFuncNameVarName(funcName, varLinkage));
if (!nameVar)
nameVar = llvm::createPGOFuncNameVar(IGM.Module, varLinkage, funcName);

// We need to GEP the function name global to point to the first character of
// the string.
llvm::SmallVector<llvm::Value *, 2> indices;
indices.append(2, llvm::ConstantInt::get(IGM.SizeTy, 0));
auto *nameGEP = llvm::ConstantExpr::getGetElementPtr(
nameVar->getValueType(), nameVar, makeArrayRef(indices));

// Emit the call to the 'llvm.instrprof.increment' LLVM intrinsic.
llvm::Value *args[] = {
nameGEP,
llvm::ConstantInt::get(IGM.Int64Ty, i->getPGOFuncHash()),
llvm::ConstantInt::get(IGM.Int32Ty, i->getNumCounters()),
llvm::ConstantInt::get(IGM.Int32Ty, i->getCounterIndex())
};
Builder.CreateIntrinsicCall(llvm::Intrinsic::instrprof_increment, args);
}

void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) {
assert(!i->getMember().isForeign);

Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ SHOULD_NEVER_VISIT_INST(ReleaseValue)
SHOULD_NEVER_VISIT_INST(ReleaseValueAddr)
SHOULD_NEVER_VISIT_INST(StrongRelease)
SHOULD_NEVER_VISIT_INST(GetAsyncContinuation)
SHOULD_NEVER_VISIT_INST(IncrementProfilerCounter)

#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
SHOULD_NEVER_VISIT_INST(StrongRetain##Name) \
Expand Down Expand Up @@ -794,7 +795,6 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PoundAssert)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GlobalStringTablePointer)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TypePtrAuthDiscriminator)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TargetOSVersionAtLeast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntInstrprofIncrement)
BUILTIN_OPERAND_OWNERSHIP(UnownedInstantaneousUse, Copy)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLet)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, EndAsyncLet)
Expand Down
16 changes: 16 additions & 0 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,22 @@ BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
Substitutions(Subs) {
}

IncrementProfilerCounterInst *IncrementProfilerCounterInst::create(
SILDebugLocation Loc, unsigned CounterIdx, StringRef PGOFuncName,
unsigned NumCounters, uint64_t PGOFuncHash, SILModule &M) {

auto PGOFuncNameLength = PGOFuncName.size();
auto Size = totalSizeToAlloc<char>(PGOFuncNameLength);
auto Buffer = M.allocateInst(Size, alignof(IncrementProfilerCounterInst));

auto *Inst = ::new (Buffer) IncrementProfilerCounterInst(
Loc, CounterIdx, PGOFuncNameLength, NumCounters, PGOFuncHash);

std::uninitialized_copy(PGOFuncName.begin(), PGOFuncName.end(),
Inst->getTrailingObjects<char>());
return Inst;
}

InitBlockStorageHeaderInst *
InitBlockStorageHeaderInst::create(SILFunction &F,
SILDebugLocation DebugLoc, SILValue BlockStorage,
Expand Down
9 changes: 8 additions & 1 deletion lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2359,7 +2359,14 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
*this << getIDAndType(FI->getOperand()) << ", "
<< QuotedString(FI->getMessage());
}


void visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *IPCI) {
*this << IPCI->getCounterIndex() << ", "
<< QuotedString(IPCI->getPGOFuncName()) << ", "
<< "num_counters " << IPCI->getNumCounters() << ", "
<< "hash " << IPCI->getPGOFuncHash();
}

void visitIndexAddrInst(IndexAddrInst *IAI) {
*this << getIDAndType(IAI->getBase()) << ", "
<< getIDAndType(IAI->getIndex());
Expand Down
1 change: 0 additions & 1 deletion lib/SIL/IR/ValueOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,6 @@ CONSTANT_OWNERSHIP_BUILTIN(None, TSanInoutAccess)
CONSTANT_OWNERSHIP_BUILTIN(None, Swift3ImplicitObjCEntrypoint)
CONSTANT_OWNERSHIP_BUILTIN(None, PoundAssert)
CONSTANT_OWNERSHIP_BUILTIN(None, TypePtrAuthDiscriminator)
CONSTANT_OWNERSHIP_BUILTIN(None, IntInstrprofIncrement)
CONSTANT_OWNERSHIP_BUILTIN(None, TargetOSVersionAtLeast)
CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer)
CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentAsyncTask)
Expand Down
Loading