nickdesaulniers updated this revision to Diff 514746.
nickdesaulniers marked 3 inline comments as done.
nickdesaulniers added a comment.
- rebase, invert inlining reporting chain, update diagnostic text
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D141451/new/
https://reviews.llvm.org/D141451
Files:
clang/include/clang/Basic/DiagnosticFrontendKinds.td
clang/lib/CodeGen/CodeGenAction.cpp
clang/test/Frontend/backend-attribute-error-warning-optimize.c
clang/test/Frontend/backend-attribute-error-warning.c
clang/test/Frontend/backend-attribute-error-warning.cpp
llvm/docs/LangRef.rst
llvm/include/llvm/IR/DiagnosticInfo.h
llvm/lib/IR/DiagnosticInfo.cpp
llvm/lib/Transforms/Utils/InlineFunction.cpp
llvm/test/Transforms/Inline/dontcall-attributes.ll
Index: llvm/test/Transforms/Inline/dontcall-attributes.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/Inline/dontcall-attributes.ll
@@ -0,0 +1,84 @@
+; RUN: opt -S -o - -passes=inline %s \
+; RUN: | FileCheck %s --check-prefixes=CHECK-BOTH,CHECK
+; RUN: opt -S -o - -passes=always-inline %s \
+; RUN: | FileCheck %s --check-prefixes=CHECK-BOTH,CHECK-ALWAYS
+
+declare void @foo() "dontcall-warn"="oh no"
+declare void @fof() "dontcall-error"="oh no"
+
+define void @bar(i32 %x) {
+ %cmp = icmp eq i32 %x, 10
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ call void @foo()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+define void @quux() {
+ call void @bar(i32 9)
+ ret void
+}
+
+; Test that @baz's call to @foo has metadata with inlining info.
+define void @baz() {
+; CHECK-LABEL: @baz(
+; CHECK-NEXT: call void @foo(), !inlined.from !0
+;
+ call void @bar(i32 10)
+ ret void
+}
+
+; Test that @zing's call to @foo has unique metadata from @baz's call to @foo.
+define void @zing() {
+; CHECK-LABEL: @zing(
+; CHECK-NEXT: call void @foo(), !inlined.from !1
+;
+ call void @baz()
+ ret void
+}
+
+; Same test but @fof has fn attr "dontcall-error"="..." rather than
+; "dontcall-warn"="...".
+define void @a() {
+ call void @fof()
+ ret void
+}
+define void @b() {
+; CHECK-LABEL: @b(
+; CHECK-NEXT: call void @fof(), !inlined.from !3
+ call void @a()
+ ret void
+}
+
+; Add some tests for alwaysinline.
+define void @always_callee() alwaysinline {
+ call void @fof()
+ ret void
+}
+define void @always_caller() alwaysinline {
+; CHECK-BOTH-LABEL: @always_caller(
+; CHECK-NEXT: call void @fof(), !inlined.from !4
+; CHECK-ALWAYS-NEXT: call void @fof(), !inlined.from !0
+ call void @always_callee()
+ ret void
+}
+define void @always_caller2() alwaysinline {
+; CHECK-BOTH-LABEL: @always_caller2(
+; CHECK-NEXT: call void @fof(), !inlined.from !5
+; CHECK-ALWAYS-NEXT: call void @fof(), !inlined.from !1
+ call void @always_caller()
+ ret void
+}
+
+; CHECK: !0 = !{!"bar"}
+; CHECK-NEXT: !1 = !{!2}
+; CHECK-NEXT: !2 = !{!"bar", !"baz"}
+; CHECK-NEXT: !3 = !{!"a"}
+; CHECK-NEXT: !4 = !{!"always_callee"}
+; CHECK-ALWAYS: !0 = !{!"always_callee"}
+; CHECK-ALWAYS-NEXT: !1 = !{!2}
+; CHECK-ALWAYS-NEXT: !2 = !{!"always_callee", !"always_caller"}
Index: llvm/lib/Transforms/Utils/InlineFunction.cpp
===================================================================
--- llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -2395,6 +2395,19 @@
// inlining, commonly when the callee is an intrinsic.
if (MarkNoUnwind && !CI->doesNotThrow())
CI->setDoesNotThrow();
+
+ const Function *Callee = CI->getCalledFunction();
+ if (Callee && (Callee->hasFnAttribute("dontcall-error") ||
+ Callee->hasFnAttribute("dontcall-warn"))) {
+ Metadata *MD = MDString::get(CI->getContext(), CalledFunc->getName());
+ if (MDNode *N = CI->getMetadata("inlined.from")) {
+ TempMDTuple Temp = cast<MDTuple>(N)->clone();
+ Temp->push_back(MD);
+ MD = MDNode::replaceWithUniqued(std::move(Temp));
+ }
+ MDTuple *MDT = MDNode::get(CI->getContext(), {MD});
+ CI->setMetadata("inlined.from", MDT);
+ }
}
}
}
Index: llvm/lib/IR/DiagnosticInfo.cpp
===================================================================
--- llvm/lib/IR/DiagnosticInfo.cpp
+++ llvm/lib/IR/DiagnosticInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
@@ -433,8 +434,9 @@
if (MDNode *MD = CI.getMetadata("srcloc"))
LocCookie =
mdconst::extract<ConstantInt>(MD->getOperand(0))->getZExtValue();
- DiagnosticInfoDontCall D(F->getName(), A.getValueAsString(), Sev,
- LocCookie);
+ DiagnosticInfoDontCall D(CI.getParent()->getParent()->getName(),
+ F->getName(), A.getValueAsString(), Sev,
+ LocCookie, CI.getMetadata("inlined.from"));
F->getContext().diagnose(D);
}
}
@@ -450,3 +452,20 @@
if (!getNote().empty())
DP << ": " << getNote();
}
+
+void DiagnosticInfoDontCall::getInliningDecisions(
+ SmallVectorImpl<std::string> &InliningDecisions) const {
+ if (!MDN)
+ return;
+
+ const MDOperand &MO = MDN->getOperand(0);
+ if (auto *MDT = dyn_cast<MDTuple>(MO)) {
+ for (const MDOperand &MO : MDT->operands()) {
+ if (auto *S = dyn_cast<MDString>(MO)) {
+ InliningDecisions.push_back(S->getString().str());
+ }
+ }
+ } else if (auto *S = dyn_cast<MDString>(MO)) {
+ InliningDecisions.push_back(S->getString().str());
+ }
+}
Index: llvm/include/llvm/IR/DiagnosticInfo.h
===================================================================
--- llvm/include/llvm/IR/DiagnosticInfo.h
+++ llvm/include/llvm/IR/DiagnosticInfo.h
@@ -1099,15 +1099,19 @@
void diagnoseDontCall(const CallInst &CI);
class DiagnosticInfoDontCall : public DiagnosticInfo {
+ StringRef CallerName;
StringRef CalleeName;
StringRef Note;
unsigned LocCookie;
+ MDNode *MDN;
public:
- DiagnosticInfoDontCall(StringRef CalleeName, StringRef Note,
- DiagnosticSeverity DS, unsigned LocCookie)
- : DiagnosticInfo(DK_DontCall, DS), CalleeName(CalleeName), Note(Note),
- LocCookie(LocCookie) {}
+ DiagnosticInfoDontCall(StringRef CallerName, StringRef CalleeName,
+ StringRef Note, DiagnosticSeverity DS,
+ unsigned LocCookie, MDNode *MDN)
+ : DiagnosticInfo(DK_DontCall, DS), CallerName(CallerName),
+ CalleeName(CalleeName), Note(Note), LocCookie(LocCookie), MDN(MDN) {}
+ StringRef getCaller() const { return CallerName; }
StringRef getFunctionName() const { return CalleeName; }
StringRef getNote() const { return Note; }
unsigned getLocCookie() const { return LocCookie; }
@@ -1115,6 +1119,8 @@
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_DontCall;
}
+ void
+ getInliningDecisions(SmallVectorImpl<std::string> &InliningDecisions) const;
};
} // end namespace llvm
Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -1774,13 +1774,17 @@
call of a function with this attribute is not eliminated via optimization.
Front ends can provide optional ``srcloc`` metadata nodes on call sites of
such callees to attach information about where in the source language such a
- call came from. A string value can be provided as a note.
+ call came from. A string value can be provided as a note. The optimizer may
+ add the optional ``inlined.from`` metadata to call sites which front ends
+ might consume to display more precise diagnostics.
``"dontcall-warn"``
This attribute denotes that a warning diagnostic should be emitted when a
call of a function with this attribute is not eliminated via optimization.
Front ends can provide optional ``srcloc`` metadata nodes on call sites of
such callees to attach information about where in the source language such a
- call came from. A string value can be provided as a note.
+ call came from. A string value can be provided as a note. The optimizer may
+ add the optional ``inlined.from`` metadata to call sites which front ends
+ might consume to display more precise diagnostics.
``fn_ret_thunk_extern``
This attribute tells the code generator that returns from functions should
be replaced with jumps to externally-defined architecture-specific symbols.
Index: clang/test/Frontend/backend-attribute-error-warning.cpp
===================================================================
--- clang/test/Frontend/backend-attribute-error-warning.cpp
+++ clang/test/Frontend/backend-attribute-error-warning.cpp
@@ -24,13 +24,19 @@
void baz(void) {
foo(); // expected-error {{call to 'foo()' declared with 'error' attribute: oh no foo}}
+ // expected-note@* {{called by function 'baz()'}}
if (x())
bar(); // expected-error {{call to 'bar()' declared with 'error' attribute: oh no bar}}
+ // expected-note@* {{called by function 'baz()'}}
quux(); // enabled-warning {{call to 'quux()' declared with 'warning' attribute: oh no quux}}
+ // enabled-note@* {{called by function 'baz()'}}
__compiletime_assert_455(); // expected-error {{call to '__compiletime_assert_455()' declared with 'error' attribute: demangle me}}
+ // expected-note@* {{called by function 'baz()'}}
duplicate_errors(); // expected-error {{call to 'duplicate_errors()' declared with 'error' attribute: two}}
+ // expected-note@* {{called by function 'baz()'}}
duplicate_warnings(); // enabled-warning {{call to 'duplicate_warnings()' declared with 'warning' attribute: two}}
+ // enabled-note@* {{called by function 'baz()'}}
}
#ifdef __cplusplus
@@ -46,15 +52,21 @@
void baz_cpp(void) {
foo(); // expected-error {{call to 'foo()' declared with 'error' attribute: oh no foo}}
+ // expected-note@* {{called by function 'baz_cpp()'}}
if (x())
bar(); // expected-error {{call to 'bar()' declared with 'error' attribute: oh no bar}}
+ // expected-note@* {{called by function 'baz_cpp()'}}
quux(); // enabled-warning {{call to 'quux()' declared with 'warning' attribute: oh no quux}}
+ // enabled-note@* {{called by function 'baz_cpp()'}}
// Test that we demangle correctly in the diagnostic for C++.
__compiletime_assert_455(); // expected-error {{call to '__compiletime_assert_455()' declared with 'error' attribute: demangle me}}
+ // expected-note@* {{called by function 'baz_cpp()'}}
nocall<int>(42); // expected-error {{call to 'int nocall<int>(int)' declared with 'error' attribute: demangle me, too}}
+ // expected-note@* {{called by function 'baz_cpp()'}}
Widget W;
int w = W; // enabled-warning {{call to 'Widget::operator int()' declared with 'warning' attribute: don't call me!}}
+ // enabled-note@* {{called by function 'baz_cpp()'}}
}
#endif
Index: clang/test/Frontend/backend-attribute-error-warning.c
===================================================================
--- clang/test/Frontend/backend-attribute-error-warning.c
+++ clang/test/Frontend/backend-attribute-error-warning.c
@@ -23,11 +23,17 @@
void baz(void) {
foo(); // expected-error {{call to 'foo' declared with 'error' attribute: oh no foo}}
+ // expected-note@* {{called by function 'baz'}}
if (x())
bar(); // expected-error {{call to 'bar' declared with 'error' attribute: oh no bar}}
+ // expected-note@* {{called by function 'baz'}}
quux(); // enabled-warning {{call to 'quux' declared with 'warning' attribute: oh no quux}}
+ // enabled-note@* {{called by function 'baz'}}
__compiletime_assert_455(); // expected-error {{call to '__compiletime_assert_455' declared with 'error' attribute: demangle me}}
+ // expected-note@* {{called by function 'baz'}}
duplicate_errors(); // expected-error {{call to 'duplicate_errors' declared with 'error' attribute: two}}
+ // expected-note@* {{called by function 'baz'}}
duplicate_warnings(); // enabled-warning {{call to 'duplicate_warnings' declared with 'warning' attribute: two}}
+ // enabled-note@* {{called by function 'baz'}}
}
Index: clang/test/Frontend/backend-attribute-error-warning-optimize.c
===================================================================
--- clang/test/Frontend/backend-attribute-error-warning-optimize.c
+++ clang/test/Frontend/backend-attribute-error-warning-optimize.c
@@ -9,6 +9,7 @@
}
void baz(void) {
foo(); // expected-error {{call to 'foo' declared with 'error' attribute: oh no foo}}
+ // expected-note@* {{called by function 'baz'}}
if (x())
bar();
}
@@ -20,3 +21,23 @@
quux = foo;
quux();
}
+
+static inline void a(int x) {
+ if (x == 10)
+ foo(); // expected-error {{call to 'foo' declared with 'error' attribute: oh no foo}}
+ // expected-note@* {{called by function 'a'}}
+ // expected-note@* {{inlined by function 'b'}}
+ // expected-note@* {{inlined by function 'd'}}
+}
+
+static inline void b() {
+ a(10);
+}
+
+void c() {
+ a(9);
+}
+
+void d() {
+ b();
+}
Index: clang/lib/CodeGen/CodeGenAction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenAction.cpp
+++ clang/lib/CodeGen/CodeGenAction.cpp
@@ -50,6 +50,8 @@
#include <memory>
#include <optional>
+#include <string>
+
using namespace clang;
using namespace llvm;
@@ -854,6 +856,17 @@
? diag::err_fe_backend_error_attr
: diag::warn_fe_backend_warning_attr)
<< llvm::demangle(D.getFunctionName().str()) << D.getNote();
+
+ SmallVector<std::string, 4> InliningDecisions;
+ D.getInliningDecisions(InliningDecisions);
+ InliningDecisions.push_back(D.getCaller().str());
+ for (size_t i = 0, e = InliningDecisions.size(); i != e; ++i) {
+ std::string S = llvm::demangle(InliningDecisions[i]);
+ if (i == 0)
+ Diags.Report(diag::note_fe_backend_in) << S;
+ else
+ Diags.Report(diag::note_fe_backend_inlined) << S;
+ }
}
void BackendConsumer::MisExpectDiagHandler(
Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -90,6 +90,8 @@
def warn_fe_backend_warning_attr :
Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
InGroup<BackendWarningAttributes>;
+def note_fe_backend_in : Note<"called by function '%0'">;
+def note_fe_backend_inlined : Note<"inlined by function '%0'">;
def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits