Skip to content

Commit 6846674

Browse files
committed
Emit LLVM optimization remarks when enabled with -Cremark
The default diagnostic handler considers all remarks to be disabled by default unless configured otherwise through LLVM internal flags: `-pass-remarks`, `-pass-remarks-missed`, and `-pass-remarks-analysis`. This behaviour makes `-Cremark` ineffective on its own. Fix this by configuring a custom diagnostic handler that enables optimization remarks based on the value of `-Cremark` option. With `-Cremark=all` enabling all remarks.
1 parent b16ac4c commit 6846674

File tree

4 files changed

+158
-12
lines changed

4 files changed

+158
-12
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ pub(crate) fn save_temp_bitcode(
259259
pub struct DiagnosticHandlers<'a> {
260260
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
261261
llcx: &'a llvm::Context,
262+
old_handler: Option<&'a llvm::DiagnosticHandler>,
262263
}
263264

264265
impl<'a> DiagnosticHandlers<'a> {
@@ -267,12 +268,35 @@ impl<'a> DiagnosticHandlers<'a> {
267268
handler: &'a Handler,
268269
llcx: &'a llvm::Context,
269270
) -> Self {
271+
let remark_passes_all: bool;
272+
let remark_passes: Vec<CString>;
273+
match &cgcx.remark {
274+
Passes::All => {
275+
remark_passes_all = true;
276+
remark_passes = Vec::new();
277+
}
278+
Passes::Some(passes) => {
279+
remark_passes_all = false;
280+
remark_passes =
281+
passes.iter().map(|name| CString::new(name.as_str()).unwrap()).collect();
282+
}
283+
};
284+
let remark_passes: Vec<*const c_char> =
285+
remark_passes.iter().map(|name: &CString| name.as_ptr()).collect();
270286
let data = Box::into_raw(Box::new((cgcx, handler)));
271287
unsafe {
288+
let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
289+
llvm::LLVMRustContextConfigureDiagnosticHandler(
290+
llcx,
291+
diagnostic_handler,
292+
data.cast(),
293+
remark_passes_all,
294+
remark_passes.as_ptr(),
295+
remark_passes.len(),
296+
);
272297
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
273-
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
298+
DiagnosticHandlers { data, llcx, old_handler }
274299
}
275-
DiagnosticHandlers { data, llcx }
276300
}
277301
}
278302

@@ -281,7 +305,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> {
281305
use std::ptr::null_mut;
282306
unsafe {
283307
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
284-
llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
308+
llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler);
285309
drop(Box::from_raw(self.data));
286310
}
287311
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -672,8 +672,12 @@ pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
672672
#[repr(C)]
673673
pub struct Linker<'a>(InvariantOpaque<'a>);
674674

675-
pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
676-
pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
675+
extern "C" {
676+
pub type DiagnosticHandler;
677+
}
678+
679+
pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
680+
pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
677681

