parent
225353d8bb
commit
ad9a1daa81
@ -11,11 +11,11 @@
|
||||
use back::lto;
|
||||
use back::link::{get_cc_prog, remove};
|
||||
use driver::driver::{CrateTranslation, ModuleTranslation, OutputFilenames};
|
||||
use driver::config::NoDebugInfo;
|
||||
use driver::config::{NoDebugInfo, Passes, AllPasses};
|
||||
use driver::session::Session;
|
||||
use driver::config;
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
|
||||
use util::common::time;
|
||||
use syntax::abi;
|
||||
use syntax::codemap;
|
||||
@ -28,9 +28,10 @@
|
||||
use std::iter::Unfold;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::mem;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::TaskBuilder;
|
||||
use libc::{c_uint, c_int};
|
||||
use libc::{c_uint, c_int, c_void};
|
||||
|
||||
|
||||
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
@ -311,24 +312,52 @@ struct CodegenContext<'a> {
|
||||
lto_ctxt: Option<(&'a Session, &'a [String])>,
|
||||
// Handler to use for diagnostics produced during codegen.
|
||||
handler: &'a Handler,
|
||||
// LLVM optimizations for which we want to print remarks.
|
||||
remark: Passes,
|
||||
}
|
||||
|
||||
impl<'a> CodegenContext<'a> {
|
||||
fn new(handler: &'a Handler) -> CodegenContext<'a> {
|
||||
CodegenContext {
|
||||
lto_ctxt: None,
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContext<'a> {
|
||||
CodegenContext {
|
||||
lto_ctxt: Some((sess, reachable)),
|
||||
handler: sess.diagnostic().handler(),
|
||||
remark: sess.opts.cg.remark.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DiagHandlerFreeVars<'a> {
|
||||
llcx: ContextRef,
|
||||
cgcx: &'a CodegenContext<'a>,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
|
||||
let DiagHandlerFreeVars { llcx, cgcx }
|
||||
= *mem::transmute::<_, *const DiagHandlerFreeVars>(user);
|
||||
|
||||
match llvm::diagnostic::Diagnostic::unpack(info) {
|
||||
llvm::diagnostic::Optimization(opt) => {
|
||||
let pass_name = CString::new(opt.pass_name, false);
|
||||
let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM");
|
||||
let enabled = match cgcx.remark {
|
||||
AllPasses => true,
|
||||
Passes(ref v) => v.iter().any(|s| s.as_slice() == pass_name),
|
||||
};
|
||||
|
||||
if enabled {
|
||||
let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc);
|
||||
cgcx.handler.note(format!("optimization {:s} for {:s} at {:s}: {:s}",
|
||||
opt.kind.describe(),
|
||||
pass_name,
|
||||
if loc.is_empty() { "[unknown]" } else { loc.as_slice() },
|
||||
llvm::twine_to_string(opt.message)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe due to LLVM calls.
|
||||
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||
mtrans: ModuleTranslation,
|
||||
@ -338,6 +367,17 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||
let ModuleTranslation { llmod, llcx } = mtrans;
|
||||
let tm = config.tm;
|
||||
|
||||
// llcx doesn't outlive this function, so we can put this on the stack.
|
||||
let fv = DiagHandlerFreeVars {
|
||||
llcx: llcx,
|
||||
cgcx: cgcx,
|
||||
};
|
||||
if !cgcx.remark.is_empty() {
|
||||
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler,
|
||||
&fv as *const DiagHandlerFreeVars
|
||||
as *mut c_void);
|
||||
}
|
||||
|
||||
if config.emit_no_opt_bc {
|
||||
let ext = format!("{}.no-opt.bc", name_extra);
|
||||
output_names.with_extension(ext.as_slice()).with_c_str(|buf| {
|
||||
@ -785,13 +825,18 @@ fn run_work_multithreaded(sess: &Session,
|
||||
for i in range(0, num_workers) {
|
||||
let work_items_arc = work_items_arc.clone();
|
||||
let diag_emitter = diag_emitter.clone();
|
||||
let remark = sess.opts.cg.remark.clone();
|
||||
|
||||
let future = TaskBuilder::new().named(format!("codegen-{}", i)).try_future(proc() {
|
||||
let diag_handler = mk_handler(box diag_emitter);
|
||||
|
||||
// Must construct cgcx inside the proc because it has non-Send
|
||||
// fields.
|
||||
let cgcx = CodegenContext::new(&diag_handler);
|
||||
let cgcx = CodegenContext {
|
||||
lto_ctxt: None,
|
||||
handler: &diag_handler,
|
||||
remark: remark,
|
||||
};
|
||||
|
||||
loop {
|
||||
// Avoid holding the lock for the entire duration of the match.
|
||||
|
@ -235,6 +235,21 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
|
||||
--pretty flowgraph output", FLOWGRAPH_PRINT_ALL))
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum Passes {
|
||||
Passes(Vec<String>),
|
||||
AllPasses,
|
||||
}
|
||||
|
||||
impl Passes {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match *self {
|
||||
Passes(ref v) => v.is_empty(),
|
||||
AllPasses => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a macro that will define all CodegenOptions fields and parsers all
|
||||
/// at once. The goal of this macro is to define an interface that can be
|
||||
/// programmatically used by the option parser in order to initialize the struct
|
||||
@ -261,7 +276,7 @@ pub fn basic_codegen_options() -> CodegenOptions {
|
||||
&[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
|
||||
|
||||
mod cgsetters {
|
||||
use super::CodegenOptions;
|
||||
use super::{CodegenOptions, Passes, AllPasses};
|
||||
|
||||
$(
|
||||
pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
|
||||
@ -310,6 +325,24 @@ fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool {
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("all") => {
|
||||
*slot = AllPasses;
|
||||
true
|
||||
}
|
||||
v => {
|
||||
let mut passes = vec!();
|
||||
if parse_list(&mut passes, v) {
|
||||
*slot = Passes(passes);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) )
|
||||
|
||||
@ -356,6 +389,8 @@ fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool {
|
||||
"extra data to put in each output filename"),
|
||||
codegen_units: uint = (1, parse_uint,
|
||||
"divide crate into N units to optimize in parallel"),
|
||||
remark: Passes = (Passes(Vec::new()), parse_passes,
|
||||
"print remarks for these optimization passes (space separated, or \"all\")"),
|
||||
)
|
||||
|
||||
pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
|
||||
@ -744,6 +779,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
}
|
||||
let cg = build_codegen_options(matches);
|
||||
|
||||
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
|
||||
early_warn("-C remark will not show source locations without --debuginfo");
|
||||
}
|
||||
|
||||
let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
|
||||
Some("auto") => Auto,
|
||||
Some("always") => Always,
|
||||
|
92
src/librustc_llvm/diagnostic.rs
Normal file
92
src/librustc_llvm/diagnostic.rs
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! LLVM diagnostic reports.
|
||||
|
||||
use libc::c_char;
|
||||
|
||||
use {ValueRef, TwineRef, DebugLocRef, DiagnosticInfoRef};
|
||||
|
||||
pub enum OptimizationDiagnosticKind {
|
||||
OptimizationRemark,
|
||||
OptimizationMissed,
|
||||
OptimizationAnalysis,
|
||||
OptimizationFailure,
|
||||
}
|
||||
|
||||
impl OptimizationDiagnosticKind {
|
||||
pub fn describe(self) -> &'static str {
|
||||
match self {
|
||||
OptimizationRemark => "remark",
|
||||
OptimizationMissed => "missed",
|
||||
OptimizationAnalysis => "analysis",
|
||||
OptimizationFailure => "failure",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptimizationDiagnostic {
|
||||
pub kind: OptimizationDiagnosticKind,
|
||||
pub pass_name: *const c_char,
|
||||
pub function: ValueRef,
|
||||
pub debug_loc: DebugLocRef,
|
||||
pub message: TwineRef,
|
||||
}
|
||||
|
||||
impl OptimizationDiagnostic {
|
||||
unsafe fn unpack(kind: OptimizationDiagnosticKind, di: DiagnosticInfoRef)
|
||||
-> OptimizationDiagnostic {
|
||||
|
||||
let mut opt = OptimizationDiagnostic {
|
||||
kind: kind,
|
||||
pass_name: 0 as *const c_char,
|
||||
function: 0 as ValueRef,
|
||||
debug_loc: 0 as DebugLocRef,
|
||||
message: 0 as TwineRef,
|
||||
};
|
||||
|
||||
super::LLVMUnpackOptimizationDiagnostic(di,
|
||||
&mut opt.pass_name,
|
||||
&mut opt.function,
|
||||
&mut opt.debug_loc,
|
||||
&mut opt.message);
|
||||
|
||||
opt
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Diagnostic {
|
||||
Optimization(OptimizationDiagnostic),
|
||||
|
||||
/// LLVM has other types that we do not wrap here.
|
||||
UnknownDiagnostic(DiagnosticInfoRef),
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic {
|
||||
let kind = super::LLVMGetDiagInfoKind(di);
|
||||
|
||||
match kind {
|
||||
super::DK_OptimizationRemark
|
||||
=> Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)),
|
||||
|
||||
super::DK_OptimizationRemarkMissed
|
||||
=> Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)),
|
||||
|
||||
super::DK_OptimizationRemarkAnalysis
|
||||
=> Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)),
|
||||
|
||||
super::DK_OptimizationFailure
|
||||
=> Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)),
|
||||
|
||||
_ => UnknownDiagnostic(di)
|
||||
}
|
||||
}
|
||||
}
|
@ -31,13 +31,14 @@
|
||||
use std::cell::RefCell;
|
||||
use std::{raw, mem};
|
||||
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
|
||||
use libc::{c_longlong, c_ulonglong};
|
||||
use libc::{c_longlong, c_ulonglong, c_void};
|
||||
use debuginfo::{DIBuilderRef, DIDescriptor,
|
||||
DIFile, DILexicalBlock, DISubprogram, DIType,
|
||||
DIBasicType, DIDerivedType, DICompositeType,
|
||||
DIVariable, DIGlobalVariable, DIArray, DISubrange};
|
||||
|
||||
pub mod archive_ro;
|
||||
pub mod diagnostic;
|
||||
|
||||
pub type Opcode = u32;
|
||||
pub type Bool = c_uint;
|
||||
@ -81,6 +82,15 @@ pub enum Linkage {
|
||||
CommonLinkage = 14,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[deriving(Show)]
|
||||
pub enum DiagnosticSeverity {
|
||||
Error,
|
||||
Warning,
|
||||
Remark,
|
||||
Note,
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum Attribute {
|
||||
ZExtAttribute = 1 << 0,
|
||||
@ -360,6 +370,18 @@ pub enum CodeGenModel {
|
||||
CodeModelLarge = 5,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum DiagnosticKind {
|
||||
DK_InlineAsm = 0,
|
||||
DK_StackSize,
|
||||
DK_DebugMetadataVersion,
|
||||
DK_SampleProfile,
|
||||
DK_OptimizationRemark,
|
||||
DK_OptimizationRemarkMissed,
|
||||
DK_OptimizationRemarkAnalysis,
|
||||
DK_OptimizationFailure,
|
||||
}
|
||||
|
||||
// Opaque pointer types
|
||||
pub enum Module_opaque {}
|
||||
pub type ModuleRef = *mut Module_opaque;
|
||||
@ -395,6 +417,14 @@ pub enum TargetMachine_opaque {}
|
||||
pub type TargetMachineRef = *mut TargetMachine_opaque;
|
||||
pub enum Archive_opaque {}
|
||||
pub type ArchiveRef = *mut Archive_opaque;
|
||||
pub enum Twine_opaque {}
|
||||
pub type TwineRef = *mut Twine_opaque;
|
||||
pub enum DiagnosticInfo_opaque {}
|
||||
pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
|
||||
pub enum DebugLoc_opaque {}
|
||||
pub type DebugLocRef = *mut DebugLoc_opaque;
|
||||
|
||||
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
|
||||
|
||||
pub mod debuginfo {
|
||||
use super::{ValueRef};
|
||||
@ -1918,6 +1948,24 @@ pub fn LLVMRustArchiveReadSection(AR: ArchiveRef, name: *const c_char,
|
||||
|
||||
pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
|
||||
data: *mut *const c_char) -> c_int;
|
||||
|
||||
pub fn LLVMWriteTwineToString(T: TwineRef, s: RustStringRef);
|
||||
|
||||
pub fn LLVMContextSetDiagnosticHandler(C: ContextRef,
|
||||
Handler: DiagnosticHandler,
|
||||
DiagnosticContext: *mut c_void);
|
||||
|
||||
pub fn LLVMUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef,
|
||||
pass_name_out: *mut *const c_char,
|
||||
function_out: *mut ValueRef,
|
||||
debugloc_out: *mut DebugLocRef,
|
||||
message_out: *mut TwineRef);
|
||||
|
||||
pub fn LLVMWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, s: RustStringRef);
|
||||
pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity;
|
||||
pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
|
||||
|
||||
pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef);
|
||||
}
|
||||
|
||||
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
|
||||
@ -2072,6 +2120,16 @@ pub fn build_string(f: |RustStringRef|) -> Option<String> {
|
||||
String::from_utf8(buf.unwrap()).ok()
|
||||
}
|
||||
|
||||
pub unsafe fn twine_to_string(tr: TwineRef) -> String {
|
||||
build_string(|s| LLVMWriteTwineToString(tr, s))
|
||||
.expect("got a non-UTF8 Twine from LLVM")
|
||||
}
|
||||
|
||||
pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String {
|
||||
build_string(|s| LLVMWriteDebugLocToString(c, tr, s))
|
||||
.expect("got a non-UTF8 DebugLoc from LLVM")
|
||||
}
|
||||
|
||||
// FIXME #15460 - create a public function that actually calls our
|
||||
// static LLVM symbols. Otherwise the linker will just throw llvm
|
||||
// away. We're just calling lots of stuff until we transitively get
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "rustllvm.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
|
||||
#if LLVM_VERSION_MINOR >= 5
|
||||
#include "llvm/IR/CallSite.h"
|
||||
@ -823,3 +825,49 @@ extern "C" LLVMTypeRef
|
||||
LLVMRustArrayType(LLVMTypeRef ElementType, uint64_t ElementCount) {
|
||||
return wrap(ArrayType::get(unwrap(ElementType), ElementCount));
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DebugLoc, LLVMDebugLocRef)
|
||||
|
||||
extern "C" void
|
||||
LLVMWriteTwineToString(LLVMTwineRef T, RustStringRef str) {
|
||||
raw_rust_string_ostream os(str);
|
||||
unwrap(T)->print(os);
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
LLVMUnpackOptimizationDiagnostic(
|
||||
LLVMDiagnosticInfoRef di,
|
||||
const char **pass_name_out,
|
||||
LLVMValueRef *function_out,
|
||||
LLVMDebugLocRef *debugloc_out,
|
||||
LLVMTwineRef *message_out)
|
||||
{
|
||||
// Undefined to call this not on an optimization diagnostic!
|
||||
llvm::DiagnosticInfoOptimizationBase *opt
|
||||
= static_cast<llvm::DiagnosticInfoOptimizationBase*>(unwrap(di));
|
||||
|
||||
*pass_name_out = opt->getPassName();
|
||||
*function_out = wrap(&opt->getFunction());
|
||||
*debugloc_out = wrap(&opt->getDebugLoc());
|
||||
*message_out = wrap(&opt->getMsg());
|
||||
}
|
||||
|
||||
extern "C" void LLVMWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) {
|
||||
raw_rust_string_ostream os(str);
|
||||
DiagnosticPrinterRawOStream dp(os);
|
||||
unwrap(di)->print(dp);
|
||||
}
|
||||
|
||||
extern "C" int LLVMGetDiagInfoKind(LLVMDiagnosticInfoRef di) {
|
||||
return unwrap(di)->getKind();
|
||||
}
|
||||
|
||||
extern "C" void LLVMWriteDebugLocToString(
|
||||
LLVMContextRef C,
|
||||
LLVMDebugLocRef dl,
|
||||
RustStringRef str)
|
||||
{
|
||||
raw_rust_string_ostream os(str);
|
||||
unwrap(dl)->print(*unwrap(C), os);
|
||||
}
|
||||
|
@ -71,6 +71,8 @@
|
||||
void LLVMRustSetLastError(const char*);
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
|
||||
typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;
|
||||
|
||||
extern "C" void
|
||||
rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
|
||||
|
Loading…
Reference in New Issue
Block a user