[InstrProf] Add the skipprofile attribute
As discussed in [0], this diff adds the `skipprofile` attribute to
prevent the function from being profiled while allowing profiled
functions to be inlined into it. The `noprofile` attribute remains
unchanged.
The `noprofile` attribute is used for functions where it is
dangerous to add instrumentation to while the `skipprofile` attribute is
used to reduce code size or performance overhead.
[0] https://discourse.llvm.org/t/why-does-the-noprofile-attribute-restrict-inlining/64108
Reviewed By: phosek
Differential Revision: https://reviews.llvm.org/D130807
GitOrigin-RevId: 12e78ff88105f2dc6cb1449d6fcd5d8f69e0512f
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 2abe628..a3c0824 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -1803,8 +1803,14 @@
startup time if the function is not called during program startup.
``noprofile``
This function attribute prevents instrumentation based profiling, used for
- coverage or profile based optimization, from being added to a function,
- even when inlined.
+ coverage or profile based optimization, from being added to a function. It
+ also blocks inlining if the caller and callee have different values of this
+ attribute.
+``skipprofile``
+ This function attribute prevents instrumentation based profiling, used for
+ coverage or profile based optimization, from being added to a function. This
+ attribute does not restrict inlining, so instrumented instruction could end
+ up in this function.
``noredzone``
This attribute indicates that the code generator should not use a
red zone, even if the target-specific ABI normally permits it.
diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h
index eee4c50..d26507a 100644
--- a/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/include/llvm/Bitcode/LLVMBitCodes.h
@@ -689,6 +689,7 @@
ATTR_KIND_ALLOC_KIND = 82,
ATTR_KIND_PRESPLIT_COROUTINE = 83,
ATTR_KIND_FNRETTHUNK_EXTERN = 84,
+ ATTR_KIND_SKIP_PROFILE = 85,
};
enum ComdatSelectionKindCodes {
diff --git a/include/llvm/IR/Attributes.td b/include/llvm/IR/Attributes.td
index ea4bf80..642a390 100644
--- a/include/llvm/IR/Attributes.td
+++ b/include/llvm/IR/Attributes.td
@@ -186,6 +186,10 @@
/// Function should not be instrumented.
def NoProfile : EnumAttr<"noprofile", [FnAttr]>;
+/// This function should not be instrumented but it is ok to inline profiled
+// functions into it.
+def SkipProfile : EnumAttr<"skipprofile", [FnAttr]>;
+
/// Function doesn't unwind stack.
def NoUnwind : EnumAttr<"nounwind", [FnAttr]>;
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 343d49b..379614b 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1919,6 +1919,8 @@
return Attribute::NoCfCheck;
case bitc::ATTR_KIND_NO_PROFILE:
return Attribute::NoProfile;
+ case bitc::ATTR_KIND_SKIP_PROFILE:
+ return Attribute::SkipProfile;
case bitc::ATTR_KIND_NO_UNWIND:
return Attribute::NoUnwind;
case bitc::ATTR_KIND_NO_SANITIZE_BOUNDS:
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index eda4ac7..f66bc2d 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -698,6 +698,8 @@
return bitc::ATTR_KIND_NOCF_CHECK;
case Attribute::NoProfile:
return bitc::ATTR_KIND_NO_PROFILE;
+ case Attribute::SkipProfile:
+ return bitc::ATTR_KIND_SKIP_PROFILE;
case Attribute::NoUnwind:
return bitc::ATTR_KIND_NO_UNWIND;
case Attribute::NoSanitizeBounds:
diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index ac4a1fd..5939fe1 100644
--- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -797,6 +797,8 @@
if (isUsingScopeBasedEH(F)) continue;
if (F.hasFnAttribute(llvm::Attribute::NoProfile))
continue;
+ if (F.hasFnAttribute(llvm::Attribute::SkipProfile))
+ continue;
// Add the function line number to the lines of the entry block
// to have a counter for the function definition.
diff --git a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index 90cc61c..b856772 100644
--- a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -1574,6 +1574,8 @@
continue;
if (F.hasFnAttribute(llvm::Attribute::NoProfile))
continue;
+ if (F.hasFnAttribute(llvm::Attribute::SkipProfile))
+ continue;
auto &TLI = LookupTLI(F);
auto *BPI = LookupBPI(F);
auto *BFI = LookupBFI(F);
diff --git a/lib/Transforms/Utils/CodeExtractor.cpp b/lib/Transforms/Utils/CodeExtractor.cpp
index 421f1f3..48e1f9e 100644
--- a/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/lib/Transforms/Utils/CodeExtractor.cpp
@@ -963,6 +963,7 @@
case Attribute::NoCfCheck:
case Attribute::MustProgress:
case Attribute::NoProfile:
+ case Attribute::SkipProfile:
break;
// These attributes cannot be applied to functions.
case Attribute::Alignment:
diff --git a/test/Bitcode/attributes.ll b/test/Bitcode/attributes.ll
index 78b54a5..f8d3172 100644
--- a/test/Bitcode/attributes.ll
+++ b/test/Bitcode/attributes.ll
@@ -535,6 +535,9 @@
; CHECK: define void @f87() [[FNRETTHUNKEXTERN:#[0-9]+]]
define void @f87() fn_ret_thunk_extern { ret void }
+; CHECK: define void @f88() [[SKIPPROFILE:#[0-9]+]]
+define void @f88() skipprofile { ret void }
+
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
@@ -589,4 +592,5 @@
; CHECK: attributes #51 = { uwtable(sync) }
; CHECK: attributes #52 = { nosanitize_bounds }
; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern }
+; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
diff --git a/test/Transforms/GCOVProfiling/noprofile.ll b/test/Transforms/GCOVProfiling/noprofile.ll
index b1ce27e..b5dad49 100644
--- a/test/Transforms/GCOVProfiling/noprofile.ll
+++ b/test/Transforms/GCOVProfiling/noprofile.ll
@@ -10,6 +10,14 @@
ret i32 42, !dbg !27
}
+; Test that the skipprofile attribute disables profiling.
+define dso_local i32 @skip_instr(i32 %a) skipprofile {
+; CHECK-LABEL: @skip_instr(
+; CHECK-NEXT: ret i32 52
+;
+ ret i32 52
+}
+
define dso_local i32 @instr(i32 %a) !dbg !28 {
; CHECK-LABEL: @instr(
; CHECK-NEXT: [[GCOV_CTR:%.*]] = load i64, ptr @__llvm_gcov_ctr, align 4, !dbg [[DBG8:![0-9]+]]
diff --git a/test/Transforms/PGOProfile/noprofile.ll b/test/Transforms/PGOProfile/noprofile.ll
index c8bdb67..0da101a 100644
--- a/test/Transforms/PGOProfile/noprofile.ll
+++ b/test/Transforms/PGOProfile/noprofile.ll
@@ -21,4 +21,10 @@
ret i32 %sub
}
+define i32 @test3() skipprofile {
+entry:
+; CHECK-NOT: call void @llvm.instrprof.increment
+ ret i32 101
+}
+
attributes #0 = { noprofile }