Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to LLVM 13 #87570

Merged
merged 12 commits into from
Aug 21, 2021
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
branch = rustc/12.0-2021-07-10
branch = rustc/13.0-2021-08-08
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
url = https://github.com/rust-embedded/book.git
Expand Down
43 changes: 3 additions & 40 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,39 +296,8 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void
}
let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));

// Recover the post-substitution assembly code from LLVM for better
// diagnostics.
let mut have_source = false;
let mut buffer = String::new();
let mut level = llvm::DiagnosticLevel::Error;
let mut loc = 0;
let mut ranges = [0; 8];
let mut num_ranges = ranges.len() / 2;
let msg = llvm::build_string(|msg| {
buffer = llvm::build_string(|buffer| {
have_source = llvm::LLVMRustUnpackSMDiagnostic(
diag,
msg,
buffer,
&mut level,
&mut loc,
ranges.as_mut_ptr(),
&mut num_ranges,
);
})
.expect("non-UTF8 inline asm");
})
.expect("non-UTF8 SMDiagnostic");

let source = have_source.then(|| {
let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
for i in 0..num_ranges {
spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
}
(buffer, spans)
});

report_inline_asm(cgcx, msg, level, cookie, source);
let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag);
report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source);
}

unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
Expand All @@ -339,13 +308,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void

match llvm::diagnostic::Diagnostic::unpack(info) {
llvm::diagnostic::InlineAsm(inline) => {
report_inline_asm(
cgcx,
llvm::twine_to_string(inline.message),
inline.level,
inline.cookie,
None,
);
report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
}

llvm::diagnostic::Optimization(opt) => {
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,18 @@ pub fn compile_codegen_unit(
}

// Finalize code coverage by injecting the coverage map. Note, the coverage map will
// also be added to the `llvm.used` variable, created next.
// also be added to the `llvm.compiler.used` variable, created next.
if cx.sess().instrument_coverage() {
cx.coverageinfo_finalize();
}

// Create the llvm.used variable
// This variable has type [N x i8*] and is stored in the llvm.metadata section
// Create the llvm.used and llvm.compiler.used variables.
if !cx.used_statics().borrow().is_empty() {
cx.create_used_variable()
}
if !cx.compiler_used_statics().borrow().is_empty() {
cx.create_compiler_used_variable()
}

// Finalize debuginfo
if cx.sess().opts.debuginfo != DebugInfo::None {
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,13 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
}

if attrs.flags.contains(CodegenFnAttrFlags::USED) {
self.add_used_global(g);
// The semantics of #[used] in Rust only require the symbol to make it into the
// object file. It is explicitly allowed for the linker to strip the symbol if it
// is dead. As such, use llvm.compiler.used instead of llvm.used.
// Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
// sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
// in some versions of the gold linker.
self.add_compiler_used_global(g);
}
}
}
Expand All @@ -484,4 +490,11 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
self.used_statics.borrow_mut().push(cast);
}

/// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
/// an array of i8*.
fn add_compiler_used_global(&self, global: &'ll Value) {
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
self.compiler_used_statics.borrow_mut().push(cast);
}
}
55 changes: 40 additions & 15 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ pub struct CodegenCx<'ll, 'tcx> {
/// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
pub used_statics: RefCell<Vec<&'ll Value>>,

/// Statics that will be placed in the llvm.compiler.used variable
/// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
pub compiler_used_statics: RefCell<Vec<&'ll Value>>,

/// Mapping of non-scalar types to llvm types and field remapping if needed.
pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,

Expand Down Expand Up @@ -115,10 +119,6 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
}
}

fn strip_powerpc64_vectors(data_layout: String) -> String {
data_layout.replace("-v256:256:256-v512:512:512", "")
}

pub unsafe fn create_module(
tcx: TyCtxt<'_>,
llcx: &'ll llvm::Context,
Expand All @@ -130,7 +130,18 @@ pub unsafe fn create_module(

let mut target_data_layout = sess.target.data_layout.clone();
if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
target_data_layout = strip_powerpc64_vectors(target_data_layout);
target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
}
if llvm_util::get_version() < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
}
if sess.target.arch == "wasm32" {
target_data_layout = "e-m:e-p:32:32-i64:64-n32:64-S128".to_string();
}
if sess.target.arch == "wasm64" {
target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pretty poor, if we're resorting to doing this we might as well not include the data layout to the target definition at all.

Out of scope for this PR regardless, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the reason the target data layout exist is that rustc needs the information itself for layout calculation and some other things.

But we don't need all the information -- only the parts parsed into TargetDataLayout. So possibly what we could do is reduce the data layout info in targets to just the necessary information, and then only check that this is consistent with the LLVM data layout (but then use the more precise LLVM data layout for code generation).

In these two cases, the newly added information is stack alignment and non-integral address spaces, both of which we don't care about.


// Ensure the data-layout values hardcoded remain the defaults.
Expand Down Expand Up @@ -318,6 +329,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
const_globals: Default::default(),
statics_to_rauw: RefCell::new(Vec::new()),
used_statics: RefCell::new(Vec::new()),
compiler_used_statics: RefCell::new(Vec::new()),
type_lowering: Default::default(),
scalar_lltypes: Default::default(),
pointee_infos: Default::default(),
Expand All @@ -340,6 +352,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
self.coverage_cx.as_ref()
}

fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
let section = cstr!("llvm.metadata");
let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);

unsafe {
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
llvm::LLVMSetInitializer(g, array);
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
llvm::LLVMSetSection(g, section.as_ptr());
}
}
}

impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
Expand Down Expand Up @@ -430,6 +454,10 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
&self.used_statics
}

fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
&self.compiler_used_statics
}

fn set_frame_pointer_type(&self, llfn: &'ll Value) {
attributes::set_frame_pointer_type(self, llfn)
}
Expand All @@ -440,17 +468,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}

fn create_used_variable(&self) {
let name = cstr!("llvm.used");
let section = cstr!("llvm.metadata");
let array =
self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
}

unsafe {
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
llvm::LLVMSetInitializer(g, array);
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
llvm::LLVMSetSection(g, section.as_ptr());
}
fn create_compiler_used_variable(&self) {
self.create_used_variable_impl(
cstr!("llvm.compiler.used"),
&*self.compiler_used_statics.borrow(),
);
}

fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ impl ModuleLlvm {
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
}
}
}
94 changes: 76 additions & 18 deletions compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ pub use self::OptimizationDiagnosticKind::*;
use crate::value::Value;
use libc::c_uint;

use super::{DiagnosticInfo, Twine};
use super::{DiagnosticInfo, SMDiagnostic};
use rustc_span::InnerSpan;

#[derive(Copy, Clone)]
pub enum OptimizationDiagnosticKind {
Expand Down Expand Up @@ -86,36 +87,91 @@ impl OptimizationDiagnostic<'ll> {
}
}

#[derive(Copy, Clone)]
pub struct InlineAsmDiagnostic<'ll> {
pub struct SrcMgrDiagnostic {
pub level: super::DiagnosticLevel,
pub message: String,
pub source: Option<(String, Vec<InnerSpan>)>,
}

impl SrcMgrDiagnostic {
pub unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic {
// Recover the post-substitution assembly code from LLVM for better
// diagnostics.
let mut have_source = false;
let mut buffer = String::new();
let mut level = super::DiagnosticLevel::Error;
let mut loc = 0;
let mut ranges = [0; 8];
let mut num_ranges = ranges.len() / 2;
let message = super::build_string(|message| {
buffer = super::build_string(|buffer| {
have_source = super::LLVMRustUnpackSMDiagnostic(
diag,
message,
buffer,
&mut level,
&mut loc,
ranges.as_mut_ptr(),
&mut num_ranges,
);
})
.expect("non-UTF8 inline asm");
})
.expect("non-UTF8 SMDiagnostic");

SrcMgrDiagnostic {
message,
level,
source: have_source.then(|| {
let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
for i in 0..num_ranges {
spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
}
(buffer, spans)
}),
}
}
}

#[derive(Clone)]
pub struct InlineAsmDiagnostic {
pub level: super::DiagnosticLevel,
pub cookie: c_uint,
pub message: &'ll Twine,
pub instruction: Option<&'ll Value>,
pub message: String,
pub source: Option<(String, Vec<InnerSpan>)>,
}

impl InlineAsmDiagnostic<'ll> {
unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
impl InlineAsmDiagnostic {
unsafe fn unpackInlineAsm(di: &'ll DiagnosticInfo) -> Self {
let mut cookie = 0;
let mut message = None;
let mut instruction = None;
let mut level = super::DiagnosticLevel::Error;

super::LLVMRustUnpackInlineAsmDiagnostic(
di,
&mut level,
&mut cookie,
&mut message,
&mut instruction,
);
super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);

InlineAsmDiagnostic { level, cookie, message: message.unwrap(), instruction }
InlineAsmDiagnostic {
level,
cookie,
message: super::twine_to_string(message.unwrap()),
source: None,
}
}

unsafe fn unpackSrcMgr(di: &'ll DiagnosticInfo) -> Self {
let mut cookie = 0;
let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
InlineAsmDiagnostic {
level: smdiag.level,
cookie,
message: smdiag.message,
source: smdiag.source,
}
}
}

pub enum Diagnostic<'ll> {
Optimization(OptimizationDiagnostic<'ll>),
InlineAsm(InlineAsmDiagnostic<'ll>),
InlineAsm(InlineAsmDiagnostic),
PGO(&'ll DiagnosticInfo),
Linker(&'ll DiagnosticInfo),
Unsupported(&'ll DiagnosticInfo),
Expand All @@ -130,7 +186,7 @@ impl Diagnostic<'ll> {
let kind = super::LLVMRustGetDiagInfoKind(di);

match kind {
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),

Dk::OptimizationRemark => {
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
Expand Down Expand Up @@ -162,6 +218,8 @@ impl Diagnostic<'ll> {
Dk::Linker => Linker(di),
Dk::Unsupported => Unsupported(di),

Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),

_ => UnknownDiagnostic(di),
}
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ pub enum DiagnosticKind {
PGOProfile,
Linker,
Unsupported,
SrcMgr,
}

/// LLVMRustDiagnosticLevel
Expand Down Expand Up @@ -2264,13 +2265,17 @@ extern "C" {
level_out: &mut DiagnosticLevel,
cookie_out: &mut c_uint,
message_out: &mut Option<&'a Twine>,
instruction_out: &mut Option<&'a Value>,
);

#[allow(improper_ctypes)]
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;

pub fn LLVMRustGetSMDiagnostic(
DI: &'a DiagnosticInfo,
cookie_out: &mut c_uint,
) -> &'a SMDiagnostic;

pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
H: InlineAsmDiagHandler,
Expand Down
Loading