Skip to content

Commit 67762ff

Browse files
authored
Rollup merge of #90833 - tmiasko:optimization-remarks, r=nikic
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. Fixes #90924. r? `@nikic`
2 parents 9ef0bcf + 8fa4529 commit 67762ff

File tree

4 files changed

+163
-19
lines changed

4 files changed

+163
-19
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+29-10
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
}
@@ -337,13 +361,8 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
337361

338362
if enabled {
339363
diag_handler.note_without_error(&format!(
340-
"optimization {} for {} at {}:{}:{}: {}",
341-
opt.kind.describe(),
342-
opt.pass_name,
343-
opt.filename,
344-
opt.line,
345-
opt.column,
346-
opt.message
364+
"{}:{}:{}: {}: {}",
365+
opt.filename, opt.line, opt.column, opt.pass_name, opt.message,
347366
));
348367
}
349368
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,12 @@ pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
675675
#[repr(C)]
676676
pub struct Linker<'a>(InvariantOpaque<'a>);
677677

678-
pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
679-
pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
678+
extern "C" {
679+
pub type DiagnosticHandler;
680+
}
681+
682+
pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
683+
pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
680684

681685
pub mod coverageinfo {
682686
use super::coverage_map;
@@ -2289,12 +2293,6 @@ extern "C" {
22892293
#[allow(improper_ctypes)]
22902294
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
22912295

2292-
pub fn LLVMContextSetDiagnosticHandler(
2293-
C: &Context,
2294-
Handler: DiagnosticHandler,
2295-
DiagnosticContext: *mut c_void,
2296-
);
2297-
22982296
#[allow(improper_ctypes)]
22992297
pub fn LLVMRustUnpackOptimizationDiagnostic(
23002298
DI: &'a DiagnosticInfo,
@@ -2324,7 +2322,7 @@ extern "C" {
23242322

23252323
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
23262324
C: &Context,
2327-
H: InlineAsmDiagHandler,
2325+
H: InlineAsmDiagHandlerTy,
23282326
CX: *mut c_void,
23292327
);
23302328

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

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+93
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"
@@ -1177,10 +1178,13 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
11771178
case DK_SampleProfile:
11781179
return LLVMRustDiagnosticKind::SampleProfile;
11791180
case DK_OptimizationRemark:
1181+
case DK_MachineOptimizationRemark:
11801182
return LLVMRustDiagnosticKind::OptimizationRemark;
11811183
case DK_OptimizationRemarkMissed:
1184+
case DK_MachineOptimizationRemarkMissed:
11821185
return LLVMRustDiagnosticKind::OptimizationRemarkMissed;
11831186
case DK_OptimizationRemarkAnalysis:
1187+
case DK_MachineOptimizationRemarkAnalysis:
11841188
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis;
11851189
case DK_OptimizationRemarkAnalysisFPCommute:
11861190
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute;
@@ -1783,3 +1787,92 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
17831787
return LLVMRustResult::Success;
17841788
}
17851789
}
1790+
1791+
// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
1792+
extern "C" DiagnosticHandler *
1793+
LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
1794+
std::unique_ptr<DiagnosticHandler> DH = unwrap(C)->getDiagnosticHandler();
1795+
return DH.release();
1796+
}
1797+
1798+
// Sets unique_ptr to object of DiagnosticHandler to provide custom diagnostic
1799+
// handling. Ownership of the handler is moved to the LLVMContext.
1800+
extern "C" void LLVMRustContextSetDiagnosticHandler(LLVMContextRef C,
1801+
DiagnosticHandler *DH) {
1802+
unwrap(C)->setDiagnosticHandler(std::unique_ptr<DiagnosticHandler>(DH));
1803+
}
1804+
1805+
using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
1806+
1807+
// Configures a diagnostic handler that invokes provided callback when a
1808+
// backend needs to emit a diagnostic.
1809+
//
1810+
// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
1811+
// the RemarkPasses array specifies individual passes for which remarks will be
1812+
// enabled.
1813+
extern "C" void LLVMRustContextConfigureDiagnosticHandler(
1814+
LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
1815+
void *DiagnosticHandlerContext, bool RemarkAllPasses,
1816+
const char * const * RemarkPasses, size_t RemarkPassesLen) {
1817+
1818+
class RustDiagnosticHandler final : public DiagnosticHandler {
1819+
public:
1820+
RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
1821+
void *DiagnosticHandlerContext,
1822+
bool RemarkAllPasses,
1823+
std::vector<std::string> RemarkPasses)
1824+
: DiagnosticHandlerCallback(DiagnosticHandlerCallback),
1825+
DiagnosticHandlerContext(DiagnosticHandlerContext),
1826+
RemarkAllPasses(RemarkAllPasses),
1827+
RemarkPasses(RemarkPasses) {}
1828+
1829+
virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
1830+
if (DiagnosticHandlerCallback) {
1831+
DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
1832+
return true;
1833+
}
1834+
return false;
1835+
}
1836+
1837+
bool isAnalysisRemarkEnabled(StringRef PassName) const override {
1838+
return isRemarkEnabled(PassName);
1839+
}
1840+
1841+
bool isMissedOptRemarkEnabled(StringRef PassName) const override {
1842+
return isRemarkEnabled(PassName);
1843+
}
1844+
1845+
bool isPassedOptRemarkEnabled(StringRef PassName) const override {
1846+
return isRemarkEnabled(PassName);
1847+
}
1848+
1849+
bool isAnyRemarkEnabled() const override {
1850+
return RemarkAllPasses || !RemarkPasses.empty();
1851+
}
1852+
1853+
private:
1854+
bool isRemarkEnabled(StringRef PassName) const {
1855+
if (RemarkAllPasses)
1856+
return true;
1857+
1858+
for (auto &Pass : RemarkPasses)
1859+
if (Pass == PassName)
1860+
return true;
1861+
1862+
return false;
1863+
}
1864+
1865+
LLVMDiagnosticHandlerTy DiagnosticHandlerCallback = nullptr;
1866+
void *DiagnosticHandlerContext = nullptr;
1867+
1868+
bool RemarkAllPasses = false;
1869+
std::vector<std::string> RemarkPasses;
1870+
};
1871+
1872+
std::vector<std::string> Passes;
1873+
for (size_t I = 0; I != RemarkPassesLen; ++I)
1874+
Passes.push_back(RemarkPasses[I]);
1875+
1876+
unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
1877+
DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
1878+
}

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)