678682
pub mod coverageinfo {
679683
use super::coverage_map;
@@ -2286,12 +2290,6 @@ extern "C" {
22862290
#[allow(improper_ctypes)]
22872291
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
22882292

2289-
pub fn LLVMContextSetDiagnosticHandler(
2290-
C: &Context,
2291-
Handler: DiagnosticHandler,
2292-
DiagnosticContext: *mut c_void,
2293-
);
2294-
22952293
#[allow(improper_ctypes)]
22962294
pub fn LLVMRustUnpackOptimizationDiagnostic(
22972295
DI: &'a DiagnosticInfo,
@@ -2321,7 +2319,7 @@ extern "C" {
23212319

23222320
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
23232321
C: &Context,
2324-
H: InlineAsmDiagHandler,
2322+
H: InlineAsmDiagHandlerTy,
23252323
CX: *mut c_void,
23262324
);
23272325

@@ -2436,4 +2434,19 @@ extern "C" {
24362434
mod_id: *const c_char,
24372435
data: &ThinLTOData,
24382436
);
2437+
2438+
pub fn LLVMRustContextGetDiagnosticHandler(Context: &Context) -> Option<&DiagnosticHandler>;
2439+
pub fn LLVMRustContextSetDiagnosticHandler(
2440+
context: &Context,
2441+
diagnostic_handler: Option<&DiagnosticHandler>,
2442+
);
2443+
pub fn LLVMRustContextConfigureDiagnosticHandler(
2444+
context: &Context,
2445+
diagnostic_handler_callback: DiagnosticHandlerTy,
2446+
diagnostic_handler_context: *mut c_void,
2447+
remark_all_passes: bool,
2448+
remark_passes: *const *const c_char,
2449+
remark_passes_len: usize,
2450+
);
2451+
24392452
}

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+90
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "LLVMWrapper.h"
22
#include "llvm/IR/DebugInfoMetadata.h"
3+
#include "llvm/IR/DiagnosticHandler.h"
34
#include "llvm/IR/DiagnosticInfo.h"
45
#include "llvm/IR/DiagnosticPrinter.h"
56
#include "llvm/IR/GlobalVariable.h"
@@ -1767,3 +1768,92 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
17671768
return LLVMRustResult::Success;
17681769
}
17691770
}
1771+
1772+
// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
1773+
extern "C" DiagnosticHandler *
1774+
LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
1775+
std::unique_ptr<DiagnosticHandler> DH = unwrap(C)->getDiagnosticHandler();
1776+
return DH.release();
1777+
}
1778+
1779+
// Sets unique_ptr to object of DiagnosticHandler to provide custom diagnostic
1780+
// handling. Ownership of the handler is moved to the LLVMContext.
1781+
extern "C" void LLVMRustContextSetDiagnosticHandler(LLVMContextRef C,
1782+
DiagnosticHandler *DH) {
1783+
unwrap(C)->setDiagnosticHandler(std::unique_ptr<DiagnosticHandler>(DH));
1784+
}
1785+
1786+
using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
1787+
1788+
// Configures a diagnostic handler that invokes provided callback when a
1789+
// backend needs to emit a diagnostic.
1790+
//
1791+
// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
1792+
// the RemarkPasses array specifies individual passes for which remarks will be
1793+
// enabled.
1794+
extern "C" void LLVMRustContextConfigureDiagnosticHandler(
1795+
LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
1796+
void *DiagnosticHandlerContext, bool RemarkAllPasses,
1797+
const char * const * RemarkPasses, size_t RemarkPassesLen) {
1798+
1799+
class RustDiagnosticHandler final : public DiagnosticHandler {
1800+
public:
1801+
RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
1802+
void *DiagnosticHandlerContext,
1803+
bool RemarkAllPasses,
1804+
std::vector<std::string> RemarkPasses)
1805+
: DiagnosticHandlerCallback(DiagnosticHandlerCallback),
1806+
DiagnosticHandlerContext(DiagnosticHandlerContext),
1807+
RemarkAllPasses(RemarkAllPasses),
1808+
RemarkPasses(RemarkPasses) {}
1809+
1810+
virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
1811+
if (DiagnosticHandlerCallback) {
1812+
DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
1813+
return true;
1814+
}
1815+
return false;
1816+
}
1817+
1818+
bool isAnalysisRemarkEnabled(StringRef PassName) const override {
1819+
return isRemarkEnabled(PassName);
1820+
}
1821+
1822+
bool isMissedOptRemarkEnabled(StringRef PassName) const override {
1823+
return isRemarkEnabled(PassName);
1824+
}
1825+
1826+
bool isPassedOptRemarkEnabled(StringRef PassName) const override {
1827+
return isRemarkEnabled(PassName);
1828+
}
1829+
1830+
bool isAnyRemarkEnabled() const override {
1831+
return RemarkAllPasses || !RemarkPasses.empty();
1832+
}
1833+
1834+
private:
1835+
bool isRemarkEnabled(StringRef PassName) const {
1836+
if (RemarkAllPasses)
1837+
return true;
1838+
1839+
for (auto &Pass : RemarkPasses)
1840+
if (Pass == PassName)
1841+
return true;
1842+
1843+
return false;
1844+
}
1845+
1846+
LLVMDiagnosticHandlerTy DiagnosticHandlerCallback = nullptr;
1847+
void *DiagnosticHandlerContext = nullptr;
1848+
1849+
bool RemarkAllPasses = false;
1850+
std::vector<std::string> RemarkPasses;
1851+
};
1852+
1853+
std::vector<std::string> Passes;
1854+
for (size_t I = 0; I != RemarkPassesLen; ++I)
1855+
Passes.push_back(RemarkPasses[I]);
1856+
1857+
unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
1858+
DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
1859+
}

src/test/ui/optimization-remark.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// build-pass
2+
// ignore-pass
3+
// no-system-llvm
4+
// revisions: all inline
5+
// compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
6+
// [all] compile-flags: -Cremark=all
7+
// [inline] compile-flags: -Cremark=inline
8+
// error-pattern: inline: f not inlined into g
9+
// dont-check-compiler-stderr
10+
11+
#[no_mangle]
12+
#[inline(never)]
13+
pub fn f() {
14+
}
15+
16+
#[no_mangle]
17+
pub fn g() {
18+
f();
19+
}

0 commit comments

Comments
 (0)